diff options
Diffstat (limited to 'libgo/go/net/http/serve_test.go')
-rw-r--r-- | libgo/go/net/http/serve_test.go | 672 |
1 files changed, 559 insertions, 113 deletions
diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index 13e5f283e4c..072da2552bc 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -156,6 +156,7 @@ func (ht handlerTest) rawResponse(req string) string { } func TestConsumingBodyOnNextConn(t *testing.T) { + t.Parallel() defer afterTest(t) conn := new(testConn) for i := 0; i < 2; i++ { @@ -237,6 +238,7 @@ var vtests = []struct { } func TestHostHandlers(t *testing.T) { + setParallel(t) defer afterTest(t) mux := NewServeMux() for _, h := range handlers { @@ -353,6 +355,7 @@ var serveMuxTests = []struct { } func TestServeMuxHandler(t *testing.T) { + setParallel(t) mux := NewServeMux() for _, e := range serveMuxRegister { mux.Handle(e.pattern, e.h) @@ -390,15 +393,16 @@ var serveMuxTests2 = []struct { // TestServeMuxHandlerRedirects tests that automatic redirects generated by // mux.Handler() shouldn't clear the request's query string. func TestServeMuxHandlerRedirects(t *testing.T) { + setParallel(t) mux := NewServeMux() for _, e := range serveMuxRegister { mux.Handle(e.pattern, e.h) } for _, tt := range serveMuxTests2 { - tries := 1 + tries := 1 // expect at most 1 redirection if redirOk is true. turl := tt.url - for tries > 0 { + for { u, e := url.Parse(turl) if e != nil { t.Fatal(e) @@ -432,6 +436,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) { // Tests for https://golang.org/issue/900 func TestMuxRedirectLeadingSlashes(t *testing.T) { + setParallel(t) paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"} for _, path := range paths { req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n"))) @@ -456,9 +461,6 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) { } func TestServerTimeouts(t *testing.T) { - if runtime.GOOS == "plan9" { - t.Skip("skipping test; see https://golang.org/issue/7237") - } setParallel(t) defer afterTest(t) reqNum := 0 @@ -479,11 +481,11 @@ func TestServerTimeouts(t *testing.T) { if err != nil { t.Fatalf("http Get #1: %v", err) } - got, _ := ioutil.ReadAll(r.Body) + got, err := ioutil.ReadAll(r.Body) expected := "req=1" - if string(got) != expected { - t.Errorf("Unexpected response for request #1; got %q; expected %q", - string(got), expected) + if string(got) != expected || err != nil { + t.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil", + string(got), err, expected) } // Slow client that should timeout. @@ -494,6 +496,7 @@ func TestServerTimeouts(t *testing.T) { } buf := make([]byte, 1) n, err := conn.Read(buf) + conn.Close() latency := time.Since(t1) if n != 0 || err != io.EOF { t.Errorf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF) @@ -505,14 +508,14 @@ func TestServerTimeouts(t *testing.T) { // Hit the HTTP server successfully again, verifying that the // previous slow connection didn't run our handler. (that we // get "req=2", not "req=3") - r, err = Get(ts.URL) + r, err = c.Get(ts.URL) if err != nil { t.Fatalf("http Get #2: %v", err) } - got, _ = ioutil.ReadAll(r.Body) + got, err = ioutil.ReadAll(r.Body) expected = "req=2" - if string(got) != expected { - t.Errorf("Get #2 got %q, want %q", string(got), expected) + if string(got) != expected || err != nil { + t.Errorf("Get #2 got %q, %v, want %q, nil", string(got), err, expected) } if !testing.Short() { @@ -532,13 +535,61 @@ func TestServerTimeouts(t *testing.T) { } } +// Test that the HTTP/2 server handles Server.WriteTimeout (Issue 18437) +func TestHTTP2WriteDeadlineExtendedOnNewRequest(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + setParallel(t) + defer afterTest(t) + ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {})) + ts.Config.WriteTimeout = 250 * time.Millisecond + ts.TLS = &tls.Config{NextProtos: []string{"h2"}} + ts.StartTLS() + defer ts.Close() + + tr := newTLSTransport(t, ts) + defer tr.CloseIdleConnections() + if err := ExportHttp2ConfigureTransport(tr); err != nil { + t.Fatal(err) + } + c := &Client{Transport: tr} + + for i := 1; i <= 3; i++ { + req, err := NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + + // fail test if no response after 1 second + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + req = req.WithContext(ctx) + + r, err := c.Do(req) + select { + case <-ctx.Done(): + if ctx.Err() == context.DeadlineExceeded { + t.Fatalf("http2 Get #%d response timed out", i) + } + default: + } + if err != nil { + t.Fatalf("http2 Get #%d: %v", i, err) + } + r.Body.Close() + if r.ProtoMajor != 2 { + t.Fatalf("http2 Get expected HTTP/2.0, got %q", r.Proto) + } + time.Sleep(ts.Config.WriteTimeout / 2) + } +} + // golang.org/issue/4741 -- setting only a write timeout that triggers // shouldn't cause a handler to block forever on reads (next HTTP // request) that will never happen. func TestOnlyWriteTimeout(t *testing.T) { - if runtime.GOOS == "plan9" { - t.Skip("skipping test; see https://golang.org/issue/7237") - } + setParallel(t) defer afterTest(t) var conn net.Conn var afterTimeoutErrc = make(chan error, 1) @@ -598,6 +649,7 @@ func (l trackLastConnListener) Accept() (c net.Conn, err error) { // TestIdentityResponse verifies that a handler can unset func TestIdentityResponse(t *testing.T) { + setParallel(t) defer afterTest(t) handler := HandlerFunc(func(rw ResponseWriter, req *Request) { rw.Header().Set("Content-Length", "3") @@ -619,13 +671,16 @@ func TestIdentityResponse(t *testing.T) { ts := httptest.NewServer(handler) defer ts.Close() + c := &Client{Transport: new(Transport)} + defer closeClient(c) + // Note: this relies on the assumption (which is true) that // Get sends HTTP/1.1 or greater requests. Otherwise the // server wouldn't have the choice to send back chunked // responses. for _, te := range []string{"", "identity"} { url := ts.URL + "/?te=" + te - res, err := Get(url) + res, err := c.Get(url) if err != nil { t.Fatalf("error with Get of %s: %v", url, err) } @@ -644,7 +699,7 @@ func TestIdentityResponse(t *testing.T) { // Verify that ErrContentLength is returned url := ts.URL + "/?overwrite=1" - res, err := Get(url) + res, err := c.Get(url) if err != nil { t.Fatalf("error with Get of %s: %v", url, err) } @@ -674,6 +729,7 @@ func TestIdentityResponse(t *testing.T) { } func testTCPConnectionCloses(t *testing.T, req string, h Handler) { + setParallel(t) defer afterTest(t) s := httptest.NewServer(h) defer s.Close() @@ -717,6 +773,7 @@ func testTCPConnectionCloses(t *testing.T, req string, h Handler) { } func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) { + setParallel(t) defer afterTest(t) ts := httptest.NewServer(handler) defer ts.Close() @@ -750,7 +807,7 @@ func TestServeHTTP10Close(t *testing.T) { // TestClientCanClose verifies that clients can also force a connection to close. func TestClientCanClose(t *testing.T) { - testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { + testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { // Nothing. })) } @@ -758,7 +815,7 @@ func TestClientCanClose(t *testing.T) { // TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close, // even for HTTP/1.1 requests. func TestHandlersCanSetConnectionClose11(t *testing.T) { - testTCPConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { + testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("Connection", "close") })) } @@ -796,6 +853,7 @@ func TestHTTP10KeepAlive304Response(t *testing.T) { // Issue 15703 func TestKeepAliveFinalChunkWithEOF(t *testing.T) { + setParallel(t) defer afterTest(t) cst := newClientServerTest(t, false /* h1 */, HandlerFunc(func(w ResponseWriter, r *Request) { w.(Flusher).Flush() // force chunked encoding @@ -828,6 +886,7 @@ func TestSetsRemoteAddr_h1(t *testing.T) { testSetsRemoteAddr(t, h1Mode) } func TestSetsRemoteAddr_h2(t *testing.T) { testSetsRemoteAddr(t, h2Mode) } func testSetsRemoteAddr(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { fmt.Fprintf(w, "%s", r.RemoteAddr) @@ -877,6 +936,7 @@ func (c *blockingRemoteAddrConn) RemoteAddr() net.Addr { // Issue 12943 func TestServerAllowsBlockingRemoteAddr(t *testing.T) { + setParallel(t) defer afterTest(t) ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { fmt.Fprintf(w, "RA:%s", r.RemoteAddr) @@ -948,7 +1008,9 @@ func TestServerAllowsBlockingRemoteAddr(t *testing.T) { t.Fatalf("response 1 addr = %q; want %q", g, e) } } + func TestIdentityResponseHeaders(t *testing.T) { + // Not parallel; changes log output. defer afterTest(t) log.SetOutput(ioutil.Discard) // is noisy otherwise defer log.SetOutput(os.Stderr) @@ -960,7 +1022,10 @@ func TestIdentityResponseHeaders(t *testing.T) { })) defer ts.Close() - res, err := Get(ts.URL) + c := &Client{Transport: new(Transport)} + defer closeClient(c) + + res, err := c.Get(ts.URL) if err != nil { t.Fatalf("Get error: %v", err) } @@ -983,6 +1048,7 @@ func TestHeadResponses_h1(t *testing.T) { testHeadResponses(t, h1Mode) } func TestHeadResponses_h2(t *testing.T) { testHeadResponses(t, h2Mode) } func testHeadResponses(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { _, err := w.Write([]byte("<html>")) @@ -1020,9 +1086,6 @@ func testHeadResponses(t *testing.T, h2 bool) { } func TestTLSHandshakeTimeout(t *testing.T) { - if runtime.GOOS == "plan9" { - t.Skip("skipping test; see https://golang.org/issue/7237") - } setParallel(t) defer afterTest(t) ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) @@ -1054,6 +1117,7 @@ func TestTLSHandshakeTimeout(t *testing.T) { } func TestTLSServer(t *testing.T) { + setParallel(t) defer afterTest(t) ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { if r.TLS != nil { @@ -1121,6 +1185,7 @@ func TestAutomaticHTTP2_Serve_H2TLSConfig(t *testing.T) { } func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) { + setParallel(t) defer afterTest(t) ln := newLocalListener(t) ln.Close() // immediately (not a defer!) @@ -1136,6 +1201,7 @@ func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) { } func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) { + setParallel(t) defer afterTest(t) ln := newLocalListener(t) ln.Close() // immediately (not a defer!) @@ -1177,6 +1243,7 @@ func TestAutomaticHTTP2_ListenAndServe_GetCertificate(t *testing.T) { } func testAutomaticHTTP2_ListenAndServe(t *testing.T, tlsConf *tls.Config) { + // Not parallel: uses global test hooks. defer afterTest(t) defer SetTestHookServerServe(nil) var ok bool @@ -1280,6 +1347,7 @@ var serverExpectTests = []serverExpectTest{ // correctly. // http2 test: TestServer_Response_Automatic100Continue func TestServerExpect(t *testing.T) { + setParallel(t) defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { // Note using r.FormValue("readbody") because for POST @@ -1373,6 +1441,7 @@ func TestServerExpect(t *testing.T) { // Under a ~256KB (maxPostHandlerReadBytes) threshold, the server // should consume client request bodies that a handler didn't read. func TestServerUnreadRequestBodyLittle(t *testing.T) { + setParallel(t) defer afterTest(t) conn := new(testConn) body := strings.Repeat("x", 100<<10) @@ -1413,6 +1482,7 @@ func TestServerUnreadRequestBodyLittle(t *testing.T) { // should ignore client request bodies that a handler didn't read // and close the connection. func TestServerUnreadRequestBodyLarge(t *testing.T) { + setParallel(t) if testing.Short() && testenv.Builder() == "" { t.Log("skipping in short mode") } @@ -1546,6 +1616,7 @@ var handlerBodyCloseTests = [...]handlerBodyCloseTest{ } func TestHandlerBodyClose(t *testing.T) { + setParallel(t) if testing.Short() && testenv.Builder() == "" { t.Skip("skipping in -short mode") } @@ -1625,6 +1696,7 @@ var testHandlerBodyConsumers = []testHandlerBodyConsumer{ } func TestRequestBodyReadErrorClosesConnection(t *testing.T) { + setParallel(t) defer afterTest(t) for _, handler := range testHandlerBodyConsumers { conn := new(testConn) @@ -1655,6 +1727,7 @@ func TestRequestBodyReadErrorClosesConnection(t *testing.T) { } func TestInvalidTrailerClosesConnection(t *testing.T) { + setParallel(t) defer afterTest(t) for _, handler := range testHandlerBodyConsumers { conn := new(testConn) @@ -1737,7 +1810,7 @@ restart: if !c.rd.IsZero() { // If the deadline falls in the middle of our sleep window, deduct // part of the sleep, then return a timeout. - if remaining := c.rd.Sub(time.Now()); remaining < cue { + if remaining := time.Until(c.rd); remaining < cue { c.script[0] = cue - remaining time.Sleep(remaining) return 0, syscall.ETIMEDOUT @@ -1823,6 +1896,7 @@ func TestRequestBodyTimeoutClosesConnection(t *testing.T) { func TestTimeoutHandler_h1(t *testing.T) { testTimeoutHandler(t, h1Mode) } func TestTimeoutHandler_h2(t *testing.T) { testTimeoutHandler(t, h2Mode) } func testTimeoutHandler(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) sendHi := make(chan bool, 1) writeErrors := make(chan error, 1) @@ -1876,6 +1950,7 @@ func testTimeoutHandler(t *testing.T, h2 bool) { // See issues 8209 and 8414. func TestTimeoutHandlerRace(t *testing.T) { + setParallel(t) defer afterTest(t) delayHi := HandlerFunc(func(w ResponseWriter, r *Request) { @@ -1892,6 +1967,9 @@ func TestTimeoutHandlerRace(t *testing.T) { ts := httptest.NewServer(TimeoutHandler(delayHi, 20*time.Millisecond, "")) defer ts.Close() + c := &Client{Transport: new(Transport)} + defer closeClient(c) + var wg sync.WaitGroup gate := make(chan bool, 10) n := 50 @@ -1905,7 +1983,7 @@ func TestTimeoutHandlerRace(t *testing.T) { go func() { defer wg.Done() defer func() { <-gate }() - res, err := Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50))) + res, err := c.Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50))) if err == nil { io.Copy(ioutil.Discard, res.Body) res.Body.Close() @@ -1917,6 +1995,7 @@ func TestTimeoutHandlerRace(t *testing.T) { // See issues 8209 and 8414. func TestTimeoutHandlerRaceHeader(t *testing.T) { + setParallel(t) defer afterTest(t) delay204 := HandlerFunc(func(w ResponseWriter, r *Request) { @@ -1932,13 +2011,15 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) { if testing.Short() { n = 10 } + c := &Client{Transport: new(Transport)} + defer closeClient(c) for i := 0; i < n; i++ { gate <- true wg.Add(1) go func() { defer wg.Done() defer func() { <-gate }() - res, err := Get(ts.URL) + res, err := c.Get(ts.URL) if err != nil { t.Error(err) return @@ -1952,6 +2033,7 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) { // Issue 9162 func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) { + setParallel(t) defer afterTest(t) sendHi := make(chan bool, 1) writeErrors := make(chan error, 1) @@ -2016,11 +2098,15 @@ func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) { timeout := 300 * time.Millisecond ts := httptest.NewServer(TimeoutHandler(handler, timeout, "")) defer ts.Close() + + c := &Client{Transport: new(Transport)} + defer closeClient(c) + // Issue was caused by the timeout handler starting the timer when // was created, not when the request. So wait for more than the timeout // to ensure that's not the case. time.Sleep(2 * timeout) - res, err := Get(ts.URL) + res, err := c.Get(ts.URL) if err != nil { t.Fatal(err) } @@ -2032,6 +2118,7 @@ func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) { // https://golang.org/issue/15948 func TestTimeoutHandlerEmptyResponse(t *testing.T) { + setParallel(t) defer afterTest(t) var handler HandlerFunc = func(w ResponseWriter, _ *Request) { // No response. @@ -2040,7 +2127,10 @@ func TestTimeoutHandlerEmptyResponse(t *testing.T) { ts := httptest.NewServer(TimeoutHandler(handler, timeout, "")) defer ts.Close() - res, err := Get(ts.URL) + c := &Client{Transport: new(Transport)} + defer closeClient(c) + + res, err := c.Get(ts.URL) if err != nil { t.Fatal(err) } @@ -2050,23 +2140,6 @@ func TestTimeoutHandlerEmptyResponse(t *testing.T) { } } -// Verifies we don't path.Clean() on the wrong parts in redirects. -func TestRedirectMunging(t *testing.T) { - req, _ := NewRequest("GET", "http://example.com/", nil) - - resp := httptest.NewRecorder() - Redirect(resp, req, "/foo?next=http://bar.com/", 302) - if g, e := resp.Header().Get("Location"), "/foo?next=http://bar.com/"; g != e { - t.Errorf("Location header was %q; want %q", g, e) - } - - resp = httptest.NewRecorder() - Redirect(resp, req, "http://localhost:8080/_ah/login?continue=http://localhost:8080/", 302) - if g, e := resp.Header().Get("Location"), "http://localhost:8080/_ah/login?continue=http://localhost:8080/"; g != e { - t.Errorf("Location header was %q; want %q", g, e) - } -} - func TestRedirectBadPath(t *testing.T) { // This used to crash. It's not valid input (bad path), but it // shouldn't crash. @@ -2085,7 +2158,7 @@ func TestRedirectBadPath(t *testing.T) { } // Test different URL formats and schemes -func TestRedirectURLFormat(t *testing.T) { +func TestRedirect(t *testing.T) { req, _ := NewRequest("GET", "http://example.com/qux/", nil) var tests = []struct { @@ -2108,6 +2181,14 @@ func TestRedirectURLFormat(t *testing.T) { {"../quux/foobar.com/baz", "/quux/foobar.com/baz"}, // incorrect number of slashes {"///foobar.com/baz", "/foobar.com/baz"}, + + // Verifies we don't path.Clean() on the wrong parts in redirects: + {"/foo?next=http://bar.com/", "/foo?next=http://bar.com/"}, + {"http://localhost:8080/_ah/login?continue=http://localhost:8080/", + "http://localhost:8080/_ah/login?continue=http://localhost:8080/"}, + + {"/фубар", "/%d1%84%d1%83%d0%b1%d0%b0%d1%80"}, + {"http://foo.com/фубар", "http://foo.com/%d1%84%d1%83%d0%b1%d0%b0%d1%80"}, } for _, tt := range tests { @@ -2133,6 +2214,7 @@ func TestZeroLengthPostAndResponse_h2(t *testing.T) { } func testZeroLengthPostAndResponse(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, r *Request) { all, err := ioutil.ReadAll(r.Body) @@ -2252,12 +2334,58 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) } } +type terrorWriter struct{ t *testing.T } + +func (w terrorWriter) Write(p []byte) (int, error) { + w.t.Errorf("%s", p) + return len(p), nil +} + +// Issue 16456: allow writing 0 bytes on hijacked conn to test hijack +// without any log spam. +func TestServerWriteHijackZeroBytes(t *testing.T) { + defer afterTest(t) + done := make(chan struct{}) + ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { + defer close(done) + w.(Flusher).Flush() + conn, _, err := w.(Hijacker).Hijack() + if err != nil { + t.Errorf("Hijack: %v", err) + return + } + defer conn.Close() + _, err = w.Write(nil) + if err != ErrHijacked { + t.Errorf("Write error = %v; want ErrHijacked", err) + } + })) + ts.Config.ErrorLog = log.New(terrorWriter{t}, "Unexpected write: ", 0) + ts.Start() + defer ts.Close() + + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + res, err := c.Get(ts.URL) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("timeout") + } +} + func TestServerNoDate_h1(t *testing.T) { testServerNoHeader(t, h1Mode, "Date") } func TestServerNoDate_h2(t *testing.T) { testServerNoHeader(t, h2Mode, "Date") } func TestServerNoContentType_h1(t *testing.T) { testServerNoHeader(t, h1Mode, "Content-Type") } func TestServerNoContentType_h2(t *testing.T) { testServerNoHeader(t, h2Mode, "Content-Type") } func testServerNoHeader(t *testing.T, h2 bool, header string) { + setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { w.Header()[header] = nil @@ -2275,6 +2403,7 @@ func testServerNoHeader(t *testing.T, h2 bool, header string) { } func TestStripPrefix(t *testing.T) { + setParallel(t) defer afterTest(t) h := HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("X-Path", r.URL.Path) @@ -2282,7 +2411,10 @@ func TestStripPrefix(t *testing.T) { ts := httptest.NewServer(StripPrefix("/foo", h)) defer ts.Close() - res, err := Get(ts.URL + "/foo/bar") + c := &Client{Transport: new(Transport)} + defer closeClient(c) + + res, err := c.Get(ts.URL + "/foo/bar") if err != nil { t.Fatal(err) } @@ -2304,10 +2436,11 @@ func TestStripPrefix(t *testing.T) { func TestRequestLimit_h1(t *testing.T) { testRequestLimit(t, h1Mode) } func TestRequestLimit_h2(t *testing.T) { testRequestLimit(t, h2Mode) } func testRequestLimit(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { t.Fatalf("didn't expect to get request in Handler") - })) + }), optQuietLog) defer cst.close() req, _ := NewRequest("GET", cst.ts.URL, nil) var bytesPerHeader = len("header12345: val12345\r\n") @@ -2350,6 +2483,7 @@ func (cr countReader) Read(p []byte) (n int, err error) { func TestRequestBodyLimit_h1(t *testing.T) { testRequestBodyLimit(t, h1Mode) } func TestRequestBodyLimit_h2(t *testing.T) { testRequestBodyLimit(t, h2Mode) } func testRequestBodyLimit(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) const limit = 1 << 20 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { @@ -2399,14 +2533,14 @@ func TestClientWriteShutdown(t *testing.T) { } err = conn.(*net.TCPConn).CloseWrite() if err != nil { - t.Fatalf("Dial: %v", err) + t.Fatalf("CloseWrite: %v", err) } donec := make(chan bool) go func() { defer close(donec) bs, err := ioutil.ReadAll(conn) if err != nil { - t.Fatalf("ReadAll: %v", err) + t.Errorf("ReadAll: %v", err) } got := string(bs) if got != "" { @@ -2445,6 +2579,7 @@ func TestServerBufferedChunking(t *testing.T) { // closing the TCP connection, causing the client to get a RST. // See https://golang.org/issue/3595 func TestServerGracefulClose(t *testing.T) { + setParallel(t) defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { Error(w, "bye", StatusUnauthorized) @@ -2557,7 +2692,8 @@ func TestCloseNotifier(t *testing.T) { go func() { _, err = fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n") if err != nil { - t.Fatal(err) + t.Error(err) + return } <-diec conn.Close() @@ -2599,7 +2735,8 @@ func TestCloseNotifierPipelined(t *testing.T) { const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n" _, err = io.WriteString(conn, req+req) // two requests if err != nil { - t.Fatal(err) + t.Error(err) + return } <-diec conn.Close() @@ -2707,6 +2844,7 @@ func TestHijackAfterCloseNotifier(t *testing.T) { } func TestHijackBeforeRequestBodyRead(t *testing.T) { + setParallel(t) defer afterTest(t) var requestBody = bytes.Repeat([]byte("a"), 1<<20) bodyOkay := make(chan bool, 1) @@ -3028,15 +3166,18 @@ func (l *errorListener) Addr() net.Addr { } func TestAcceptMaxFds(t *testing.T) { - log.SetOutput(ioutil.Discard) // is noisy otherwise - defer log.SetOutput(os.Stderr) + setParallel(t) ln := &errorListener{[]error{ &net.OpError{ Op: "accept", Err: syscall.EMFILE, }}} - err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {}))) + server := &Server{ + Handler: HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})), + ErrorLog: log.New(ioutil.Discard, "", 0), // noisy otherwise + } + err := server.Serve(ln) if err != io.EOF { t.Errorf("got error %v, want EOF", err) } @@ -3161,6 +3302,7 @@ func TestHTTP10ConnectionHeader(t *testing.T) { func TestServerReaderFromOrder_h1(t *testing.T) { testServerReaderFromOrder(t, h1Mode) } func TestServerReaderFromOrder_h2(t *testing.T) { testServerReaderFromOrder(t, h2Mode) } func testServerReaderFromOrder(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) pr, pw := io.Pipe() const size = 3 << 20 @@ -3265,6 +3407,7 @@ func TestTransportAndServerSharedBodyRace_h2(t *testing.T) { testTransportAndServerSharedBodyRace(t, h2Mode) } func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) const bodySize = 1 << 20 @@ -3453,6 +3596,7 @@ func TestAppendTime(t *testing.T) { } func TestServerConnState(t *testing.T) { + setParallel(t) defer afterTest(t) handler := map[string]func(w ResponseWriter, r *Request){ "/": func(w ResponseWriter, r *Request) { @@ -3500,14 +3644,39 @@ func TestServerConnState(t *testing.T) { } ts.Start() - mustGet(t, ts.URL+"/") - mustGet(t, ts.URL+"/close") + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + mustGet := func(url string, headers ...string) { + req, err := NewRequest("GET", url, nil) + if err != nil { + t.Fatal(err) + } + for len(headers) > 0 { + req.Header.Add(headers[0], headers[1]) + headers = headers[2:] + } + res, err := c.Do(req) + if err != nil { + t.Errorf("Error fetching %s: %v", url, err) + return + } + _, err = ioutil.ReadAll(res.Body) + defer res.Body.Close() + if err != nil { + t.Errorf("Error reading %s: %v", url, err) + } + } + + mustGet(ts.URL + "/") + mustGet(ts.URL + "/close") - mustGet(t, ts.URL+"/") - mustGet(t, ts.URL+"/", "Connection", "close") + mustGet(ts.URL + "/") + mustGet(ts.URL+"/", "Connection", "close") - mustGet(t, ts.URL+"/hijack") - mustGet(t, ts.URL+"/hijack-panic") + mustGet(ts.URL + "/hijack") + mustGet(ts.URL + "/hijack-panic") // New->Closed { @@ -3587,31 +3756,10 @@ func TestServerConnState(t *testing.T) { } mu.Lock() - t.Errorf("Unexpected events.\nGot log: %s\n Want: %s\n", logString(stateLog), logString(want)) + t.Errorf("Unexpected events.\nGot log:\n%s\n Want:\n%s\n", logString(stateLog), logString(want)) mu.Unlock() } -func mustGet(t *testing.T, url string, headers ...string) { - req, err := NewRequest("GET", url, nil) - if err != nil { - t.Fatal(err) - } - for len(headers) > 0 { - req.Header.Add(headers[0], headers[1]) - headers = headers[2:] - } - res, err := DefaultClient.Do(req) - if err != nil { - t.Errorf("Error fetching %s: %v", url, err) - return - } - _, err = ioutil.ReadAll(res.Body) - defer res.Body.Close() - if err != nil { - t.Errorf("Error reading %s: %v", url, err) - } -} - func TestServerKeepAlivesEnabled(t *testing.T) { defer afterTest(t) ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) @@ -3632,6 +3780,7 @@ func TestServerKeepAlivesEnabled(t *testing.T) { func TestServerEmptyBodyRace_h1(t *testing.T) { testServerEmptyBodyRace(t, h1Mode) } func TestServerEmptyBodyRace_h2(t *testing.T) { testServerEmptyBodyRace(t, h2Mode) } func testServerEmptyBodyRace(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) var n int32 cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, req *Request) { @@ -3695,6 +3844,7 @@ func (c *closeWriteTestConn) CloseWrite() error { } func TestCloseWrite(t *testing.T) { + setParallel(t) var srv Server var testConn closeWriteTestConn c := ExportServerNewConn(&srv, &testConn) @@ -3935,6 +4085,7 @@ Host: foo // If a Handler finishes and there's an unread request body, // verify the server try to do implicit read on it before replying. func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) { + setParallel(t) conn := &testConn{closec: make(chan bool)} conn.readBuf.Write([]byte(fmt.Sprintf( "POST / HTTP/1.1\r\n" + @@ -4033,7 +4184,11 @@ func TestServerValidatesHostHeader(t *testing.T) { io.WriteString(&conn.readBuf, methodTarget+tt.proto+"\r\n"+tt.host+"\r\n") ln := &oneConnListener{conn} - go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {})) + srv := Server{ + ErrorLog: quietLog, + Handler: HandlerFunc(func(ResponseWriter, *Request) {}), + } + go srv.Serve(ln) <-conn.closec res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil) if err != nil { @@ -4088,6 +4243,7 @@ func TestServerHandlersCanHandleH2PRI(t *testing.T) { // Test that we validate the valid bytes in HTTP/1 headers. // Issue 11207. func TestServerValidatesHeaders(t *testing.T) { + setParallel(t) tests := []struct { header string want int @@ -4097,9 +4253,10 @@ func TestServerValidatesHeaders(t *testing.T) { {"X-Foo: bar\r\n", 200}, {"Foo: a space\r\n", 200}, - {"A space: foo\r\n", 400}, // space in header - {"foo\xffbar: foo\r\n", 400}, // binary in header - {"foo\x00bar: foo\r\n", 400}, // binary in header + {"A space: foo\r\n", 400}, // space in header + {"foo\xffbar: foo\r\n", 400}, // binary in header + {"foo\x00bar: foo\r\n", 400}, // binary in header + {"Foo: " + strings.Repeat("x", 1<<21) + "\r\n", 431}, // header too large {"foo: foo foo\r\n", 200}, // LWS space is okay {"foo: foo\tfoo\r\n", 200}, // LWS tab is okay @@ -4112,7 +4269,11 @@ func TestServerValidatesHeaders(t *testing.T) { io.WriteString(&conn.readBuf, "GET / HTTP/1.1\r\nHost: foo\r\n"+tt.header+"\r\n") ln := &oneConnListener{conn} - go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {})) + srv := Server{ + ErrorLog: quietLog, + Handler: HandlerFunc(func(ResponseWriter, *Request) {}), + } + go srv.Serve(ln) <-conn.closec res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil) if err != nil { @@ -4132,6 +4293,7 @@ func TestServerRequestContextCancel_ServeHTTPDone_h2(t *testing.T) { testServerRequestContextCancel_ServeHTTPDone(t, h2Mode) } func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) ctxc := make(chan context.Context, 1) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { @@ -4157,13 +4319,12 @@ func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, h2 bool) { } } +// Tests that the Request.Context available to the Handler is canceled +// if the peer closes their TCP connection. This requires that the server +// is always blocked in a Read call so it notices the EOF from the client. +// See issues 15927 and 15224. func TestServerRequestContextCancel_ConnClose(t *testing.T) { - // Currently the context is not canceled when the connection - // is closed because we're not reading from the connection - // until after ServeHTTP for the previous handler is done. - // Until the server code is modified to always be in a read - // (Issue 15224), this test doesn't work yet. - t.Skip("TODO(bradfitz): this test doesn't yet work; golang.org/issue/15224") + setParallel(t) defer afterTest(t) inHandler := make(chan struct{}) handlerDone := make(chan struct{}) @@ -4192,7 +4353,7 @@ func TestServerRequestContextCancel_ConnClose(t *testing.T) { select { case <-handlerDone: - case <-time.After(3 * time.Second): + case <-time.After(4 * time.Second): t.Fatalf("timeout waiting to see ServeHTTP exit") } } @@ -4204,6 +4365,7 @@ func TestServerContext_ServerContextKey_h2(t *testing.T) { testServerContext_ServerContextKey(t, h2Mode) } func testServerContext_ServerContextKey(t *testing.T, h2 bool) { + setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { ctx := r.Context() @@ -4229,6 +4391,7 @@ func testServerContext_ServerContextKey(t *testing.T, h2 bool) { // https://golang.org/issue/15960 func TestHandlerSetTransferEncodingChunked(t *testing.T) { + setParallel(t) defer afterTest(t) ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("Transfer-Encoding", "chunked") @@ -4243,6 +4406,7 @@ func TestHandlerSetTransferEncodingChunked(t *testing.T) { // https://golang.org/issue/16063 func TestHandlerSetTransferEncodingGzip(t *testing.T) { + setParallel(t) defer afterTest(t) ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("Transfer-Encoding", "gzip") @@ -4416,13 +4580,19 @@ func BenchmarkClient(b *testing.B) { b.StopTimer() defer afterTest(b) - port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user - if port == "" { - port = "39207" - } var data = []byte("Hello world.\n") if server := os.Getenv("TEST_BENCH_SERVER"); server != "" { // Server process mode. + port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user + if port == "" { + port = "0" + } + ln, err := net.Listen("tcp", "localhost:"+port) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } + fmt.Println(ln.Addr().String()) HandleFunc("/", func(w ResponseWriter, r *Request) { r.ParseForm() if r.Form.Get("stop") != "" { @@ -4431,33 +4601,44 @@ func BenchmarkClient(b *testing.B) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Write(data) }) - log.Fatal(ListenAndServe("localhost:"+port, nil)) + var srv Server + log.Fatal(srv.Serve(ln)) } // Start server process. cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$") cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes") + cmd.Stderr = os.Stderr + stdout, err := cmd.StdoutPipe() + if err != nil { + b.Fatal(err) + } if err := cmd.Start(); err != nil { b.Fatalf("subprocess failed to start: %v", err) } defer cmd.Process.Kill() + + // Wait for the server in the child process to respond and tell us + // its listening address, once it's started listening: + timer := time.AfterFunc(10*time.Second, func() { + cmd.Process.Kill() + }) + defer timer.Stop() + bs := bufio.NewScanner(stdout) + if !bs.Scan() { + b.Fatalf("failed to read listening URL from child: %v", bs.Err()) + } + url := "http://" + strings.TrimSpace(bs.Text()) + "/" + timer.Stop() + if _, err := getNoBody(url); err != nil { + b.Fatalf("initial probe of child process failed: %v", err) + } + done := make(chan error) go func() { done <- cmd.Wait() }() - // Wait for the server process to respond. - url := "http://localhost:" + port + "/" - for i := 0; i < 100; i++ { - time.Sleep(100 * time.Millisecond) - if _, err := getNoBody(url); err == nil { - break - } - if i == 99 { - b.Fatalf("subprocess does not respond") - } - } - // Do b.N requests to the server. b.StartTimer() for i := 0; i < b.N; i++ { @@ -4719,6 +4900,7 @@ func BenchmarkCloseNotifier(b *testing.B) { // Verify this doesn't race (Issue 16505) func TestConcurrentServerServe(t *testing.T) { + setParallel(t) for i := 0; i < 100; i++ { ln1 := &oneConnListener{conn: nil} ln2 := &oneConnListener{conn: nil} @@ -4727,3 +4909,267 @@ func TestConcurrentServerServe(t *testing.T) { go func() { srv.Serve(ln2) }() } } + +func TestServerIdleTimeout(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + setParallel(t) + defer afterTest(t) + ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { + io.Copy(ioutil.Discard, r.Body) + io.WriteString(w, r.RemoteAddr) + })) + ts.Config.ReadHeaderTimeout = 1 * time.Second + ts.Config.IdleTimeout = 2 * time.Second + ts.Start() + defer ts.Close() + + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + get := func() string { + res, err := c.Get(ts.URL) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + return string(slurp) + } + + a1, a2 := get(), get() + if a1 != a2 { + t.Fatalf("did requests on different connections") + } + time.Sleep(3 * time.Second) + a3 := get() + if a2 == a3 { + t.Fatal("request three unexpectedly on same connection") + } + + // And test that ReadHeaderTimeout still works: + conn, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo.com\r\n")) + time.Sleep(2 * time.Second) + if _, err := io.CopyN(ioutil.Discard, conn, 1); err == nil { + t.Fatal("copy byte succeeded; want err") + } +} + +func get(t *testing.T, c *Client, url string) string { + res, err := c.Get(url) + if err != nil { + t.Fatal(err) + } + defer res.Body.Close() + slurp, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + return string(slurp) +} + +// Tests that calls to Server.SetKeepAlivesEnabled(false) closes any +// currently-open connections. +func TestServerSetKeepAlivesEnabledClosesConns(t *testing.T) { + setParallel(t) + defer afterTest(t) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + io.WriteString(w, r.RemoteAddr) + })) + defer ts.Close() + + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + get := func() string { return get(t, c, ts.URL) } + + a1, a2 := get(), get() + if a1 != a2 { + t.Fatal("expected first two requests on same connection") + } + var idle0 int + if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool { + idle0 = tr.IdleConnKeyCountForTesting() + return idle0 == 1 + }) { + t.Fatalf("idle count before SetKeepAlivesEnabled called = %v; want 1", idle0) + } + + ts.Config.SetKeepAlivesEnabled(false) + + var idle1 int + if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool { + idle1 = tr.IdleConnKeyCountForTesting() + return idle1 == 0 + }) { + t.Fatalf("idle count after SetKeepAlivesEnabled called = %v; want 0", idle1) + } + + a3 := get() + if a3 == a2 { + t.Fatal("expected third request on new connection") + } +} + +func TestServerShutdown_h1(t *testing.T) { testServerShutdown(t, h1Mode) } +func TestServerShutdown_h2(t *testing.T) { testServerShutdown(t, h2Mode) } + +func testServerShutdown(t *testing.T, h2 bool) { + setParallel(t) + defer afterTest(t) + var doShutdown func() // set later + var shutdownRes = make(chan error, 1) + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + go doShutdown() + // Shutdown is graceful, so it should not interrupt + // this in-flight response. Add a tiny sleep here to + // increase the odds of a failure if shutdown has + // bugs. + time.Sleep(20 * time.Millisecond) + io.WriteString(w, r.RemoteAddr) + })) + defer cst.close() + + doShutdown = func() { + shutdownRes <- cst.ts.Config.Shutdown(context.Background()) + } + get(t, cst.c, cst.ts.URL) // calls t.Fail on failure + + if err := <-shutdownRes; err != nil { + t.Fatalf("Shutdown: %v", err) + } + + res, err := cst.c.Get(cst.ts.URL) + if err == nil { + res.Body.Close() + t.Fatal("second request should fail. server should be shut down") + } +} + +// Issue 17878: tests that we can call Close twice. +func TestServerCloseDeadlock(t *testing.T) { + var s Server + s.Close() + s.Close() +} + +// Issue 17717: tests that Server.SetKeepAlivesEnabled is respected by +// both HTTP/1 and HTTP/2. +func TestServerKeepAlivesEnabled_h1(t *testing.T) { testServerKeepAlivesEnabled(t, h1Mode) } +func TestServerKeepAlivesEnabled_h2(t *testing.T) { testServerKeepAlivesEnabled(t, h2Mode) } +func testServerKeepAlivesEnabled(t *testing.T, h2 bool) { + setParallel(t) + defer afterTest(t) + cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { + fmt.Fprintf(w, "%v", r.RemoteAddr) + })) + defer cst.close() + srv := cst.ts.Config + srv.SetKeepAlivesEnabled(false) + a := cst.getURL(cst.ts.URL) + if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) { + t.Fatalf("test server has active conns") + } + b := cst.getURL(cst.ts.URL) + if a == b { + t.Errorf("got same connection between first and second requests") + } + if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) { + t.Fatalf("test server has active conns") + } +} + +// Issue 18447: test that the Server's ReadTimeout is stopped while +// the server's doing its 1-byte background read between requests, +// waiting for the connection to maybe close. +func TestServerCancelsReadTimeoutWhenIdle(t *testing.T) { + setParallel(t) + defer afterTest(t) + const timeout = 250 * time.Millisecond + ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { + select { + case <-time.After(2 * timeout): + fmt.Fprint(w, "ok") + case <-r.Context().Done(): + fmt.Fprint(w, r.Context().Err()) + } + })) + ts.Config.ReadTimeout = timeout + ts.Start() + defer ts.Close() + + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + res, err := c.Get(ts.URL) + if err != nil { + t.Fatal(err) + } + slurp, err := ioutil.ReadAll(res.Body) + res.Body.Close() + if err != nil { + t.Fatal(err) + } + if string(slurp) != "ok" { + t.Fatalf("Got: %q, want ok", slurp) + } +} + +// Issue 18535: test that the Server doesn't try to do a background +// read if it's already done one. +func TestServerDuplicateBackgroundRead(t *testing.T) { + setParallel(t) + defer afterTest(t) + + const goroutines = 5 + const requests = 2000 + + hts := httptest.NewServer(HandlerFunc(NotFound)) + defer hts.Close() + + reqBytes := []byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n") + + var wg sync.WaitGroup + for i := 0; i < goroutines; i++ { + wg.Add(1) + go func() { + defer wg.Done() + cn, err := net.Dial("tcp", hts.Listener.Addr().String()) + if err != nil { + t.Error(err) + return + } + defer cn.Close() + + wg.Add(1) + go func() { + defer wg.Done() + io.Copy(ioutil.Discard, cn) + }() + + for j := 0; j < requests; j++ { + if t.Failed() { + return + } + _, err := cn.Write(reqBytes) + if err != nil { + t.Error(err) + return + } + } + }() + } + wg.Wait() +} |