Repository navigation
http(h2): send the request again over HTTP/1.1 after HTTP_1_1_REQUIRED #46259
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
robobun
wants to merge
3
commits into
main
Choose a base branch
from
robobun/e999e598/fetch-http1-fallback-on-reset
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 (optional) Users running with the h2 flag can lose HTTP/2 for an origin after a single HTTP_1_1_REQUIRED fallback, for as long as traffic keeps the fallback socket alive. The resent request parks its HTTP/1.1 socket in the keep-alive pool on completion.
find_in(HTTPContext.rs:869-875) then hands that socket to any later request that offersH1OrH2, and each use re-parks it. Fix: keep a socket opened byretry_over_http1out of the pool, or make the pool prefer an idle h2 session over an h1 socket forH1OrH2requests, so only requests pinned to h1 take it. The PR asks whether this is acceptable; with the 5-minute idle default (HTTPContext.rs:781) and steady traffic the socket never expires.Why this was flagged
A server answers one request with RST_STREAM(HTTP_1_1_REQUIRED) while the h2 flag is on. ClientSession.rs:1218-1219 calls
retry_over_http1, lib.rs:2199-2204, which pins the request and restarts it over a new HTTP/1.1 TLS connection; on completion that socket is released to the keep-alive pool like any h1 socket. A later request withoutprotocolcallsalpn_offer()->H1OrH2;connect(HTTPContext.rs:1124) asksexisting_socket, andfind_inreturns the first slot that passes HTTPContext.rs:869-875, where an h1 socket is accepted forH1OrH2. Each such use re-parks the socket and re-arms the 5-minute timer (HTTPContext.rs:779-783), so under continuous traffic the origin stays on HTTP/1.1 for one request at a time, with no multiplexing, until the socket is idle for 5 minutes. On the base branch only an explicitprotocol: "http1.1"could put an h1 socket in the pool while the flag is on, so this did not occur for ordinary requests. The PR description flags this and asks if it is acceptable; no code bounds it.Verification: The PR description's "Downsides" names it and the new test "an HTTP/1.1 connection that became idle before the h2 connection carries the next request" (test/js/web/fetch/fetch-http2-client.test.ts:2980-3009) pins it:
/nextis answered "200 over h1" although an idle h2 session is in the pool.find_in(HTTPContext.rs:867-875) accepts the h1 socket for anyH1OrH2caller.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left this as it is. The question is in the Downsides of the description, for a maintainer to decide.
connectinHTTPContext.rschecksactive_h2_sessionsbefore the pool, so concurrent requests still join an active h2 connection.HTTP_1_1_REQUIREDpays one refused h2 attempt for each request. If the connection of the resend stays out of the pool, each refused request pays a new TLS handshake.HTTP_1_1_REQUIREDit uses HTTP/1.1 for the origin (SetHTTP11Required). That needs a table per origin, which is a separate change.If a maintainer wants the pool to keep a connection that never offered h2 away from a request that offers it, that is one flag on the pooled socket and one check in
find_in. I can add it here.