Skip to content

Commit af7d24a

Browse files
committed
feat(h2): implement the extended CONNECT protocol from RFC 8441
1 parent b5022f3 commit af7d24a

File tree

8 files changed

+57
-2
lines changed

8 files changed

+57
-2
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,3 +252,6 @@ required-features = ["full"]
252252
name = "server"
253253
path = "tests/server.rs"
254254
required-features = ["full"]
255+
256+
[patch.crates-io]
257+
h2 = { git = "https://github.com/hyperium/h2.git", branch = "rfc8441" }

src/client/conn.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,23 @@ where
486486
Poll::Ready(Ok(conn.take().unwrap().into_parts()))
487487
})
488488
}
489+
490+
/// Returns whether the [extended CONNECT protocol][1] is enabled or not.
491+
///
492+
/// This setting is configured by the server peer by sending the
493+
/// [`SETTINGS_ENABLE_CONNECT_PROTOCOL` parameter][2] in a `SETTINGS` frame.
494+
/// This method returns the currently acknowledged value recieved from the
495+
/// remote.
496+
///
497+
/// [1]: https://datatracker.ietf.org/doc/html/rfc8441#section-4
498+
/// [2]: https://datatracker.ietf.org/doc/html/rfc8441#section-3
499+
#[cfg(feature = "http2")]
500+
pub fn http2_is_extended_connect_protocol_enabled(&self) -> bool {
501+
match self.inner.as_ref().unwrap() {
502+
ProtoClient::H1 { .. } => false,
503+
ProtoClient::H2 { h2 } => h2.is_extended_connect_protocol_enabled(),
504+
}
505+
}
489506
}
490507

491508
impl<T, B> Future for Connection<T, B>

src/ext.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
//! HTTP extensions
1+
//! HTTP extensions.
22
33
use bytes::Bytes;
44
#[cfg(feature = "http1")]
55
use http::header::{HeaderName, IntoHeaderName, ValueIter};
66
use http::HeaderMap;
77

8+
#[cfg(feature = "http2")]
9+
pub use h2::ext::Protocol;
10+
811
/// A map from header names to their original casing as received in an HTTP message.
912
///
1013
/// If an HTTP/1 response `res` is parsed on a connection whose option

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ mod cfg;
7676
mod common;
7777
pub mod body;
7878
mod error;
79-
mod ext;
79+
pub mod ext;
8080
#[cfg(test)]
8181
mod mock;
8282
pub mod rt;

src/proto/h2/client.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,15 @@ where
200200
req_rx: ClientRx<B>,
201201
}
202202

203+
impl<B> ClientTask<B>
204+
where
205+
B: HttpBody + 'static,
206+
{
207+
pub(crate) fn is_extended_connect_protocol_enabled(&self) -> bool {
208+
self.h2_tx.is_extended_connect_protocol_enabled()
209+
}
210+
}
211+
203212
impl<B> Future for ClientTask<B>
204213
where
205214
B: HttpBody + Send + 'static,

src/proto/h2/server.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub(crate) struct Config {
4040
pub(crate) initial_conn_window_size: u32,
4141
pub(crate) initial_stream_window_size: u32,
4242
pub(crate) max_frame_size: u32,
43+
pub(crate) enable_connect_protocol: bool,
4344
pub(crate) max_concurrent_streams: Option<u32>,
4445
#[cfg(feature = "runtime")]
4546
pub(crate) keep_alive_interval: Option<Duration>,
@@ -54,6 +55,7 @@ impl Default for Config {
5455
initial_conn_window_size: DEFAULT_CONN_WINDOW,
5556
initial_stream_window_size: DEFAULT_STREAM_WINDOW,
5657
max_frame_size: DEFAULT_MAX_FRAME_SIZE,
58+
enable_connect_protocol: false,
5759
max_concurrent_streams: None,
5860
#[cfg(feature = "runtime")]
5961
keep_alive_interval: None,
@@ -113,6 +115,9 @@ where
113115
if let Some(max) = config.max_concurrent_streams {
114116
builder.max_concurrent_streams(max);
115117
}
118+
if config.enable_connect_protocol {
119+
builder.enable_connect_protocol();
120+
}
116121
let handshake = builder.handshake(io);
117122

118123
let bdp = if config.adaptive_window {

src/server/conn.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,15 @@ impl<E> Http<E> {
500500
self
501501
}
502502

503+
/// Enables the [extended CONNECT protocol].
504+
///
505+
/// [extended CONNECT protocol]: https://datatracker.ietf.org/doc/html/rfc8441#section-4
506+
#[cfg(feature = "http2")]
507+
pub fn http2_enable_connect_protocol(&mut self) -> &mut Self {
508+
self.h2_builder.enable_connect_protocol = true;
509+
self
510+
}
511+
503512
/// Set the maximum buffer size for the connection.
504513
///
505514
/// Default is ~400kb.

src/server/server.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,15 @@ impl<I, E> Builder<I, E> {
403403
self
404404
}
405405

406+
/// Enables the [extended CONNECT protocol].
407+
///
408+
/// [extended CONNECT protocol]: https://datatracker.ietf.org/doc/html/rfc8441#section-4
409+
#[cfg(feature = "http2")]
410+
pub fn http2_enable_connect_protocol(mut self) -> Self {
411+
self.protocol.http2_enable_connect_protocol();
412+
self
413+
}
414+
406415
/// Sets the `Executor` to deal with connection tasks.
407416
///
408417
/// Default is `tokio::spawn`.

0 commit comments

Comments
 (0)