Skip to content

http.client hangs reading a 304 or 204 response that has Transfer-Encoding: chunked #157951

Description

@DrVelvetFog

Bug description:

HTTPResponse.read() blocks when a 304 (or 204) response carries Transfer-Encoding: chunked. With no timeout set it waits forever.

RFC 9112 §6.1 explicitly allows this header on a 304: "A server MAY send a Transfer-Encoding header field ... in a 304 (Not Modified) response to a GET request, neither of which includes a message body". So a compliant server can trigger it. requests and urllib3 go through http.client, so they hang the same way.

import http.client, socket, threading

srv = socket.create_server(("127.0.0.1", 0))

def serve():
    conn, _ = srv.accept()
    conn.recv(65536)
    conn.sendall(b"HTTP/1.1 304 Not Modified\r\n"
                 b"Transfer-Encoding: chunked\r\n\r\n")
    conn.recv(1)  # keep the connection open, as a keep-alive server would

threading.Thread(target=serve, daemon=True).start()

c = http.client.HTTPConnection(*srv.getsockname(), timeout=5)
c.request("GET", "/")
r = c.getresponse()
print(r.status)  # 304
print(r.read())  # expected b'', but blocks until the timeout (forever without one)

Cause: HTTPResponse.begin() sets self.length = 0 for 1xx, 204, 304 and HEAD, but leaves self.chunked = True. read() short-circuits for HEAD only, so for 204/304 it goes into _read_chunked() and waits for a chunk that never comes. HEAD hit the same problem in bpo-6312 (gh-50561) and got the HEAD-specific check in read(). The other bodiless statuses never did.

Suggested fix: set self.chunked = False alongside self.length = 0 in that block of begin(). I have a patch with a test and I'm happy to open the PR.

CPython versions tested on:

3.14, CPython main branch

Operating systems tested on:

macOS

Linked PRs

Activity

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

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions