Skip to content

Fix crash in HTTPResumableUploadChannel when parent channel is closed#304

Merged
Lukasa merged 4 commits intoapple:mainfrom
simonjbeaumont:sb/fix-crash
Jan 28, 2026
Merged

Fix crash in HTTPResumableUploadChannel when parent channel is closed#304
Lukasa merged 4 commits intoapple:mainfrom
simonjbeaumont:sb/fix-crash

Conversation

@simonjbeaumont
Copy link
Copy Markdown
Contributor

@simonjbeaumont simonjbeaumont commented Jan 23, 2026

Motivation:

Servers using HTTPResumableUploadHandler can currently crash during channel creation if the parent channel is closed.

During channel creation, the handler will inherit the autoRead option from the parent channel:

try! parent.syncOptions!.getOption(ChannelOptions.autoRead)

The force-unwrap of syncOptions is justified because this handler can only be used with channels that support sync options, but the force-try can trigger a crash with supported channels when the connection is interrupted.

NIO's BaseSocketChannel will throw an error if the channel is closed, and this presents a race window and we've observed crashes with the following output:

HTTPResumableUploadChannel.swift:81: Fatal error: 'try!' expression unexpectedly raised an error: I/O on closed channel

Modifications:

Replace the force-try with try? to prevent the crash. Given it looks like the only reason this would throw is if the connection is closed, the channel is not long for this world, and so the default value used is moot. However, I've defaulted this to false as it's the most conservative option.

I also wrote a test that uses new EmbeddedChannel API that was added to support this fix. The PR has been structured to add the test first, showing it failing, and then add the fix commit, which then shows the test passing.

Result:

The server will no longer crash when parent channels close during upload operations.

@simonjbeaumont simonjbeaumont added the 🔨 semver/patch No public API change. label Jan 23, 2026
@simonjbeaumont simonjbeaumont changed the title Fix crash in HTTPResumableUploadChannel when parent channel is closed [DO NOT MERGE] Fix crash in HTTPResumableUploadChannel when parent channel is closed Jan 26, 2026
@simonjbeaumont
Copy link
Copy Markdown
Contributor Author

This is the test reproducing the issue in CI:

Test Suite 'NIOResumableUploadTests' started at 2026-01-26 17:11:41.910
Test Case 'NIOResumableUploadTests.testChannelInitHandlesParentThrowingOnOptionsRead' started at 2026-01-26 17:11:41.910
NIOResumableUpload/HTTPResumableUploadChannel.swift:81: Fatal error: 'try!' expression unexpectedly raised an error: Already closed

— source: https://github.com/apple/swift-nio-extras/actions/runs/21366623846/job/61500061031?pr=304#step:4:2224

Now I'll push the fix commit.

@simonjbeaumont
Copy link
Copy Markdown
Contributor Author

OK, the test is now passing. This PR is just blocked on us getting a new NIO release with the testing support we need.

FranzBusch pushed a commit to FranzBusch/swift-nio that referenced this pull request Jan 27, 2026
…tion` if channel is closed (apple#3495)

### Motivation:

Channels based on `BaseSocketChannel` throw in both `getOption` and
`setOption` if the channel has been closed, since the `setsockopt` will
fail. However, the current behavior of `EmbeddedChannel` is options
remain writable and readable on closed channels.

There are situations where we'd like to be able to model the runtime
behaviour of the real channel in tests, e.g. to test this fix:
apple/swift-nio-extras#304.

### Modifications:

- Add API to enable throwing in `EmbeddedChannel.getOption` and
`.setOption` if channel is closed.
- Add a test for this new behavior.

### Result:

- New API to enable throwing in `EmbeddedChannel.getOption` and
`.setOption` if channel is closed.
- No observable change for existing users of `EmbeddedChannel`.
@simonjbeaumont
Copy link
Copy Markdown
Contributor Author

OK, now that we have a NIO release with the EmbeddedChannel support for the test, I've updated the NIO dependency and this PR is ready to review.

@simonjbeaumont simonjbeaumont marked this pull request as ready for review January 28, 2026 09:09
@simonjbeaumont simonjbeaumont changed the title [DO NOT MERGE] Fix crash in HTTPResumableUploadChannel when parent channel is closed Fix crash in HTTPResumableUploadChannel when parent channel is closed Jan 28, 2026
@Lukasa Lukasa merged commit 3df009d into apple:main Jan 28, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 semver/patch No public API change.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants