Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

can't upgrade request that came in with `Connection: close, Upgrade`

Ouverte
#4,244 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

@akasakariko y travaille déjà.

Depuis le 27/10/2026.

  • #4248 par @akasakariko — ouverte

Évaluation

Difficulté
3/5
Temps estimé
1-2 jours
Accessibilité débutants
62/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
rust
Domaine
networking

Piste de recherche

Start with the linked src/proto/h1/conn.rs code that rewrites the response Connection header, then run the issue's gist or add a focused test that exercises a request with Connection: close, Upgrade. Trace how requested connection options are merged into the 101 response and make the upgrade response emit only upgrade for both request forms. Done means the sample prints Connection: ["upgrade"] for both Upgrade and close, Upgrade requests.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

C-bug
Version

hyper 1.12.0

Platform

Linux 6.16.3+deb13-amd64

Summary

I'm trying to support a particular WebSocket client (UniFi G6 camera), and the sequence goes as follows:

  1. Client request comes in with the header Connection: close, Upgrade. Apparently this means either upgrade or close the connection. (RFC 9110 section 7.6.1 says it's a list of options.)
  2. my hyper application (using axum) attempts to do the upgrade with 101 Connection: Upgrade
  3. hyper replaces the Connection: Upgrade with Connection: upgrade, close (hyper 1.12.0) or Connection: close (hyper 1.8.1). My AI buddy and I think that because 101 is not a final response, saying close doesn't make sense. https://github.com/hyperium/hyper/blob/7f67699ce32d717081deb7018b4da7d679277ac0/src/proto/h1/conn.rs#L715
  4. the client logs 2026-10-26T05:34:17+0000 P4 19156,969 avclient[1561]: Internal transfer error occurred: HS: UPGRADE malformed [ubnt_avclient:connection.cpp:SecureTransferProtocolHandler:308] and gives up rather than establishing the websocket. It might be using this code: https://github.com/warmcat/libwebsockets/blob/v3.0.1/lib/roles/ws/client-ws.c#L271 . Apparently newer versions are less picky https://github.com/warmcat/libwebsockets/blob/v3.1.0/lib/roles/ws/client-ws.c#L276 but, you know, the client's running the version it's running.

If I use tokio-tungstenite directly, it sends Connection: Upgrade in response, and the websocket gets set up correctly.

Code Sample

Here's a sample that just shows the request -> response headers with a hyper client and server (removing the camera, axum, and tungstenite). https://gist.github.com/scottlamb/b83ee082af86c306320efb9ae90491b3

use hyper::header::{CONNECTION, HeaderValue, UPGRADE};
use hyper::{Request, Response, StatusCode};
use hyper_util::rt::TokioIo;

async fn upgrade(mut req: Request<hyper::body::Incoming>) -> Result<Response<String>, hyper::Error> {
    let on_upgrade = hyper::upgrade::on(&mut req);
    tokio::spawn(async move {
        let _ = on_upgrade.await;
    });
    let mut resp = Response::new(String::new());
    *resp.status_mut() = StatusCode::SWITCHING_PROTOCOLS;
    resp.headers_mut().insert(CONNECTION, HeaderValue::from_static("upgrade"));
    resp.headers_mut().insert(UPGRADE, HeaderValue::from_static("foo"));
    Ok(resp)
}

async fn try_upgrade(connection: &'static str) -> Vec<HeaderValue> {
    let (client_io, server_io) = tokio::io::duplex(4096);
    tokio::spawn(
        hyper::server::conn::http1::Builder::new()
            .serve_connection(TokioIo::new(server_io), hyper::service::service_fn(upgrade))
            .with_upgrades(),
    );
    let (mut sender, conn) = hyper::client::conn::http1::handshake(TokioIo::new(client_io))
        .await
        .unwrap();
    tokio::spawn(conn.with_upgrades());
    let req = Request::builder()
        .uri("/")
        .header("Host", "example.com")
        .header(CONNECTION, connection)
        .header(UPGRADE, "foo")
        .body(String::new())
        .unwrap();
    let resp = sender.send_request(req).await.unwrap();
    assert_eq!(resp.status(), StatusCode::SWITCHING_PROTOCOLS);
    resp.headers().get_all(CONNECTION).iter().cloned().collect()
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
    for connection in ["Upgrade", "close, Upgrade"] {
        println!(
            "request Connection: {connection:?} -> response Connection: {:?}",
            try_upgrade(connection).await
        );
    }
}
Expected Behavior

request Connection: "Upgrade" -> response Connection: ["upgrade"]
request Connection: "close, Upgrade" -> response Connection: ["upgrade"]

Actual Behavior

request Connection: "Upgrade" -> response Connection: ["upgrade"]
request Connection: "close, Upgrade" -> response Connection: ["upgrade, close"]

Additional Context

No response

Langage dominant
Rust
Étoiles
16.4k
Forks
1.8k
Merge moyen
1 j 13 h
PR mergées (30 j)
12

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de hyperium/hyper

Toutes les issues de hyperium/hyper

Issues similaires

Plus d'issues Rust

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.