Skip to content

Document that the Connector can determine HTTP version #2717

Open
@jyn514

Description

@jyn514

Version
hyper 0.14.14

Platform
Linux pop-os 5.13.0-7614-generic #14~1631647151~20.04~930e87c-Ubuntu SMP Fri Sep 17 00:26:31 UTC x86_64 x86_64 x86_64 GNU/Linux

Description

Hyper silently upgrades HTTPS requests that set Version::HTTP_11 to an HTTP/2 connection.

I tried this code:

    // set up https client to connect to the preview service
    let https = HttpsConnector::with_native_roots();
    let client = HyperClient::builder().build::<_, Body>(https);

    // create a closure that hyper will use later to handle HTTP requests
    let make_service = make_service_fn(move |_| {
        let client = client.to_owned();

        async move {
            Ok::<_, anyhow::Error>(service_fn(move |req| {
                let client = client.to_owned();
                *req.uri_mut() = "https://example.com".parse().unwrap();
                *req.version_mut() = Version::HTTP_11;
                async move {
                    let mut resp = match client.request(req).await {
                        Ok(r) => r,
                        Err(err) => {
                            panic!("{}", err);
                        }
                    };

I expected to see this happen: Hyper sends an HTTP/1.1 request.
Instead, this happened: Hyper sends an HTTP/2 request.

You can verify this either with wireshark or by applying this diff, which will cause the above snippet to panic instead of sending the wrong version:

diff --git a/src/client/client.rs b/src/client/client.rs
index 72a78ab1..95810583 100644
--- a/src/client/client.rs
+++ b/src/client/client.rs
@@ -268,6 +268,11 @@ where
             } else {
                 origin_form(req.uri_mut());
             }
+        } else if pooled.is_http2() && req.version() != Version::HTTP_2 {
+            warn!("Connection is HTTP/2, but request requires HTTP/1");
+            return Err(ClientError::Normal(
+                crate::Error::new_user_unsupported_version(),
+            ));
         } else if req.method() == Method::CONNECT {
             authority_form(req.uri_mut());
         }

This matters when proxying websocket connections, which are only supported with HTTP/2 when the server supports the RFC 8441 extension.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-clientArea: client.A-docsArea: documentation.E-easyEffort: easy. A task that would be a great starting point for a new contributor.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions