Skip to content

vey-proxy: support h2 to upstream h1 - #109

Merged
zh-jq merged 17 commits into
mainfrom
h2-to-h1
Sep 21, 2026
Merged

zh-jq merged 17 commits into
mainfrom
h2-to-h1

Conversation

@zh-jq

@zh-jq zh-jq commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

No description provided.

zh-jq and others added 3 commits September 20, 2026 00:55
HTTP/2 clients talking to HTTP/1 origins need ICAP adaptation on already-converted headers, so bypass and ICAP share the same types and H2 request bodies stay chunked so trailers survive.

Co-authored-by: Cursor <cursoragent@cursor.com>
Handshake-only TLS keeps escaper IO on TCP and returns the leaf that
connected, so H2/H1 wrap can use that instance instead of looking it
up by name after reload.

Co-authored-by: Cursor <cursoragent@cursor.com>
H2 clients offer both protocols, prefer the H2 pool, then H1. TLS wrap
uses the leaf from tls_connect so the converted request can finish and
return to the site H1 pool.

Co-authored-by: Cursor <cursoragent@cursor.com>
@zh-jq
zh-jq force-pushed the h2-to-h1 branch 2 times, most recently from 5644495 to 3708a62 Compare September 20, 2026 00:27
Co-authored-by: Cursor <cursoragent@cursor.com>
zh-jq and others added 12 commits September 20, 2026 23:07
…eout

Bidirectional idle errors were inverted relative to no_cached_data, and the
H1-to-H2 204 original-body path waited on trailers without a bound. Use the
response-header timeout instead of task idle, which is far too long.

Co-authored-by: Cursor <cursoragent@cursor.com>
check_options was stealing idle connections via get(), and yaml pool
maps reset ICAP min_idle to the generic default of 32. Overlay the
map onto the existing config, keep min_idle 0, and OPTIONS only on
expiry so reused sessions stay available.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Connection-based auth cannot multiplex on H2, and gRPC must not fall back
through ALPN to HTTP/1, so origin H2 uses tls_setup_connection directly.

Co-authored-by: Cursor <cursoragent@cursor.com>
REQMOD H2-to-H1 keeps From and adds To HTTP/1.1. RESPMOD H1-to-H2 only
advertises To HTTP/2.0 because the encapsulated response is already H1.

Co-authored-by: Cursor <cursoragent@cursor.com>
Check expire and block once from TenantContext so stats stay with the
user. Expire replies like an unknown host; block still returns 403.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy peer/bind Instant onto EgressNotes at connect so idle pools and
adaptation send can drop expired connections without Timestamp::now().

Co-authored-by: Cursor <cursoragent@cursor.com>
Take RecvStream by mut ref in H2-to-H1 REQMOD so a reused H1 origin can
be replaced after idle close, and return 400 for expired tenant like H1.

Co-authored-by: Cursor <cursoragent@cursor.com>
Finish client-to-ICAP first, then drain ICAP-to-peer, so idle timeouts
name the remaining direction and body sizes are recorded once.

Co-authored-by: Cursor <cursoragent@cursor.com>
Consume Encapsulated opt-body so OPTIONS parse does not leave unread
bytes, and keep client/upstream body sizes when origin headers arrive
before the transfer finishes.

Co-authored-by: Cursor <cursoragent@cursor.com>
Split header and body in stream run so dispatch only mutates headers.
H2ForwardTask owns Request<()> for origin send and RESPMOD; H1 origin
still converts locally. RequestExt::host() feeds forwarded headers.

Co-authored-by: Cursor <cursoragent@cursor.com>
Track Connecting/Connected/Relaying/Finished like H1 forward, and align
websocket stages with HTTP CONNECT so ready_time is recorded at Relaying.

Co-authored-by: Cursor <cursoragent@cursor.com>
@zh-jq
zh-jq merged commit 88987ec into main Sep 21, 2026
132 of 134 checks passed
@zh-jq
zh-jq deleted the h2-to-h1 branch September 21, 2026 16:16
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.

1 participant