-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
HTTP/2 103 Early Hints Support #3991
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
base: master
Are you sure you want to change the base?
Conversation
|
Hello @dicej , @pablocm, @vikanezrimaya, @nox, @seanmonstar! My commit originally builds on @dicej's prototype commit 4e2483a in PR - #3815. However, this code is obsolete and does not build anymore. Therefore, I have included both the commits in my PR. @seanmonstar @nox let me know if this would be the right way to move forward. The code changes follow the proposed public API suggested from @vikanezrimaya. After merging this, I will release a PR for Axum wrapper. Note - The tests will pass once we merge the h2 repo's PR - hyperium/h2#865 Thank you very much once again for your time and support. 🙏🏼 |
This is a prototype intended to spur discussion about what support for 1xx informational responses should look like in a Hyper server. The good news is that it works great (for HTTP/1 only, so far). The bad news is it's kind of ugly. Here's what I did: - Add `ext::InformationalSender`, a type which wraps a `futures_channel::mspc::Sender<Response<()>>`. This may be added as an extension to an inbound `Request` by the Hyper server, and the application and/or middleware may use it to send one or more informational responses before sending the real one. - Add code to `proto::h1::dispatch` and friends to add such an extension to each inbound request and then poll the `Receiver` end along with the future representing the final response. If the app never sends any informational responses, then everything proceeds as normal. Otherwise, we send those responses as they become available until the final response is ready. TODO items: - [ ] Also support informational responses in the HTTP/2 server. - [ ] Determine best way to handle when the app sends an informational response with a non-1xx status code. Currently we just silently ignore it. - [ ] Come up with a less hacky API? - [ ] Add test coverage. Signed-off-by: Joel Dice <joel.dice@fermyon.com>
Add complete HTTP/2 103 Early Hints implementation with client and server support: - Add InformationalSender extension for server-side hint transmission via mpsc channel - Create InformationalCallback system for client-side informational response handling - Extend HTTP/2 client builder with informational_responses() configuration method - Implement informational response polling in h2 client task with callback invocation - Add server-side informational response forwarding using h2's send_informational API - Include extensive integration tests covering multiple scenarios and edge cases - Add complete working example with TLS, resource preloading, and performance monitoring - Update Cargo.toml with local h2 dependency and example build configuration The implementation enables servers to send resource preload hints before final responses, allowing browsers to start downloading critical resources early and improve page load performance. Clients can register callbacks to process 103 Early Hints and other informational responses. Closes hyperium#3980, hyperium#2426
JakubKoralewski
left a comment
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.
Hi, I'm interested in 10x support so thought I'd contribute a review. Thanks for this work. I am not a contributor just hope to make it easier to review for someone in charge.
| use http::{Method, Request}; | ||
| use pin_project_lite::pin_project; | ||
|
|
||
| #[cfg(feature = "server")] |
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 think src/proto/h2/mod.rs already makes sure this whole file is #[cfg(server)] (applies to all instances of #[cfg(feature)] in this file)
| } | ||
|
|
||
| #[cfg(feature = "server")] | ||
| let (informational_tx, informational_rx) = mpsc::channel(10); |
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.
informational_pusher will solve this:
this creates a new channel for each call to .poll_server, doesn't seem right, no?
looks like mpsc::channel does not allocate the whole bounded_size, but it does create a bunch (>=3) Boxes,
once informational_pusher is used, and if contributors agree to add a crate it might be worth to consider https://docs.rs/thingbuf/latest/thingbuf/struct.StaticThingBuf.html
| tokio-test = "0.4" | ||
| tokio-util = "0.7.10" | ||
| # Additional dependencies for HTTP/2 Early Hints example | ||
| rcgen = "0.12" |
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.
in [dependencies]: maybe make it clear that 0.4.13 is required for "h2" crate?
| // API data (lower priority - dynamic content) | ||
| .header( | ||
| "link", | ||
| "</api/initial-data.json>; rel=preload; as=fetch; crossorigin", |
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.
nit; isn't this a misuse of preloading if data is not needed to display above-fold-content?
| #[cfg(feature = "server")] | ||
| { | ||
| req.extensions_mut() | ||
| .insert(InformationalSender(informational_tx)); |
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.
what if the user does not care about their server supporting 10x? should this Sender still be created?
you should probably use the API accepted by @seanmonstar, i.e. this: https://gist.github.com/vikanezrimaya/037101dc7b28de37ef03a47569213236#api-based-on-the-old-server-push-proposal (linked to title api-based-on-the-old-server-push-proposal) (with the caveatt it should be informational_pusher not :early_hints_pusher) and then the pusher can add the extension so it only gets added when needed
(my api idea) before I saw the one based on the old server push proposal
request.provide_interim(Response::builder().status(StatusCode::EARLY_HINTS).body(()).unwrap());where implementation is this Rusty-pseudocode:
trait HttpRequestExtInterim {
fn provide_interim(&mut self, hints: Response<()>) -> TrySendError<Response<()>> {
let request = self;
let (rx, tx) = mpsc::channel(10); // or something non-allocating?
request.extensions_mut().insert(InformationalSender(tx));
tx.try_send(hints)
}
}
because the extension needs to be on the Request before the call to H2Stream, I'm guessing in the Service handler we are after?
but what if InformationalSender stored lazily both sides of the mpsc::channel with an None Option at first, and then the HttpRequestExtInterim.provide_interim actually allocated the Option only when used?
| loop { | ||
| // Check for informational responses first | ||
| #[cfg(feature = "server")] | ||
| if let Some(informational_rx) = me.informational_rx.as_mut() { |
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.
shouldn't this be in the H2StreamStateProj::Service case, i.e. no need to check for informational if we're currently streaming the Body?
Implement HTTP/2 103 Early Hints Support
Add complete HTTP/2 103 Early Hints implementation with full client and server support, building upon the initial 1xx informational responses prototype to deliver a solution for web performance optimization.
Key Features Added
Client-side Support
InformationalConfigwith callback system for processing 1xx informational responsesinformational_responses()configuration methodServer-side Support
InformationalSenderextension for server-side hint transmission via mpsc channelComplete Implementation
Changed Files
Use Cases Supported
Technical Implementation
Standards Compliance
Browser Tests
The implementation provides a robust foundation for web performance optimization while maintaining the reliability and safety expected from the hyper HTTP library.
Resolves #3980 and #2426 for HTTP/2 103 Early Hints support and extends the informational responses capability for HTTP/2 protocols.