Skip to content

CAMEL-24120: camel-smb - Fix double download and stream download file handle leak#24788

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

CAMEL-24120: camel-smb - Fix double download and stream download file handle leak#24788
davsclaus merged 1 commit into
mainfrom
fix/CAMEL-24120

Conversation

@davsclaus

Copy link
Copy Markdown
Contributor

Summary

  • Fix double download: SmbFile.getBody() was bypassing the body already stored by retrieveFile and always re-downloading the file from the server. Now returns the binding body first, falling back to lazy fetch only when no body was stored (e.g., pollEnrich).
  • Fix file handle leak: For streamDownload=true, the smbj File handle was leaked because FileInputStream.close() does not close the underlying File. Introduced SmbFileClosingInputStream wrapper whose close() also closes the smbj File handle.
  • Fix dead-on-arrival stream: retrieveFileToStreamInBody was wrapping the smbj File in try-with-resources even for the stream download path, closing the handle before the stream was ever read. This was masked by the double download bug.

Test plan

  • Existing SMB integration tests pass (stream download, local work directory, no-download)
  • Verify with server-side instrumentation that files are downloaded only once
  • Verify streamDownload=true does not leak SMB file handles after stream is consumed

Claude Code on behalf of davsclaus

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

… handle leak

SmbFile.getBody() bypassed the body stored by retrieveFile and always
re-downloaded the file from the server. Fixed to return the binding body
first, falling back to lazy fetch only when no body was stored.

For streamDownload=true, the smbj File handle was leaked because
FileInputStream.close() does not close the underlying File. Introduced
SmbFileClosingInputStream wrapper whose close() also closes the smbj
File handle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
@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.

Well-designed fix for three interrelated bugs in the SMB stream download path. The issues have been present since streamDownload was added in CAMEL-21352, but bug #3 was masked by bug #1 (double download always re-opened a fresh handle).

Bug 1 — Double download (SmbFile.getBody()):
The override always called operations.getBodyAsInputStream() / operations.getBody(), re-downloading the file even though retrieveFileToStreamInBody already stored the body via the binding. Fix correctly checks super.getBody() first (which delegates to getBinding().getBody(this) on GenericFile), falling back to lazy fetch only for pollEnrich or paths that skip retrieveFile. ✅

Bug 2 — File handle leak (SmbFileClosingInputStream):
smbj's FileInputStream.close() does NOT close the underlying File handle — confirmed by the library's design. The new SmbFileClosingInputStream extends FilterInputStream and closes the smbj File in finally on close(). Error handling is correct: if getInputStream() throws during setup, the catch(Exception) block closes the File handle via IOHelper.close(shareFile). ✅

Bug 3 — Dead-on-arrival stream (retrieveFileToStreamInBody):
The old code wrapped the File handle in try-with-resources even for the stream download path, so the handle was closed before the stream was ever read. Fix correctly splits the stream/non-stream paths: non-stream keeps try-with-resources (reads all bytes); stream keeps the File open, wrapped in SmbFileClosingInputStream. ✅

Design observations:

  • The NOSONAR comment on getBodyAsInputStream() is correctly removed — the File handle is now properly managed via SmbFileClosingInputStream
  • Both retrieveFileToStreamInBody and getBodyAsInputStream consistently use the same wrapper pattern
  • SmbFileClosingInputStream is correctly package-private — internal implementation detail

Static analysis: ast-grep ran on all modified/new files — no findings.

Checklist:

  • ✅ Three bugs fixed with minimal, focused changes
  • ✅ Resource management is correct (handle closed on error, on stream close, and on non-stream path)
  • ✅ No new dependencies
  • ✅ Commit convention followed
  • ✅ CI pending (builds running)

Reviewed with Claude Code (claude-code/1.0) on behalf of gnodet. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-smb

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

Maveniverse Scalpel detected 38 affected modules (current approach: 9).

⚠️ 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 9 modules (1 direct + 8 downstream), skip tests for 29 (generated code, meta-modules)

Modules Scalpel would test (9)
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-launcher-container
  • camel-smb
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
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 (38 modules)
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • 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 :: 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 :: Kamelet Main
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: SMB
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin

⚙️ View full build and test results

@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
@davsclaus
davsclaus merged commit 2c904e4 into main Jul 16, 2026
3 of 5 checks passed
@davsclaus
davsclaus deleted the fix/CAMEL-24120 branch July 16, 2026 13:40
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