Repository navigation
HTTP/3 impl - #3985
Draft
Rafael-Conde wants to merge 41 commits into
Draft
HTTP/3 impl#3985Rafael-Conde wants to merge 41 commits into
Rafael-Conde wants to merge 41 commits into
Conversation
Author
|
@seanmonstar , I'm making my current implementation available here. Let me know if there is a better way do to this. I'm making this changes available to get feedback and improve the implementation! any feedback is welcome! |
Author
|
I plan on keep working on this and make more changes available as soon as I can |
|
May be this also will help you - https://crates.io/crates/axum-h3 axum-h3 - crates.io: Rust Package Registry |
…ad fast path (hyperium#4147) `is_complete_fast` recognizes `\r\n\r\n` and `\n\n` as head terminators but not `\n\r\n`, while the full parser (httparse) accepts all three. So a request whose head ends with `\n\r\n` parses fine when it arrives in a single read, but stalls when it arrives split across reads: the fast path never reports the head complete and the connection keeps waiting for more bytes. This extends the `\n` branch to also accept a following `\r\n`, using the same panic-safe slicing idiom as the `\r` branch. Added the `\n\r\n` witness and the `\n\r` negative to `test_is_complete_fast`, plus a parse-level test documenting that the full parser accepts this terminator. Closes hyperium#4145
Show how to process data and trailer frames while preserving back-pressure, and contrast that with intentionally collecting a bounded body in memory. Closes hyperium#2201
…rium#4167) The following lints no longer exist in recent clippy versions and cause `unknown lint` errors (promoted to errors by `-D warnings` / `-W unknown-lints`): - clippy::unnecessary_rest_pattern - clippy::rest_pattern_accessible_field - clippy::definition_in_module_root Remove them from the allowed lints list in Cargo.toml.
This was referenced Aug 28, 2026
The previous channel variant for `Incoming` used several individual channels to handle the various mechanisms: sending data, signaling error/abort, sending trailers, waiting for optional expect-101 polling. Each individual channel would allocate its own internal shared state in an Arc. Now the `Incoming` channel variant uses a single combined implementation, putting all the required shared pieces in a single Arc. This resulted in less allocations, and less places to potentially store wakers. The following performance improvements were noticed with microbenchmarks: | Benchmark | Before | After | Improvement | | --------------- | ------ | ---------- | ----------- | | Create/drop | 400 ns | 130–139 ns | ~66% | | Data handoff | 229 ns | 147–155 ns | ~34% | | Expect-101 wait | 492 ns | 267–298 ns | ~40–46% |
i stumbled across this while investigating a solution to hyperium#3914. in hyperium#2798, a documentation test was introduced that appears to have been broken since its inception. after spending some time figuring out how to run this documentation test, i found the following errors: ``` ; RUSTDOCFLAGS='--cfg hyper_unstable_ffi' RUSTFLAGS='--cfg hyper_unstable_ffi' cargo test --doc --features client,server,http1,http2,ffi get_in_order Compiling hyper v1.11.1 (/hyper) Finished `test` profile [unoptimized + debuginfo] target(s) in 1.39s Doc-tests hyper running 1 test test src/ext/mod.rs - ext::OriginalHeaderOrder::get_in_order (line 262) - compile ... FAILED failures: ---- src/ext/mod.rs - ext::OriginalHeaderOrder::get_in_order (line 262) stdout ---- error: expected item, found keyword `let` --> src/ext/mod.rs:266:1 | 266 | let mut h_order = OriginalHeaderOrder::default(); | ^^^ `let` cannot be used for global variables | = help: consider using `static` and a `Mutex` instead of `let mut` = note: for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html> error: aborting due to 1 previous error Couldn't compile the test. failures: src/ext/mod.rs - ext::OriginalHeaderOrder::get_in_order (line 262) ``` after wrapping the code in the example in a `fn main() {}` block: ``` ; RUSTDOCFLAGS='--cfg hyper_unstable_ffi' RUSTFLAGS='--cfg hyper_unstable_ffi' cargo test --doc --features client,server,http1,http2,ffi get_in_order Compiling hyper v1.11.1 (/hyper) Finished `test` profile [unoptimized + debuginfo] target(s) in 0.37s Doc-tests hyper running 1 test test src/ext/mod.rs - ext::OriginalHeaderOrder::get_in_order (line 262) - compile ... FAILED failures: ---- src/ext/mod.rs - ext::OriginalHeaderOrder::get_in_order (line 262) stdout ---- error: expected `;`, found keyword `let` --> src/ext/mod.rs:284:22 | 284 | h_order.append(name3) | ^ help: add `;` here 285 | 286 | let mut iter = h_order.get_in_order() | --- unexpected token error: expected `;`, found keyword `let` --> src/ext/mod.rs:286:38 | 286 | let mut iter = h_order.get_in_order() | ^ help: add `;` here 287 | 288 | let (name, idx) = iter.next(); | --- unexpected token error[E0603]: struct `OriginalHeaderOrder` is private --> src/ext/mod.rs:264:17 | 264 | use hyper::ext::OriginalHeaderOrder; | ^^^^^^^^^^^^^^^^^^^ private struct | note: the struct `OriginalHeaderOrder` is defined here --> src/ext/mod.rs:204:1 | 204 | pub(crate) struct OriginalHeaderOrder { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0433]: cannot find type `Headermap` in this scope --> src/ext/mod.rs:269:17 | 269 | let mut h_map = Headermap::new(); | ^^^^^^^^^ use of undeclared type `Headermap` | help: a struct with a similar name exists | 269 - let mut h_map = Headermap::new(); 269 + let mut h_map = HeaderMap::new(); | error: aborting due to 4 previous errors Some errors have detailed explanations: E0433, E0603. For more information about an error, try `rustc --explain E0433`. Couldn't compile the test. failures: src/ext/mod.rs - ext::OriginalHeaderOrder::get_in_order (line 262) ``` after addressing these errors, i observed: ``` error[E0277]: the trait bound `&[u8; 10]: IntoHeaderName` is not satisfied --> src/ext/mod.rs:273:14 | 273 | h_map.append(name1); | ------ ^^^^^ the trait `IntoHeaderName` is not implemented for `&[u8; 10]` | | | required by a bound introduced by this call | help: the following other types implement trait `IntoHeaderName` --> /.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/http-1.3.1/src/header/map.rs:3690:5 | 3690 | impl IntoHeaderName for HeaderName {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `HeaderName` ... 3712 | impl<'a> IntoHeaderName for &'a HeaderName {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a HeaderName` ... 3734 | impl IntoHeaderName for &'static str {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'static str` note: required by a bound in `HeaderMap::<T>::append` --> /.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/http-1.3.1/src/header/map.rs:1373:12 | 1371 | pub fn append<K>(&mut self, key: K, value: T) -> bool | ------ required by a bound in this associated function 1372 | where 1373 | K: IntoHeaderName, | ^^^^^^^^^^^^^^ required by this bound in `HeaderMap::<T>::append` error[E0061]: this method takes 2 arguments but 1 argument was supplied --> src/ext/mod.rs:273:7 | 273 | h_map.append(name1); | ^^^^^^------- argument hyperium#2 of type `HeaderValue` is missing | note: method defined here --> /.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/http-1.3.1/src/header/map.rs:1371:12 | 1371 | pub fn append<K>(&mut self, key: K, value: T) -> bool | ^^^^^^ help: provide the argument | 273 | h_map.append(name1, /* HeaderValue */); | +++++++++++++++++++ ``` because these errors point to missing arguments and incorrect types, this commit removes this example altogether. i'm not convinced it was ever run. Signed-off-by: katelyn martin <git@katelyn.world>
…erium#4196) This adjusts hyperium#4110 to use `append` instead of `insert` when a nonzero number of "connection" headers are already present, and only if none of the existing headers already include the value being added. Fixes hyperium#4195
…um#4198) The send task of an HTTP/2 `Upgraded` stream reserved one byte of capacity at the top of every loop, before any write was queued. As with `PipeToSendStream` before hyperium#4061, an idle tunnel then pins the last byte of the connection-level window, and a second stream can deadlock against peers that only send WINDOW_UPDATE once their window is exhausted. Pull the next write from the channel first, hold it until h2 has capacity, and only then reserve. The next write is still not pulled before the held one is handed to h2, so the writer keeps seeing backpressure. The task now always polls the channel when it holds nothing, which makes the separate close notification unnecessary, so remove it. Refs hyperium#4003
- capi/README.md: "staring with" -> "starting with" in the build instructions - docs/MSRV.md: "Minimum Support Rust Version" -> "Minimum Supported Rust Version" - docs/GOVERNANCE.md: "elsehwere" -> "elsewhere"
…wlist (hyperium#4220) Fix the two remaining violations in src/proto/h1/decode.rs by inlining the header variable into the format string, which also satisfies the uninlined_format_args lint that the old &header borrow was dodging. Refs: hyperium#4071
…m#4183) Adds max_header_size(val: usize) on both server and client HTTP/1 builders. This allows configuring an explicit byte limit for request/response headers (including the start line and chunked trailers). When the limit is exceeded: - On server: responds with 431 Request Header Fields Too Large and closes the connection. - On client: returns a Parse::TooLarge error (is_parse_too_large). - On chunked decoder: replaces existing TODO in proto/h1/conn.rs with the configured h1_max_header_size. Closes hyperium#3832.
…yperium#4201) When parsing a message with more than one `Connection` header line, the per-line logic keyed the branch off the current value of `keep_alive`, so a line that set `keep_alive` to false made the next line take the HTTP/1.0 arm and set it back to true. `Connection: close` followed by `Connection: keep-alive` therefore parsed as keep-alive, while the reverse order parsed correctly. Track whether any `Connection` line carried a `close` token and let that win for the rest of the loop, in both `Server::parse` and `Client::parse`. HTTP/1.0 messages that opt in with `Connection: keep-alive` are unchanged.
…request (hyperium#4208) The Receiver signals want when its queue reports Pending, and SendRequest::is_ready reports that want. A want signaled after finding the queue empty can land after the Sender's give() for the request that follows, and tokio's coop budget can make the queue report Pending with a request already queued. Either way the request is taken with want set, and the connection reports ready until the response completes. hyper-util's legacy pool returns connections on is_ready, so it hands a busy connection to the next request, which then waits behind the whole response. Withdraw the want with want::Taker::unwant when a request is taken. Want is signaled again once the dispatcher is idle. Requires want with Taker::unwant (seanmonstar/want#6).
- Make sure the bare links render as clickable. - Add a note to refrain from using AI/LLMs when writing a HIP.
…rium#4222) Keep the closed dispatch receiver alive until all in-progress sends have published and canceled their callbacks Preserve the connection result across drain polls and keep upgrade handoffs unchanged Closes hyperium#4202
…hyperium#4229) This should be able to run automatically even without our approving of new contributors PRs, so they will hopefully be alerted before we have to read some generated PR description that is overly long. Organization members are skipped, since there is already trust established.
see hyperium#4071. this commit addresses the `let_unit_value` clippy lint. only two sites are affected, relating to tracing spans. this commit introduces a `hyper::trace::Disabled` type to act as a ZST marker in places that can sometimes conditionally compile to a `tracing::span::Entered` guard. this is based upon experimenting in <https://github.com/cratelyn/hyper-span-macro-example>. to restate some of those learnings here: ### background hyper contains a `trace` submodule, introduced in hyperium#3326, that contains macros like the following: ```rust macro_rules! trace { ($($arg:tt)*) => { #[cfg(feature = "tracing")] { tracing::trace!($($arg)+); } } } macro_rules! trace_span { ($($arg:tt)*) => { { #[cfg(feature = "tracing")] { let _span = tracing::trace_span!($($arg)+); _span.entered() } } } } ``` these thinly wrap `tracing`'s macros, to account for the fact that tracing support in hyper is opt-in. it is gated behind a feature flag, and additionally mandates that the `hyper_unstable_tracing` flag be enabled. however, this leads to violations of clippy's `let_unit_value` rule when compiled without the `tracing` feature flag is enabled. this is because `trace_span!` only returns a `tracing::span::Entered` when that flag is active, otherwise it returns `()`. thus, we *must* bind these calls to a variable, so that we properly hold on to the span guard when the tracing flag is active. however, we must contend with the fact that when this flag is not active, strict clippy linting yields us warnings like this: ```text cargo clippy --no-default-features Checking hyper-span-macro-example v0.1.0 error: this let-binding has unit value --> src/main.rs:52:5 | 52 | let _entered = trace_span!("instrumented"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.99.0/index.html#let_unit_value ``` ### why not use `#[allow(..)]` one might try to selectively apply `#[allow(clippy::let_unit_value)]` attributes to stifle this. however, applying attributes to expressions is still a nightly feature we cannot rely on yet, so call-sites for our macros must be updated rather than modifying the code generated by the macro. see rust-lang/rust#15701. this would require us to do something like this throughout the codebase, wherever we create tracing spans: ```rust #[cfg_attr(not(feature = "tracing"), allow(clippy::let_unit_value))] let _entered = trace_span!("instrumented"); ``` `#[cfg_attr]` is a bit esoteric, and if we require that instrumenting code in hyper require this song and dance every time we create a span, it will generally discourage instrumentation. ### changes this commit introduce a `Disabled` type to replace the empty `()` when tracing instrumentation is disabled. this satisfies clippy's `let_unit_value` rule because macros like `trace_span!` will never return `()` no matter which feature flags are active. this _also_ prevents accidentally writing code that would drop span guards once the tracing flag is enabled, because an inert `#[must_use]` guard acts as a stand-in when the flag isn't present. Signed-off-by: katelyn martin <git@katelyn.world>
Rafael-Conde
force-pushed
the
rafael/http3-impl
branch
from
October 19, 2026 18:23
bc12303 to
b073378
Compare
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
I'm creating this as a draft to make my attempt so far available.
I haven't done much but I already got a lot of questions, I got time in my hands and I would like to keep contributing, but I would appreciate feedback to whether I'm going in the right direction or not and how could I improve my current attempt.
I'm looking to improve myself and the contribution in general!
I intend to keep working on it and make more changes available as I feel like input could greatly benefit the end result.