Skip to content

CAMEL-24088: camel-ftp - streamDownload treats refused RETR as success#24807

Merged
davsclaus merged 1 commit into
mainfrom
fix/CAMEL-24088
Jul 16, 2026
Merged

CAMEL-24088: camel-ftp - streamDownload treats refused RETR as success#24807
davsclaus merged 1 commit into
mainfrom
fix/CAMEL-24088

Conversation

@davsclaus

Copy link
Copy Markdown
Contributor

Summary

Claude Code on behalf of davsclaus

Fixes two related bugs in FtpOperations where the streamDownload=true path never checks the FTP client's success indicators, causing silent data loss:

  • retrieveFileToStreamInBody: FTPClient.retrieveFileStream() returns null when the server refuses RETR (550/450/425), but the code unconditionally set result = true. The consumer then routes the exchange with a null body and the process strategy commits — moving or deleting the remote file that was never downloaded. Fixed by setting result = is != null and only populating the body/header when the stream is available.

  • releaseRetrievedFileResources: FTPClient.completePendingCommand() returns false when the transfer did not complete (server sent 426/451), but the return value was discarded. A truncated stream would be silently accepted and the commit would still run. Fixed by checking the return value and throwing GenericFileOperationFailedException on failure.

These fixes also re-enable ignoreFileNotFoundOrPermissionError for streamDownload mode — it was previously dead code because retrieved was always true.

Test plan

  • New unit test FtpOperationsStreamDownloadTest with 5 test cases:
    • testRetrieveFileStreamReturnsNullOnServerError — verifies retrieveFile returns false when server refuses RETR
    • testRetrieveFileStreamSuccessReturnsTrue — verifies normal success path still works
    • testReleaseResourcesThrowsOnFailedCompletion — verifies exception on failed completePendingCommand
    • testReleaseResourcesSucceedsOnCompletedTransfer — verifies normal release path
    • testReleaseResourcesSkipsWhenNoStream — verifies no-op when no stream header present

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
@davsclaus davsclaus requested review from gnodet and oscerd July 16, 2026 15:24
@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — important fix for silent data loss in FTP streamDownload mode.

retrieveFileToStreamInBody: FTPClient.retrieveFileStream() returns null on server refusal
(550/450/425), but the old code unconditionally set result = true (line 487 on main). This
caused the consumer to route an exchange with a null body, and the process strategy would then
commit — moving or deleting the remote file that was never actually downloaded. The fix
(result = is != null + guarded body/header) is clean and correct.

releaseRetrievedFileResources: The discarded completePendingCommand() return value meant a
truncated transfer (426/451) was silently accepted. The new check-and-throw is correct —
GenericFileOperationFailedException extends RuntimeCamelException (a RuntimeException),
so it won't be caught by the existing IOException catch clause in the same try block.

Side benefit: ignoreFileNotFoundOrPermissionError was effectively dead code for streamDownload
mode since retrieved was always true — this fix re-enables it.

Tests cover all five paths well (null stream, success stream, failed completion, success completion,
no-stream release).

Claude Code on behalf of gnodet

@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-ftp

🔬 Scalpel shadow comparison — Scalpel: 12 tested, 29 compile-only — current: 12 all tested

Maveniverse Scalpel detected 41 affected modules (current approach: 12).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 12 modules (1 direct + 11 downstream), skip tests for 29 (generated code, meta-modules)

Modules Scalpel would test (12)
  • camel-azure-files
  • camel-ftp
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-jsch
  • camel-launcher-container
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • camel-zookeeper-master
Modules with tests skipped (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (41 modules)
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: Azure :: Files
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Component DSL
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: FTP
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: Jsch
  • Camel :: Kamelet Main
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin
  • Camel :: Zookeeper Master

⚙️ View full build and test results

@davsclaus davsclaus merged commit b47a8de into main Jul 16, 2026
5 checks passed
@davsclaus davsclaus deleted the fix/CAMEL-24088 branch July 16, 2026 19:51
@davsclaus davsclaus added this to the 4.22.0 milestone Jul 16, 2026
@davsclaus davsclaus self-assigned this Jul 16, 2026
@davsclaus davsclaus added the bug Something isn't working label Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants