Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

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

Aperta
#4,244 4 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@akasakariko ci sta già lavorando.

Dal 27/10/2026.

  • #4248 di @akasakariko — aperta

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
62/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
rust
Ambito
networking

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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

Lingua principale
Rust
Stelle
16.4k
Fork
1.8k
Merge medio
1g 13h
PR unite (30g)
12

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di hyperium/hyper

Tutte le issue di hyperium/hyper

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.