From dc0527ee7de3a067aa1c3a1c2120b5ecf16b0aac Mon Sep 17 00:00:00 2001 From: Andy Pan Date: Sun, 10 Mar 2024 23:08:31 +0800 Subject: [PATCH] net/http: add tests with zero and negative read/write timeouts Change-Id: I38ebd280c200b30692eb35640327034a5e898bd0 Reviewed-on: https://go-review.googlesource.com/c/go/+/570376 Reviewed-by: Damien Neil Reviewed-by: David Chase Auto-Submit: Damien Neil LUCI-TryBot-Result: Go LUCI --- src/net/http/serve_test.go | 68 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index 1012e44b68..8998f38367 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -792,6 +792,51 @@ func testServerReadTimeout(t *testing.T, mode testMode) { } } +func TestServerNoReadTimeout(t *testing.T) { run(t, testServerNoReadTimeout) } +func testServerNoReadTimeout(t *testing.T, mode testMode) { + reqBody := "Hello, Gophers!" + resBody := "Hi, Gophers!" + for _, timeout := range []time.Duration{0, -1} { + cst := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) { + ctl := NewResponseController(res) + ctl.EnableFullDuplex() + res.WriteHeader(StatusOK) + // Flush the headers before processing the request body + // to unblock the client from the RoundTrip. + if err := ctl.Flush(); err != nil { + t.Errorf("server flush response: %v", err) + return + } + got, err := io.ReadAll(req.Body) + if string(got) != reqBody || err != nil { + t.Errorf("server read request body: %v; got %q, want %q", err, got, reqBody) + } + res.Write([]byte(resBody)) + }), func(ts *httptest.Server) { + ts.Config.ReadTimeout = timeout + ts.Config.IdleTimeout = 10 * time.Millisecond + t.Logf("Server.Config.ReadTimeout = %d", timeout) + }) + + pr, pw := io.Pipe() + res, err := cst.c.Post(cst.ts.URL, "text/plain", pr) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + + // TODO(panjf2000): sleep is not so robust, maybe find a better way to test this? + time.Sleep(10 * time.Millisecond) // stall sending body to server to test server doesn't time out + pw.Write([]byte(reqBody)) + pw.Close() + + got, err := io.ReadAll(res.Body) + if string(got) != resBody || err != nil { + t.Errorf("client read response body: %v; got %v, want %q", err, got, resBody) + } + } +} + func TestServerWriteTimeout(t *testing.T) { run(t, testServerWriteTimeout) } func testServerWriteTimeout(t *testing.T, mode testMode) { for timeout := 5 * time.Millisecond; ; timeout *= 2 { @@ -857,6 +902,29 @@ func testServerWriteTimeout(t *testing.T, mode testMode) { } } +func TestServerNoWriteTimeout(t *testing.T) { run(t, testServerNoWriteTimeout) } +func testServerNoWriteTimeout(t *testing.T, mode testMode) { + for _, timeout := range []time.Duration{0, -1} { + cst := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) { + _, err := io.Copy(res, neverEnding('a')) + t.Logf("server write response: %v", err) + }), func(ts *httptest.Server) { + ts.Config.WriteTimeout = timeout + t.Logf("Server.Config.WriteTimeout = %d", timeout) + }) + + res, err := cst.c.Get(cst.ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + n, err := io.CopyN(io.Discard, res.Body, 1<<20) // 1MB should be sufficient to prove the point + if n != 1<<20 || err != nil { + t.Errorf("client read response body: %d, %v", n, err) + } + } +} + // Test that the HTTP/2 server handles Server.WriteTimeout (Issue 18437) func TestWriteDeadlineExtendedOnNewRequest(t *testing.T) { run(t, testWriteDeadlineExtendedOnNewRequest) -- 2.50.0