Skip to content

net/http: sniffing for non-zero GET request body is broken #47568

Closed
@neild

Description

@neild

When making a request which usually lacks a response body (GET, HEAD, DELETE, etc.), if the Request.Body is non-nil, the content length is not set, and Transfer-Encoding: chunked is not set, we attempt to read one byte from the body before sending the request. If the read succeeds within 200ms and indicates a zero-length body, we set Request.Body = nil.

If the read takes more than 200ms, we set Transfer-Encoding: chunked and proceed.

See: https://go.googlesource.com/go/+/refs/heads/master/src/net/http/transfer.go#191

The latter path (when the probe does not complete within 200ms) is broken when the body is not zero-length.

In this path, we replace Request.Body with io.MultiReader(finishAsyncByteRead{t}, t.Body). finishAsyncByteRead.Read does not return io.EOF after reading the initial byte, so the io.MultiReader retries the read, which never completes.

https://go.googlesource.com/go/+/refs/heads/master/src/net/http/transfer.go#1066

The impact is that sending a request can hang when all of the following apply:

  • The request method is one of GET, HEAD, DELETE, OPTIONS, PROPFIND, or SEARCH.
  • The Request.Body is non-nil.
  • The content length is not set, or is set to -1.
  • Transfer-Encoding: chunked is not set.
  • The request body does not respond to a read within 200ms.

Thanks to @EdSchouten for identifying this problem in CL 328711.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions