Skip to content

Upload requests with Transfer-Encoding: chunked hang forever #49

Description

@maddie

Summary

The hand-written HTTP parser never chunk-decodes request bodies: BodyType::Chunked (src/http/request.rs) reads the raw stream in fixed 1024-byte read_exact blocks until EOF. With a finite payload the client keeps the connection open (keep-alive, no half-close), the final block never fills, and the server blocks forever instead of answering.

Impact

Any client that sends Transfer-Encoding: chunked stalls after its first payload. Concrete case: librespeed/speedtest-cli#122 — librespeed-cli v1.0.13+ uploads at 0.55 Mbps against librespeed-rs 1.4.0:

  • The Go client wraps the upload body in a counting io.TeeReader which hides its length, so it sends chunked.
  • Server log from a replica of this body handling: CHUNKED: read 1048837 raw bytes, then EOF/blocked — 1024×1024 payload + 261 bytes of chunk framing; 1048837 is not a multiple of 1024, so the last read_exact(1024) blocks waiting for 763 more bytes that never come.
  • Upload rate = one payload / default 15 s duration = 1 MiB / 15 s ≈ 0.55 Mbps.

Same stall applies to curl -H "Transfer-Encoding: chunked" --data-binary @file and any chunked uploader. Content-Length requests (BodyType::Fixed) work fine.

Suggested fix

Parse chunked encoding in the Chunked branch (RFC 9112 §7.1): read the chunk-size line, the chunk data, and the terminating CRLF per chunk; stop at a 0-size chunk and consume the trailer section. Tokio's BufReader (already in use) provides lines() and read_exact for this.

Client-side note

librespeed/speedtest-cli now sends Content-Length for its fixed-size uploads (librespeed/speedtest-cli#143) as a workaround, but fixing chunked handling here makes the server robust for all clients.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions