Skip to content

Commit

Permalink
always attempt http/2
Browse files Browse the repository at this point in the history
  • Loading branch information
goatgoose committed Nov 22, 2024
1 parent e87a725 commit 0220444
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 33 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci_rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ jobs:
working-directory: ${{env.ROOT_PATH}}
run: cargo test

- name: "Feature Tests: Fingerprint, kTLS, QUIC, PQ, and http2"
- name: "Feature Tests: Fingerprint, kTLS, QUIC, and PQ"
working-directory: ${{env.ROOT_PATH}}
# Test all features except for FIPS, which is tested separately.
run: cargo test --features unstable-fingerprint,unstable-ktls,quic,pq,http2
run: cargo test --features unstable-fingerprint,unstable-ktls,quic,pq

- name: "Feature Test: Renegotiate"
working-directory: ${{env.ROOT_PATH}}
Expand Down
10 changes: 4 additions & 6 deletions bindings/rust/s2n-tls-hyper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,20 @@ license = "Apache-2.0"
publish = false

[features]
default = ["http1"]
http1 = ["hyper-util/http1"]
http2 = ["hyper-util/http2", "dep:hashbrown", "dep:tokio-util"]
default = []

[dependencies]
s2n-tls = { version = "=0.3.7", path = "../s2n-tls" }
s2n-tls-tokio = { version = "=0.3.7", path = "../s2n-tls-tokio" }
hyper = { version = "1" }
hyper-util = { version = "0.1", features = ["client-legacy", "tokio"] }
hyper-util = { version = "0.1", features = ["client-legacy", "tokio", "http1", "http2"] }
tower-service = { version = "0.3" }
http = { version = "1" }

# Newer versions require Rust 1.65, see https://github.com/aws/s2n-tls/issues/4242.
hashbrown = { version = "=0.15.0", optional = true }
hashbrown = { version = "=0.15.0" }
# Newer versions require Rust 1.70, see https://github.com/aws/s2n-tls/issues/4395.
tokio-util = { version = "=0.7.11", optional = true }
tokio-util = { version = "=0.7.11" }

[dev-dependencies]
tokio = { version = "1", features = ["macros", "test-util"] }
Expand Down
14 changes: 13 additions & 1 deletion bindings/rust/s2n-tls-hyper/src/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ where
///
/// This API creates an `HttpsConnector` using the default hyper `HttpConnector`. To use an
/// existing HTTP connector, use `HttpsConnector::new_with_http()`.
///
/// Note that the HttpsConnector will automatically attempt to negotiate HTTP/2 by overriding
/// the ALPN extension. Any ALPN values configured on `conn_builder` with APIs like
/// `s2n_tls::config::Builder::set_application_protocol_preference()` will be ignored.
pub fn new(conn_builder: Builder) -> HttpsConnector<HttpConnector, Builder> {
let mut http = HttpConnector::new();

Expand Down Expand Up @@ -77,6 +81,10 @@ where
/// ```
///
/// `HttpsConnector::new()` can be used to create the HTTP connector automatically.
///
/// Note that the HttpsConnector will automatically attempt to negotiate HTTP/2 by overriding
/// the ALPN extension. Any ALPN values configured on `conn_builder` with APIs like
/// `s2n_tls::config::Builder::set_application_protocol_preference()` will be ignored.
pub fn new_with_http(http: Http, conn_builder: Builder) -> HttpsConnector<Http, Builder> {
Self { http, conn_builder }
}
Expand Down Expand Up @@ -118,7 +126,11 @@ where
return Box::pin(async move { Err(Error::InvalidScheme) });
}

let builder = self.conn_builder.clone();
// Attempt to negotiate HTTP/2.
let builder = connection::ModifiedBuilder::new(self.conn_builder.clone(), |conn| {
conn.set_application_protocol_preference([b"h2"])
});

let host = req.host().unwrap_or("").to_owned();
let call = self.http.call(req);
Box::pin(async move {
Expand Down
1 change: 0 additions & 1 deletion bindings/rust/s2n-tls-hyper/src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ where
let conn = stream.inner().as_ref();
match conn.application_protocol() {
// Inform hyper that HTTP/2 was negotiated in the ALPN.
#[cfg(feature = "http2")]
Some(b"h2") => connected.negotiated_h2(),
_ => connected,
}
Expand Down
64 changes: 41 additions & 23 deletions bindings/rust/s2n-tls-hyper/tests/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,43 +218,26 @@ async fn error_matching() -> Result<(), Box<dyn Error + Send + Sync>> {

#[tokio::test]
async fn http2() -> Result<(), Box<dyn Error + Send + Sync>> {
let server_config = {
let mut builder = common::config()?;
builder.set_application_protocol_preference(["h2"])?;
builder.build()?
};

for send_h2 in [true, false] {
let client_config = {
for expected_http_version in [Version::HTTP_11, Version::HTTP_2] {
let server_config = {
let mut builder = common::config()?;
if send_h2 {
if expected_http_version == Version::HTTP_2 {
builder.set_application_protocol_preference(["h2"])?;
}
builder.build()?
};

common::echo::make_echo_request(server_config.clone(), |port| async move {
let connector = HttpsConnector::new(client_config);
let connector = HttpsConnector::new(common::config()?.build()?);
let client: Client<_, Empty<Bytes>> =
Client::builder(TokioExecutor::new()).build(connector);

let uri = Uri::from_str(format!("https://localhost:{}", port).as_str())?;
let response = client.get(uri).await?;
assert_eq!(response.status(), 200);

// Ensure that HTTP/2 is negotiated when included in the ALPN.
#[cfg(feature = "http2")]
let expected_version = match send_h2 {
true => Version::HTTP_2,
false => Version::HTTP_11,
};

// If the http2 feature isn't enabled, then HTTP/1 should be negotiated even if HTTP/2
// was included in the ALPN.
#[cfg(not(feature = "http2"))]
let expected_version = Version::HTTP_11;

assert_eq!(response.version(), expected_version);
// Ensure that HTTP/2 is negotiated when supported by the server.
assert_eq!(response.version(), expected_http_version);

Ok(())
})
Expand All @@ -263,3 +246,38 @@ async fn http2() -> Result<(), Box<dyn Error + Send + Sync>> {

Ok(())
}

/// Ensure that HTTP/2 is negotiated, regardless of any pre-configured ALPN values.
#[tokio::test]
async fn config_alpn_ignored() -> Result<(), Box<dyn Error + Send + Sync>> {
let server_config = {
let mut builder = common::config()?;
builder.set_application_protocol_preference(["h2"])?;
builder.build()?
};

common::echo::make_echo_request(server_config, |port| async move {
let client_config = {
let mut builder = common::config()?;
// Set an arbitrary non-HTTP/2 ALPN value.
builder.set_application_protocol_preference([b"http/1.1"])?;
builder.build()?
};

let connector = HttpsConnector::new(client_config);
let client: Client<_, Empty<Bytes>> =
Client::builder(TokioExecutor::new()).build(connector);

let uri = Uri::from_str(format!("https://localhost:{}", port).as_str())?;
let response = client.get(uri).await?;
assert_eq!(response.status(), 200);

// Ensure that HTTP/2 was negotiated.
assert_eq!(response.version(), Version::HTTP_2);

Ok(())
})
.await?;

Ok(())
}

0 comments on commit 0220444

Please sign in to comment.