Skip to content

feat(client): add HttpConnect connector that keeps early tunnel data - #320

Open
heitzlki wants to merge 1 commit into
hyperium:masterfrom
heitzlki:http-connect-proxy
Open

heitzlki wants to merge 1 commit into
hyperium:masterfrom
heitzlki:http-connect-proxy

Conversation

@heitzlki

@heitzlki heitzlki commented Sep 11, 2026

Copy link
Copy Markdown

Follow-up to hyperium/hyper#4095: #315 fixed the parsing, but tunnel() still throws away anything after the header end, which breaks protocols where the server speaks first. Fixing it in place changes Tunnel's response type, which is why #313 went nowhere.

So this is the alternative @seanmonstar suggested on the issue: a new connector, HttpConnect, that sends an actual CONNECT request over an h1 connection and returns the upgraded IO, early bytes survive through hyper's own upgrade buffer. The conn future is driven inside the connector future, so nothing needs to be spawned. The returned IO forwards Connected so it works with the legacy client. Tunnel itself is untouched except a pub(super) on the shared Headers enum.

HTTP/1 only for now, h2 CONNECT could go behind the same type later.

Closes hyperium/hyper#4095

Tunnel drops whatever the destination sends right after the proxy's
200, and fixing that in place would change its response type (hyperium#313).
HttpConnect does a real CONNECT request over an h1 connection and
returns the upgraded IO, so leftover bytes survive via hyper's
upgrade buffer. HTTP/1 only for now.

Closes hyperium/hyper#4095
where
C: Service<Uri>,
C::Future: Send + 'static,
C::Response: Read + Write + Connection + Unpin + Send + 'static,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

So, here's an idea. (It might have been in my head and I never expressed it.) This HttpConnect type could be generic over an HTTP service, instead of a "connector", and then it could work with HTTP/1 or 2 (or 3?).

That'd mean impl Service<http::Request<SomeEmptyBody>, Response = http::Response<B>>, and then we would build a CONNECT request kind of like in the handshake function, using hyper::upgrade. Of course, the user would have to provide an HTTP connection that supports upgrades (so if it's HTTP/2, they'd need to have enabled extended connect). But, that seems fine.

Is this too crazy?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Not too crazy, h2 CONNECT multiplexing tunnels over one proxy connection is exactly what the gRPC folks want anyway. Two questions before I rework it:

1 Should the service-generic type be the whole API, or the core with the current connector version kept as a thin wrapper? With a bare service the caller has to drive the conn themselves, which is the one thing the connector version handles for you.

2 Behind a service I can't see the transport, so Tunneled loses the underlying Connected. Fine to just return Connected::new()?

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.

HTTP CONNECT proxy tunnel has lax response parsing and loses early data

2 participants