Skip to content

net/http: chunked reader rejects chunk extensions with BWS before the semicolon, which RFC 9112 §7.1.1 permits #82257

Open

Description

@zzwenb

What version of Go are you using?

go1.25.14 (linux/amd64, official golang:1.25-bookworm image)

Does this issue reproduce with the latest release?

Yes.

What did you do?

Sent a POST request with Transfer-Encoding: chunked where the chunk header is 5 ;x=y — a single bad-white-space (BWS) byte between the chunk size and the semicolon that starts the chunk extension:

import socket
payload = (b"POST /upload HTTP/1.1\r\nHost: t\r\nConnection: close\r\n"
           b"Transfer-Encoding: chunked\r\n\r\n"
           b"5 ;x=y\r\nhello\r\n0\r\n\r\n")
s = socket.create_connection(("127.0.0.1", 18080)); s.sendall(payload)
print(s.recv(4096))

against a minimal server that reads the full body and reports framing errors:

http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "body framing error: "+err.Error(), http.StatusBadRequest)
        return
    }
    fmt.Fprintf(w, "parsed-ok bytes=%d body=%q\n", len(body), body)
})

What did you expect to see?

RFC 9112 §7.1.1 defines the chunk extension grammar as

chunk-ext = *( BWS ";" BWS chunk-ext-name [ BWS "=" BWS chunk-ext-val ] )

so BWS is explicitly permitted before the semicolon as well as after it, and the request should be accepted (as 5;x=y and 5; x=y both are).

What did you see instead?

400 Bad Request with body body framing error: invalid byte in chunk length — the BWS byte is hit while still scanning the chunk-size token.

Note the asymmetry: 5; x=y (BWS after the semicolon) is accepted, while 5 ;x=y (BWS before it) is rejected, so BWS support is currently one-sided relative to RFC 9112 §7.1.1.

Context

  • RFC 7230 did not allow BWS here; RFC 9112 adopted the relaxation (this was also the subject of verified errata against RFC 7230).
  • The rejection propagates to stacks built on net/http: Caddy v2.11.7 returns 502 for the same request, while nginx 1.31.7, Apache httpd 2.4.69, and HAProxy 3.4.7 all accept it, so the same bytes produce different outcomes across a deployment chain.
  • Related: net/http: reject HTTP requests with CR/LF in chunk extension quoted-string #77285 tightened chunk-extension handling in the opposite direction (CR/LF in quoted strings). If rejecting BWS before the semicolon is intentional hardening, it would help to have that documented; otherwise this looks like a conformance gap with RFC 9112 §7.1.1.

Activity

  1. gopherbot commented on Oct 16, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/849946 mentions this issue: net/http/internal: allow whitespace before chunk extensions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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