Skip to content

Close the caller's stream when writeInputStreamToFile can't open the target - #114

Merged
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:leak-writeinputstream-target
Sep 7, 2026
Merged

Close the caller's stream when writeInputStreamToFile can't open the target#114
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:leak-writeinputstream-target

Conversation

@pjfanning

Copy link
Copy Markdown
Member

SchemaResourceManager.writeInputStreamToFile leans on IOUtil.copyCompletely to close both streams:

OutputStream output = Files.newOutputStream(targetFile.toPath());
IOUtil.copyCompletely(input, output);

But copyCompletely only runs once the target has been opened. If Files.newOutputStream throws — an unwritable directory, a path component that is not a directory, a full disk — the caller's input is never closed.

The callers in BaseSchemaResourceManager hand it live downloads: url.openStream() (copyOrIdentifyDuplicateURL), conn.getInputStream() (redownloadEntry) and the index document stream (writeCache). A write failure there leaks the socket, and redownloadEntry/copyOrIdentifyDuplicateURL both just warning(...) and carry on to the next resource, so this accumulates across a -refresh run.

The method now owns the input in a try-with-resources, so it is released either way; the second close on the normal path is a no-op.

Added SchemaResourceManagerWriteTest, which puts a plain file where the target's parent directory should be. It fails on trunk and passes with this change.

🤖 Generated with Claude Code

…target

SchemaResourceManager.writeInputStreamToFile relies on IOUtil.copyCompletely
to close both streams, but copyCompletely only runs once the target has been
opened. If Files.newOutputStream throws - an unwritable directory, a path
component that is not a directory, a full disk - the caller's input is never
closed.

Callers in BaseSchemaResourceManager pass live downloads: url.openStream(),
conn.getInputStream() and the index document stream. A write failure there
leaks the socket.

Own the input in a try-with-resources so it is released either way. The second
close on the normal path is a no-op.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pjfanning
pjfanning merged commit fd2b423 into apache:trunk Sep 7, 2026
3 checks passed
@pjfanning
pjfanning deleted the leak-writeinputstream-target branch September 7, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant