From 519e0fb67638002b346787fd8955cea497c8181b Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Wed, 3 Nov 2021 10:12:08 +0100 Subject: [PATCH] feat(h2): implement the extended CONNECT protocol from RFC 8441 --- Cargo.toml | 3 +++ src/client/conn.rs | 17 +++++++++++++++++ src/ext.rs | 5 ++++- src/lib.rs | 2 +- src/proto/h2/client.rs | 9 +++++++++ src/proto/h2/server.rs | 5 +++++ src/server/conn.rs | 9 +++++++++ src/server/server.rs | 9 +++++++++ 8 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c119a106c3..c62b13fd34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -252,3 +252,6 @@ required-features = ["full"] name = "server" path = "tests/server.rs" required-features = ["full"] + +[patch.crates-io] +h2 = { git = "https://github.com/hyperium/h2.git", branch = "rfc8441" } diff --git a/src/client/conn.rs b/src/client/conn.rs index 1b7b661994..57917a2980 100644 --- a/src/client/conn.rs +++ b/src/client/conn.rs @@ -486,6 +486,23 @@ where Poll::Ready(Ok(conn.take().unwrap().into_parts())) }) } + + /// Returns whether the [extended CONNECT protocol][1] is enabled or not. + /// + /// This setting is configured by the server peer by sending the + /// [`SETTINGS_ENABLE_CONNECT_PROTOCOL` parameter][2] in a `SETTINGS` frame. + /// This method returns the currently acknowledged value recieved from the + /// remote. + /// + /// [1]: https://datatracker.ietf.org/doc/html/rfc8441#section-4 + /// [2]: https://datatracker.ietf.org/doc/html/rfc8441#section-3 + #[cfg(feature = "http2")] + pub fn http2_is_extended_connect_protocol_enabled(&self) -> bool { + match self.inner.as_ref().unwrap() { + ProtoClient::H1 { .. } => false, + ProtoClient::H2 { h2 } => h2.is_extended_connect_protocol_enabled(), + } + } } impl Future for Connection diff --git a/src/ext.rs b/src/ext.rs index 10cde75970..8885417a0e 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -1,10 +1,13 @@ -//! HTTP extensions +//! HTTP extensions. use bytes::Bytes; #[cfg(feature = "http1")] use http::header::{HeaderName, IntoHeaderName, ValueIter}; use http::HeaderMap; +#[cfg(feature = "http2")] +pub use h2::ext::Protocol; + /// A map from header names to their original casing as received in an HTTP message. /// /// If an HTTP/1 response `res` is parsed on a connection whose option diff --git a/src/lib.rs b/src/lib.rs index 41a0b37518..f7a93a1959 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,7 +76,7 @@ mod cfg; mod common; pub mod body; mod error; -mod ext; +pub mod ext; #[cfg(test)] mod mock; pub mod rt; diff --git a/src/proto/h2/client.rs b/src/proto/h2/client.rs index ae20c8515b..5eaaca3b9c 100644 --- a/src/proto/h2/client.rs +++ b/src/proto/h2/client.rs @@ -200,6 +200,15 @@ where req_rx: ClientRx, } +impl ClientTask +where + B: HttpBody + 'static, +{ + pub(crate) fn is_extended_connect_protocol_enabled(&self) -> bool { + self.h2_tx.is_extended_connect_protocol_enabled() + } +} + impl Future for ClientTask where B: HttpBody + Send + 'static, diff --git a/src/proto/h2/server.rs b/src/proto/h2/server.rs index ad06174646..d5161b4b92 100644 --- a/src/proto/h2/server.rs +++ b/src/proto/h2/server.rs @@ -40,6 +40,7 @@ pub(crate) struct Config { pub(crate) initial_conn_window_size: u32, pub(crate) initial_stream_window_size: u32, pub(crate) max_frame_size: u32, + pub(crate) enable_connect_protocol: bool, pub(crate) max_concurrent_streams: Option, #[cfg(feature = "runtime")] pub(crate) keep_alive_interval: Option, @@ -54,6 +55,7 @@ impl Default for Config { initial_conn_window_size: DEFAULT_CONN_WINDOW, initial_stream_window_size: DEFAULT_STREAM_WINDOW, max_frame_size: DEFAULT_MAX_FRAME_SIZE, + enable_connect_protocol: false, max_concurrent_streams: None, #[cfg(feature = "runtime")] keep_alive_interval: None, @@ -113,6 +115,9 @@ where if let Some(max) = config.max_concurrent_streams { builder.max_concurrent_streams(max); } + if config.enable_connect_protocol { + builder.enable_connect_protocol(); + } let handshake = builder.handshake(io); let bdp = if config.adaptive_window { diff --git a/src/server/conn.rs b/src/server/conn.rs index b488f8ba7e..79c099030d 100644 --- a/src/server/conn.rs +++ b/src/server/conn.rs @@ -500,6 +500,15 @@ impl Http { self } + /// Enables the [extended CONNECT protocol]. + /// + /// [extended CONNECT protocol]: https://datatracker.ietf.org/doc/html/rfc8441#section-4 + #[cfg(feature = "http2")] + pub fn http2_enable_connect_protocol(&mut self) -> &mut Self { + self.h2_builder.enable_connect_protocol = true; + self + } + /// Set the maximum buffer size for the connection. /// /// Default is ~400kb. diff --git a/src/server/server.rs b/src/server/server.rs index 0d559c579d..55b052239b 100644 --- a/src/server/server.rs +++ b/src/server/server.rs @@ -403,6 +403,15 @@ impl Builder { self } + /// Enables the [extended CONNECT protocol]. + /// + /// [extended CONNECT protocol]: https://datatracker.ietf.org/doc/html/rfc8441#section-4 + #[cfg(feature = "http2")] + pub fn http2_enable_connect_protocol(mut self) -> Self { + self.protocol.http2_enable_connect_protocol(); + self + } + /// Sets the `Executor` to deal with connection tasks. /// /// Default is `tokio::spawn`.