Skip to content

http: don't keep alive close-delimited proxy responses#101

Open
Alexander4731 wants to merge 7 commits into
SagerNet:devfrom
alex-net-proxy:fix-http-proxy-close-delimited-response
Open

http: don't keep alive close-delimited proxy responses#101
Alexander4731 wants to merge 7 commits into
SagerNet:devfrom
alex-net-proxy:fix-http-proxy-close-delimited-response

Conversation

@Alexander4731
Copy link
Copy Markdown

Summary

Fix HTTP proxy handling for close-delimited upstream responses.

The HTTP proxy inbound currently decides whether to keep the client connection alive from the client request's Proxy-Connection: keep-alive, then overwrites the proxied response's close semantics.

This breaks some legacy HTTP servers, especially HTTP/1.0 devices that return responses like:

HTTP/1.0 401 Unauthorized
WWW-Authenticate: Basic realm="K2P"
Content-Type: text/html
Connection: close

These responses often do not include Content-Length or Transfer-Encoding; the response body is delimited by closing the connection. If the proxy rewrites the downstream response as keep-alive, clients may receive a truncated response or a reset connection before seeing headers such as WWW-Authenticate.

Fix

Only keep the downstream HTTP proxy connection alive when:

  • the client requested HTTP proxy keep-alive,
  • the upstream response itself is reusable,
  • the upstream response is not close-delimited.

This preserves the existing keep-alive behavior for length-delimited reusable responses, while keeping legacy close-delimited responses safe.

Reproduction

Using an HTTP proxy inbound or mixed inbound:

curl -v -x http://127.0.0.1:3067 http://legacy-router.example:8081/

Before this change, a legacy HTTP/1.0 Basic Auth server can produce:

< HTTP/1.0 401 Unauthorized
* Recv failure: Connection was reset

The same target via SOCKS5 succeeds because SOCKS5 forwards the TCP stream without rewriting the HTTP response:

curl -v -x socks5h://127.0.0.1:3067 http://legacy-router.example:8081/

Expected response:

< HTTP/1.0 401 Unauthorized
< WWW-Authenticate: Basic realm="K2P"
< Content-Type: text/html
< Connection: close

Tests

Added tests for:

  • rejecting keep-alive for close-delimited HTTP/1.0 responses,
  • preserving keep-alive for length-delimited responses,
  • ignoring no-body responses such as 1xx, 204, and 304.

@nekohasekai nekohasekai force-pushed the dev branch 2 times, most recently from 33b66f8 to 7297f95 Compare May 14, 2026 08:36
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