-
Notifications
You must be signed in to change notification settings - Fork 30
Design portable fetch transport API #693
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
Draft
martin-kolinek
wants to merge
11
commits into
main
Choose a base branch
from
u/makolnek/fetch-builder-redesign
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.
Draft
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
418b21f
docs(fetch): define portable transport API
martin-kolinek d1b4496
docs(fetch): clarify transport extension model
martin-kolinek ecf5bf0
docs(fetch): split Hyper TLS composition
martin-kolinek 1ffbe8b
docs(fetch): name shared Hyper engine
martin-kolinek c6fccfc
docs(fetch): define protocol and duplex behavior
martin-kolinek 1697a72
docs(fetch): align design with current transports
martin-kolinek 2a23226
docs(fetch): clarify target contract status
martin-kolinek ae41066
docs(fetch): erase transports internally
martin-kolinek e4146a9
docs(fetch): clarify TLS builder names
martin-kolinek 7c3fa72
docs(fetch): keep Transport dyn-compatible
martin-kolinek ba0bd5e
docs(fetch): borrow transport during validation
martin-kolinek 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| # Transport capability matrix | ||
|
|
||
| Status: target capability contract. “Supported” describes available backend/native capability; | ||
| the merged implementations may still need wiring identified by this design. | ||
|
|
||
| This document compares the supported Hyper TLS combinations with the planned WinHTTP transport. It | ||
| separates differences that matter to libraries from backend mechanisms that should not expand the | ||
| portable `fetch` API. | ||
|
|
||
| The WinHTTP column describes the target contract grounded in available native mechanisms, the | ||
| merged implementation, and the executable capability probes linked from this design. | ||
|
|
||
| The two Hyper columns share one TLS-neutral `fetch_hyper_common` engine. `fetch_hyper_rustls` and | ||
| `fetch_hyper_native_tls` provide connector composition, not separate HTTP implementations. | ||
|
|
||
| ## TLS and client authentication | ||
|
|
||
| | Capability | Hyper + rustls | Hyper + native TLS | WinHTTP + SChannel | Public treatment | | ||
| | --- | --- | --- | --- | --- | | ||
| | Platform trust | Platform verifier | Native platform trust | Native Windows trust | Baseline/invariant | | ||
| | Named client credential | Catalog can bind key material or a signing resolver | Catalog binds a materialized native identity | Catalog can bind a store selector or imported material | Baseline | | ||
| | Exportable certificate and private key binding | Supports common key encodings | Requires PKCS#8 through the current adapter | Planned import into a temporary certificate store | Transport construction | | ||
| | Non-exportable Windows-store binding | Supported through a rustls signing resolver | No equivalent current API | Supported through `CERT_CONTEXT` | Transport construction | | ||
| | Arbitrary external signing service | Supported through rustls signing traits | Unsupported | Unsupported unless it provides a compatible Windows key handle | `fetch_hyper_rustls` composition only | | ||
| | Custom verifier callback | Supported | Unsupported | No userspace callback | `fetch_hyper_rustls` composition only | | ||
| | Exact TLS server-name override while preserving request authority | Connector dials the request endpoint and supplies the override to rustls | Connector dials the request endpoint and supplies the override to native TLS | `WinHttpConnect` uses the TLS name, resolution override uses the endpoint, and replaced `Host` preserves authority | Baseline | | ||
| | Custom SAN/subject server-identity policy | Enforced before application data by a verifier | Unsupported | Cannot be safely enforced before request disclosure | Explicit portable non-goal; `fetch_hyper_rustls` only | | ||
| | Certificate or public-key pins | Implementable in a verifier | Unsupported | Cannot be safely enforced before request disclosure | Explicit portable non-goal; supporting composition crate only | | ||
| | Per-client custom trust roots | Expressible through custom rustls configuration | Not exposed by the current adapter | Uses Windows trust stores | Explicit portable non-goal; supporting composition crate only | | ||
| | TLS backend and crypto-provider selection | `fetch_hyper_rustls` | `fetch_hyper_native_tls` | SChannel is fixed | Application selects a composition dependency | | ||
| | Revocation | Required by the platform-verifier policy | Platform behavior | Must be enabled explicitly | Invariant, not a capability | | ||
|
|
||
| Libraries select a stable logical client-credential identifier. Applications bind that identifier | ||
| to key material, a Windows-store selector, or another transport-native provider. This makes source | ||
| modality a transport-construction concern rather than a library-facing capability axis. | ||
|
|
||
| ## HTTP protocols | ||
|
|
||
| | Capability | Hyper + either TLS backend | WinHTTP | Public treatment | | ||
| | --- | --- | --- | --- | | ||
| | Portable HTTP/1.1 and HTTP/2 constraints | Supported | Supported | Baseline | | ||
| | Strictly require HTTP/2 | Supported by Hyper's HTTP/2-only mode | Supported by enabling HTTP/2 and setting `WINHTTP_OPTION_HTTP_PROTOCOL_REQUIRED` | Baseline; gRPC is a demonstrated consumer | | ||
| | Initial HTTP/2 stream receive window | Fixed or adaptive policy | OS default; a fixed window option exists | Transport-owned default, not public configuration | | ||
| | Prefer HTTP/3 | Unsupported | Supported on recent Windows with fallback | WinHTTP composition preference; portable requirements take precedence | | ||
| | Require HTTP/3 | Unsupported | Mechanically supported | Not exposed until HTTP/3 joins the portable baseline | | ||
| | Fine-grained HTTP/2 flow control | Supported | Different partial native controls | Internal transport policy | | ||
|
|
||
| Portable protocol configuration constrains HTTP/1.1 and HTTP/2 rather than ordering every protocol | ||
| a transport may implement. A gRPC library can require exact HTTP/2. WinHTTP enforces that with its | ||
| HTTP/2 enable flag and `WINHTTP_OPTION_HTTP_PROTOCOL_REQUIRED`; no user-space emulation is needed. | ||
| The option requires Windows 10 version 1903 or later, older than the WinHTTP transport's supported | ||
| platform baseline. | ||
|
|
||
| The receive window is not a protocol requirement. Its optimum depends on path bandwidth and RTT, | ||
| active stream count, response consumption, memory budget, and adaptive-window behavior. A numeric | ||
| cross-transport option would expose only part of that policy. Transports select and benchmark their | ||
| own defaults. | ||
|
|
||
| The portable default imposes no protocol constraint. A WinHTTP HTTP/3 preference expands its | ||
| transport candidates but cannot override an exact HTTP/1.1 or HTTP/2 library requirement. Removing | ||
| a preference is not a conflict; no transport-specific API can require HTTP/3. | ||
|
|
||
| ## Connections | ||
|
|
||
| | Capability | Hyper + either TLS backend | WinHTTP | Public treatment | | ||
| | --- | --- | --- | --- | | ||
| | Fixed maximum connection lifetime | Enforced by retiring aged connections | Session-generation rollover retires the pool no later than the bound | Baseline | | ||
| | Per-connection lifetime callback | Supported by current Hyper options | No portable callback model | Transport-specific; fixed lifetime covers the demonstrated library need | | ||
| | Maximum idle age | Arbitrary duration or unlimited | Shortening is supported; longer retention depends on protocol and native scavenging | Baseline with value/protocol validation | | ||
| | Total connections per origin | Not provided by the current Hyper option | Native per-server cap | Baseline requirement, but Hyper needs a real total-concurrency implementation | | ||
| | Maximum idle connections per host | Current Hyper `max_connections` behavior | No equivalent meaning; WinHTTP's cap is total connections | Rename and keep transport-specific | | ||
| | Coarse idle HTTP/2 health check | Supported | Supported with a native minimum interval | Transport-owned policy; no public option | | ||
| | Keep-alive interval, acknowledgement timeout, and active-only mode | Supported by Hyper | Not available at the same granularity | Transport-specific | | ||
| | Multiple dispatch pools | Implemented above the transport | Can use multiple transport instances | Pipeline policy, not a transport capability | | ||
| | Avoid Nagle/delayed-ACK stalls | Set `TCP_NODELAY` on owned sockets | No setter; calibrated HTTP/1.1 measurements match `TCP_NODELAY`, HTTP/2 still needs qualification | Transport invariant with backend regression coverage | | ||
| | Kernel receive/send buffers | Configurable on owned sockets | No corresponding WinHTTP option | Operating-system default/autotuning | | ||
| | Initial TCP congestion window | Windows custom connectors can call an undocumented `WSAIoctl`; no portable equivalent | No corresponding WinHTTP option | Operating-system/network policy | | ||
|
|
||
| The current `ConnectionPoolOptions::max_connections` name is misleading: Hyper forwards it to | ||
| `pool_max_idle_per_host`, while downstream TVS configuration describes a maximum number of | ||
| concurrent connections per server. These are different guarantees and must become different | ||
| options rather than backend mappings of one field. | ||
|
|
||
| Connection idle age is value-dependent rather than a useful type-level distinction. WinHTTP can | ||
| honor an upper bound by closing earlier, but cannot promise arbitrary long HTTP/1.1 retention. | ||
| Construction validates the requested value together with the protocol requirement. | ||
|
|
||
| Nagle control is deliberately not configurable. General-purpose HTTP needs prompt semantic | ||
| boundaries and control frames; bulk transfers already fill segments, while protocol-aware | ||
| coalescing provides efficiency without ACK-dependent delay. The | ||
| [WinHTTP experiment](../../../fetch_winhttp/docs/nagle-behavior-experiment.md) verifies equivalent | ||
| behavior on the tested path but does not turn an undocumented implementation detail into a | ||
| platform guarantee. | ||
|
|
||
| Fixed socket buffers and initial congestion windows are not portable outcomes. They can defeat | ||
| kernel adaptation, consume memory per connection, or tune one network at the expense of another. | ||
| Application buffers remain separate implementation details. | ||
|
|
||
| ## Timeouts, I/O, and platform services | ||
|
|
||
| | Capability | Hyper + either TLS backend | WinHTTP | Public treatment | | ||
| | --- | --- | --- | --- | | ||
| | End-to-end and attempt deadlines | Pipeline-owned | Pipeline-owned | Pipeline policy | | ||
| | Connect deadline | Wraps connector establishment | Native resolve/connect controls with different phase boundaries | Baseline after defining one observable deadline | | ||
| | Separate resolve/send/receive timers | Not exposed by the supported Hyper path | Native controls | Transport-specific | | ||
| | Streaming request and response bodies | Supported | Native upload/download paths implemented | Required `Transport` invariant | | ||
| | Full-duplex HTTP/2 | Supported | Native behavior demonstrated on Windows 11 build 26100; directional implementation required | Required invariant; retain platform compatibility coverage | | ||
| | Request trailers | Supported by Hyper body frames | No public WinHTTP send API | Fallible request feature; WinHTTP rejects before sending | | ||
| | Response trailers | Supported | Queryable after body completion, including HTTP/1.1 on the supported platform | Fallible terminal response-body frame | | ||
| | Response decompression | Transport can preserve encoded responses | Native support differs by encoding | Owned by configured fetch-level decompression; transports return encoded bodies | | ||
| | Cancellation when the request future is dropped | Supported | Planned through handle closure | Required `Transport` invariant | | ||
| | Plain HTTP opt-in | Pipeline request validation plus transport support | Supported | Pipeline policy | | ||
| | Runtime/executor selection | Hyper requires an adapter | WinHTTP owns asynchronous I/O callbacks | Transport construction | | ||
| | Proxy discovery and integrated Windows authentication | Not in the standard Hyper connector | Native WinHTTP strengths | Transport-specific application configuration | | ||
|
|
||
| ## Demonstrated library requirements | ||
|
|
||
| Current downstream code demonstrates a smaller set than the theoretical backend inventory: | ||
|
|
||
| - gRPC requires HTTP/2 and configures a connect timeout; | ||
| - the TVS client configures exportable client key material, a server-certificate validator, | ||
| connection limits, idle age, and detailed HTTP/2 keep-alive values; | ||
| - fetch integration tests exercise fixed maximum connection lifetime. | ||
|
|
||
| These uses do not automatically justify preserving every existing knob: | ||
|
|
||
| - the TVS connection-limit setting currently maps to Hyper's idle-pool limit rather than the | ||
| configured concurrent-connection meaning and needs correction; | ||
| - detailed keep-alive timings are Hyper mechanisms unless the service can state a portable outcome | ||
| it requires; | ||
| - inherited C# settings for HTTP/2 windows, socket buffers, and initial congestion do not by | ||
| themselves demonstrate a library requirement; transport defaults remain until representative | ||
| benchmarks show a material deficit; | ||
| - the rustls `Validator` should first be reduced to platform trust plus an exact TLS server name. | ||
| Its SAN-pattern and subject-name modalities survive only if concrete TVS deployments cannot name | ||
| one DNS identity present in their certificates. | ||
|
|
||
| ## Public surface conclusion | ||
|
|
||
| The current evidence does not justify capability traits or a transport-generic | ||
| `HttpClientBuilder<T>`. Every demonstrated library requirement has a common observable contract, | ||
| and exact TLS server-name mapping covers the need to reach a local endpoint while authenticating a | ||
| service DNS name. The public builder can therefore be one concrete type with the same methods for | ||
| all supported transports. | ||
|
|
||
| Custom server identity remains outside the proposed surface. It would cover service-defined SAN | ||
| patterns or known subject names only if TVS cannot migrate to an exact DNS identity. Hyper/rustls | ||
| supports that richer mechanism; the current native-TLS adapter and WinHTTP do not. It therefore | ||
| cannot become a portable capability. A TVS library that retains it must select a supporting | ||
| transport through `fetch_hyper_rustls` and reject the others. | ||
|
|
||
| Named client credentials, exact TLS server-name mapping, strict HTTP/2, fixed connection lifetime, | ||
| connect deadline, connection limits, streaming, cancellation, and HTTP/1.1/HTTP/2 constraints | ||
| belong to the baseline and do not need capability traits. | ||
|
|
||
| Arbitrary signers, raw verifier callbacks, and backend TLS objects stay on composition builders. | ||
| Detailed keep-alive controls, HTTP/3, proxy/WPAD, integrated authentication, phase-specific | ||
| timeouts, and pool internals stay composition-owned unless a demonstrated library need justifies a | ||
| dependency-light companion configuration crate. HTTP/2 flow-control sizing, socket buffers, and | ||
| initial congestion are transport-owned defaults rather than public options on any builder. | ||
|
|
||
| Construction remains fallible despite the uniform surface. Invalid values, missing named | ||
| credentials, unsupported operating-system versions, and unavailable resources are environmental | ||
| or provisioning failures; they are not evidence for a type-level transport capability. | ||
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.
A required invariant is being promoted from a single-host manual probe — Testing · Medium · High
The experiment records five manual runs on Windows 11 24H2 build 26100, while Microsoft only guarantees duplex behavior on “some versions.”
fetch_winhttp/docs/design.md:68-75requires every supported client/server baseline to pass before release, andimplementation.md:1333-1341describes future integration coverage, but this change adds only examples and no CI/release gate that executes them across the supported matrix. A later OS or runner change can therefore invalidate a requiredTransportinvariant without failing the suite.Direction: turn the decisive probe cases into gated integration tests and make supported-SKU qualification consume their results before advertising the capability.
Done when: every supported Windows baseline is automatically qualified (or rejected) and a duplex regression blocks release.