aboutsummaryrefslogtreecommitdiff
path: root/src/net/http/client_test.go
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2021-08-05 19:26:21 -0700
committerDamien Neil <dneil@google.com>2021-09-02 17:00:30 +0000
commitacc2957bc9873ab7e65942045830a3dc0592eda2 (patch)
tree59e58c2ac80f487b9ef4cca1d622d7a2649bbe2e /src/net/http/client_test.go
parent2a463a22cee8ddbd4801acd2ef34eefa551a718a (diff)
downloadgo-acc2957bc9873ab7e65942045830a3dc0592eda2.tar.xz
net/http: fix hang in probing for a zero-length request body
Fix a hang that occurs when making a request and 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. In this case, we give up on probing for a zero-length body and send the request while the probe completes in the background. Fix a bug in the io.Reader wrapping the in-flight probe: It should return io.EOF after the probe completes, but does not. Fixes #47568. Change-Id: I7f9188c96e1210055df68424081af927006e4816 Reviewed-on: https://go-review.googlesource.com/c/go/+/340256 Trust: Damien Neil <dneil@google.com> Run-TryBot: Damien Neil <dneil@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Ingo Oeser <nightlyone@googlemail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/net/http/client_test.go')
-rw-r--r--src/net/http/client_test.go44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 01d605c351..05ed2268b5 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -2082,3 +2082,47 @@ func (b *issue40382Body) Close() error {
}
return nil
}
+
+func TestProbeZeroLengthBody(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ reqc := make(chan struct{})
+ cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) {
+ close(reqc)
+ if _, err := io.Copy(w, r.Body); err != nil {
+ t.Errorf("error copying request body: %v", err)
+ }
+ }))
+ defer cst.close()
+
+ bodyr, bodyw := io.Pipe()
+ var gotBody string
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ req, _ := NewRequest("GET", cst.ts.URL, bodyr)
+ res, err := cst.c.Do(req)
+ b, err := io.ReadAll(res.Body)
+ if err != nil {
+ t.Error(err)
+ }
+ gotBody = string(b)
+ }()
+
+ select {
+ case <-reqc:
+ // Request should be sent after trying to probe the request body for 200ms.
+ case <-time.After(60 * time.Second):
+ t.Errorf("request not sent after 60s")
+ }
+
+ // Write the request body and wait for the request to complete.
+ const content = "body"
+ bodyw.Write([]byte(content))
+ bodyw.Close()
+ wg.Wait()
+ if gotBody != content {
+ t.Fatalf("server got body %q, want %q", gotBody, content)
+ }
+}