Skip to content

Chunked HTTP/1.1 doesn't send the last zero-chunk when body is empty #3252

Closed
@XOR-op

Description

@XOR-op

Version
hyper 0.14.26, h2 0.3.19, http 0.2.9

Platform
Linux 5.15, Ubuntu 22.04

Description
In HTTP/1.1, when transfer-encoding: chunked is set, all the data should be sent at a format of chunk. However, in hyper, if the body part is empty, e.g. Body::empty() or Body::from_static(b""), hyper server doesn't send b"0\r\n\r\n" to the client, causing infitite wait on the client side. When the body contains some bytes, e.g. Body::from_static(b"0"), hyper will send a non-zero size chunk as well as a zero-size last chunk. According to pseudo code from RFC9112 7.1.3, zero size body should be allowed.

I expect hyper sends valid last chunk b"0\r\n\r\n" to the client when the body is empty. Manually sending it is impossible with public API so I have no workaround now.

Source code to reproduce the behavior:

async fn get_302() -> anyhow::Result<Response<Body>> {
    let resp_builder = http::response::Builder::new();
    let (mut parts, body) = resp_builder
        .status(302)
        .version(Version::HTTP_11)
        .header(header::LOCATION, "127.0.0.1:1234/ok")
        .header(header::TRANSFER_ENCODING, "chunked")
        .body(Body::empty())
        .unwrap().into_parts();
    Ok(Response::from_parts(parts, body))
}

async fn run_server() {
    let listener = TcpListener::bind("127.0.0.1:1234").await.unwrap();
    let service = service_fn(|req| {
        get_302()
    });
    while let (conn, _) = listener.accept().await.unwrap() {
        let _ = Http::new().http1_only(true).serve_connection(conn, service).await;
    }
}

#[tokio::main]
async fn main() {
    run_server().await
}

Metadata

Metadata

Assignees

Labels

C-bugCategory: bug. Something is wrong. This is bad!

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions