You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix an HTTP/1.1 tunnel hang for unknown-length upstream responses.
When CrabTrap MITMs an HTTPS CONNECT tunnel, some upstream responses arrive
without Content-Length and without Transfer-Encoding. In that case, EOF is
the only valid response-body delimiter. CrabTrap was writing the response body
to the client but keeping the tunnel open, causing clients like curl to wait
indefinitely after receiving the full body.
This changes tunnel keep-alive behavior so unframed, unknown-length responses
close the tunnel after the response is written.
Fixes HTTP/1.1 CONNECT tunnel hangs when upstream responses have no Content-Length and no Transfer-Encoding. Per RFC 7230 §3.3.3, EOF is the only valid body delimiter for such responses, so the tunnel must close after writing the response. The fix adds two checks to shouldKeepAlive: respect resp.Close from Go's HTTP transport, and detect unframed responses (body present, unknown length, no transfer encoding) to close the tunnel.
Adds resp.Close check to shouldKeepAlive in handler.go — aligns with Go's net/http signal that the server wants the connection closed
Adds unframed response detection (ContentLength < 0 && len(TransferEncoding) == 0) to prevent keep-alive on EOF-delimited responses
New test TestUnknownLengthUnframedResponseDoesNotKeepTunnelAlive validates the fix
Confidence Score: 5/5
This PR is safe to merge — it's a targeted, correct fix for a well-understood HTTP/1.1 protocol issue.
The change is minimal (9 lines of logic + test), correctly implements RFC 7230 §3.3.3 semantics, only affects the specific edge case of unframed responses, and includes a focused test. The conditions are well-guarded — normal keep-alive for framed responses (Content-Length or Transfer-Encoding present) is unaffected.
No files require special attention.
Important Files Changed
Filename
Overview
internal/proxy/handler.go
Adds two early-return checks to shouldKeepAlive: resp.Close and unframed response detection. Both are correct per HTTP/1.1 semantics and well-scoped.
internal/proxy/streaming_test.go
Adds a focused test validating that shouldKeepAlive returns false for unframed responses.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix Unframed Tunnel Response Hangs
Summary
Fix an HTTP/1.1 tunnel hang for unknown-length upstream responses.
When CrabTrap MITMs an HTTPS
CONNECTtunnel, some upstream responses arrivewithout
Content-Lengthand withoutTransfer-Encoding. In that case, EOF isthe only valid response-body delimiter. CrabTrap was writing the response body
to the client but keeping the tunnel open, causing clients like
curlto waitindefinitely after receiving the full body.
This changes tunnel keep-alive behavior so unframed, unknown-length responses
close the tunnel after the response is written.
Reproduction
This hung behind CrabTrap before the fix:
curl -fsSL \ --proxy 'http://gat_local_ct100_dev:@192.168.32.100:8080' \ --cacert /opt/egress-gateway/crabtrap/certs/ca.crt \ https://api.github.com/repos/openai/codex/releases/latest \ -o /tmp/codex-release.jsonVerbose output showed the response body was fully received, but curl waited for
EOF:
Concrete URL:
This was observed while running the Codex installer from:
Fix
If a tunnel response has:
ContentLength < 0TransferEncodingthen CrabTrap no longer keeps the HTTP/1.1 tunnel alive. Closing the tunnel
gives the client the EOF delimiter it is waiting for.
Test
Added a focused test covering unknown-length, unframed tunnel responses:
Also manually verified the Codex release metadata and release tarball download
complete through CrabTrap after the fix.