🐛 Expose supportedProtocols on ConnectionManager to fix fallback for RFC-strict servers - #2583
🐛 Expose supportedProtocols on ConnectionManager to fix fallback for RFC-strict servers#2583chrisslazzz wants to merge 3 commits into
Conversation
| }); | ||
|
|
||
| test( | ||
| 'routes to fallbackAdapter when server selects http/1.1 via ALPN', |
There was a problem hiding this comment.
This test exercises the existing fallback path against a lenient server
(www.baidu.com), which completes the TLS handshake regardless of the ALPN
list and therefore doesn't reproduce the root cause described in the PR — a
strict RFC 7301 server aborting the handshake before Dio code runs.
Testing the actual fix would require a server that sends a fatal
no_application_protocol alert when only ['h2'] is offered, but completes
the handshake when ['h2', 'http/1.1'] is offered. Two options:
- Local TLS server — spin up a
SecureServerSocketwith
supportedProtocols: ['http/1.1']in test setup. Needs embedded
self-signed certificates, which the repo doesn't currently have. - Remote host — use a public server that strictly enforces ALPN this
way. Happy to do this if the maintainers know of a reliable one, though
leaning on an external host for a correctness test adds fragility to CI.
Happy to implement either if that's the direction the maintainers want to go.
|
Hi @chrisslazzz . Your commit email doesn't seem to be associated with your GitHub account. Please correct this so we can at least verify the user. |
39a6725 to
6c1a890
Compare
sorry about that. Should be ok now |
1/2 maybe; the GPG key is still missing. 🤔 |
6c1a890 to
0639ca4
Compare
uff, now maybe 1/1? 👀 |
PR review — fix is correct, but the test doesn't defend the bugI independently reproduced the issue (#2584) and confirmed the root cause. The fix approach here — exposing However, the added test has a significant gap that the PR author already flagged in their own review comment: The test does not exercise the bugThe test
I confirmed this by testing three TLS server implementations locally:
Only Go's What would make the test effectiveA test that actually defends this fix needs a server that:
This requires a local TLS server with strict ALPN enforcement. Two options the PR author already mentioned:
Without a test that actually fails on the old code and passes on the new code, a future regression that re-hardcodes Minor: the fix is opt-inThe default stays
|
…RFC-strict servers Hardcoded supportedProtocols: ['h2'] in _ConnectionManager._createSocket prevented fallbackAdapter from ever firing against RFC 7301-compliant HTTP/1.1-only servers: such servers abort the TLS handshake with a fatal no_application_protocol alert before any Dio code runs, so DioH2NotSupportedException is never raised and the fallback is bypassed. Expose supportedProtocols on ConnectionManager (default ['h2'], fully backwards-compatible). Setting it to ['h2', 'http/1.1'] lets the TLS handshake succeed against any server; if the server selects http/1.1, _throwIfH2NotSelected raises DioH2NotSupportedException, which Http2Adapter already catches and routes to fallbackAdapter. Co-Authored-By: Claude <noreply@anthropic.com>
0639ca4 to
6b26003
Compare
|
@CaiJingLong I've reworked the tests to use openssl s_server as the strict-ALPN enforcement server instead of a Go binary. What do you think? Is openssl available in CI? The setup sends no_application_protocol when the client advertises only h2 and completes the handshake with http/1.1 selected when both are offered. The tests call |
Re-review — the reworked tests now genuinely reproduce the bug ✅Thanks for the rework, @chrisslazzz. The (a) Local verification
To your question: is openssl available in CI?Yes. (b) Fact-checking pass — every external claim checks outA read-only fact-checking review verified each claimable assertion against primary sources. Highlights:
(c) Adversarial pass — no blockers, all findings are test-harness hardeningThe core fix is correct and security-neutral; every issue found is in the
One process noteThis PR now bundles two concerns (the opt-in VerdictApprove-able once items 1–2 above are addressed (deterministic openssl readiness + guaranteed teardown) — those are the CI-flake risks. The rest are nits. The fix logic itself is sound, minimal, backwards-compatible, and now properly tested.
|
Add `false_secrets` to pubspec.yaml and a subdirectory `.pubignore` under `test/certificates/` so the self-signed test key/cert pair introduced for the strict-ALPN regression tests never enters the published artifact, and `dart pub publish` no longer flags it. Co-Authored-By: GLM-5.2 <noreply@zhipu.ai>
Added: exclude the test fixture private key from the published packageI pushed a follow-up commit (
Why both?
Why
|
Code Coverage Report: Only Changed Files listed
Minimum allowed coverage is |
- Register process teardown immediately after Process.start so the child is killed even if the test is cancelled mid-setup - Replace fixed 300 ms readiness delay with a TCP port-poll loop; detect early openssl exit (e.g. wrong CWD, missing certs) and skip rather than hang - Guard stdout listener against re-entry on fragmented requests - Simplify _bindHttp11OnlyServer return type to int (port only) - Complete dartdoc sentence for supportedProtocols; note that 'h2' must be present for HTTP/2 to be negotiated Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@AlexV525 Thanks for the detailed review — addressed items 1–6 in 63c9571. Items 1 & 2 (readiness + teardown): Replaced the fixed 300 ms delay with a TCP port-poll loop (40 × 50 ms). On the TOCTOU race: I kept the port-probe approach ( Items 3 & 5 (re-entry guard + early exit): Added Items 4 & 6 (dartdoc): Completed the cut-off sentence; added a note that Also extracted |
|
@chrisslazzz Tests start failing after the recent change. |
|
@AlexV525 Haven't figured out how the failures are connected to my changes & how to run some of these tests locally. Hopefully, I'll find some more time by the end of the week.. But could this also have been a temporary issue with badssl.com? |
fallbackAdaptersilently never fires against HTTP/1.1-only servers that enforce ALPN strictly. WithsupportedProtocols: ['h2']hardcoded, a compliant server has no matching protocol and — per RFC 7301 §3.2 — responds with a fatalno_application_protocolalert, aborting the TLS handshake. The resultingHandshakeExceptionis never caught byHttp2Adapter._fetch, so it propagates to the caller instead of reaching the fallback.This PR exposes
supportedProtocolsonConnectionManager(default['h2'], no behaviour change). Setting it to['h2', 'http/1.1']allows the handshake to complete against any server: if the server selectshttp/1.1,_throwIfH2NotSelectedraisesDioH2NotSupportedException, whichHttp2Adapteralready catches and routes tofallbackAdapter.Implementation, tests, and CHANGELOG by Claude (Sonnet 4.6) via GitHub Copilot.
Fixes #2584