hyperium / hyperium/hyper

Document that the Connector can determine HTTP version

Open
#2,717 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-client A-docs E-easy
Dominant language
Rust
Stars
16.3k
Forks
1.8k
Avg merge
1d 22h
Merged PRs (30d)
14

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the HTTPS example and the referenced src/client/client.rs diff, focusing on how the Connector handles HTTP_11 requests and HTTP/2 connections. Add documentation describing this behavior and its relevance to proxied WebSocket connections and RFC 8441. Done when the documented behavior matches what the example and diff demonstrate.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
documentation
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.