Skip to content

Safe-cast URLResponse in ProxyHTTPHandler#203

Merged
swhitty merged 2 commits into
swhitty:mainfrom
ianegordon:ian/tvt-284-proxy-safe-cast
Apr 23, 2026
Merged

Safe-cast URLResponse in ProxyHTTPHandler#203
swhitty merged 2 commits into
swhitty:mainfrom
ianegordon:ian/tvt-284-proxy-safe-cast

Conversation

@ianegordon

Copy link
Copy Markdown
Contributor

Summary

ProxyHTTPHandler.handleRequest force-unwrapped the URLResponse returned by URLSession.data(for:) as an HTTPURLResponse. If the session is configured with a custom URLProtocol, a file:// URL, or hits certain error paths, the response isn't guaranteed to be an HTTPURLResponse — the force cast traps and crashes the server actor.

Change

FlyingFox/Sources/Handlers/ProxyHTTPHandler.swift:

 public func handleRequest(_ request: HTTPRequest) async throws -> HTTPResponse {
     let req = try await makeURLRequest(for: request)
     let (data, response) = try await session.data(for: req)
-    return makeResponse(for: response as! HTTPURLResponse, data: data)
+    guard let httpResponse = response as? HTTPURLResponse else {
+        throw URLError(.badServerResponse)
+    }
+    return makeResponse(for: httpResponse, data: data)
 }

Test

New test in FlyingFox/Tests/Handlers/HTTPHandlerTests.swift uses a URLProtocol subclass that returns a plain (non-HTTP) URLResponse and asserts the handler throws URLError rather than crashing.

Test plan

  • swift build clean.
  • New test proxyHandler_ThrowsError_WhenResponseIsNotHTTPURLResponse passes.
  • swift test — 405 tests across 49 suites pass (up from 404).

🤖 Generated with Claude Code

URLSession.data(for:) returning a non-HTTPURLResponse (custom
URL protocols, file://, some error paths) previously trapped on
force-unwrap, tearing down the server actor. Replace the force
cast with a guard that throws URLError(.badServerResponse).

Also adds a test using a URLProtocol that returns a plain
URLResponse to lock in the behavior.

Closes TVT-284

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@codecov

codecov Bot commented Apr 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.21%. Comparing base (d97e0e2) to head (1fc3a3e).
⚠️ Report is 7 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #203      +/-   ##
==========================================
+ Coverage   92.40%   93.21%   +0.80%     
==========================================
  Files          69       69              
  Lines        3543     4806    +1263     
==========================================
+ Hits         3274     4480    +1206     
- Misses        269      326      +57     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Exercises the makeResponse(...) branch of handleRequest using a
URLProtocol fake that returns a valid HTTPURLResponse. Together
with the existing non-HTTP-response test, both sides of the
guard added for TVT-284 are now covered.

Also normalizes the existing test function name to match the
project convention (no underscore between "Error" and "When").

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@swhitty swhitty left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

nice!

@swhitty swhitty merged commit b07d008 into swhitty:main Apr 23, 2026
13 checks passed
@ianegordon ianegordon deleted the ian/tvt-284-proxy-safe-cast branch April 24, 2026 04:28
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.

2 participants