1
0
mirror of https://github.com/golang/go synced 2024-11-23 09:20:05 -07:00

net/http: refactor tests to run most in HTTP/1 and HTTP/2 modes

Replace the ad-hoc approach to running tests in HTTP/1 and HTTP/2
modes with a 'run' function that executes a test in various modes.
By default, these modes are HTTP/1 and HTTP/2, but tests can
opt-in to HTTPS/1 as well.

The 'run' function also takes care of post-test cleanup (running the
afterTest function).

The 'run' function runs tests in parallel by default. Tests which
can't run in parallel (generally because they use global test hooks)
pass a testNotParallel option to disable parallelism.

Update clientServerTest to use t.Cleanup to clean up after itself,
rather than leaving this up to tests to handle.

Drop an unnecessary mutex in SetReadLoopBeforeNextReadHook.
Test hooks can't be set in parallel, and we want the race detector
to notify us if two simultaneous tests try to set a hook.

Fixes #56032

Change-Id: I16be64913c426fc93d84abc6ad85dbd3bc191224
Reviewed-on: https://go-review.googlesource.com/c/go/+/438137
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Damien Neil <dneil@google.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Damien Neil 2022-10-03 16:07:48 -07:00
parent 5ca0cd3f18
commit 747e1961e9
8 changed files with 1503 additions and 1819 deletions

View File

@ -67,11 +67,9 @@ func (w chanWriter) Write(p []byte) (n int, err error) {
return len(p), nil
}
func TestClient(t *testing.T) {
setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
func TestClient(t *testing.T) { run(t, testClient) }
func testClient(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, robotsTxtHandler).ts
c := ts.Client()
r, err := c.Get(ts.URL)
@ -87,14 +85,9 @@ func TestClient(t *testing.T) {
}
}
func TestClientHead_h1(t *testing.T) { testClientHead(t, h1Mode) }
func TestClientHead_h2(t *testing.T) { testClientHead(t, h2Mode) }
func testClientHead(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, robotsTxtHandler)
defer cst.close()
func TestClientHead(t *testing.T) { run(t, testClientHead) }
func testClientHead(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, robotsTxtHandler)
r, err := cst.c.Head(cst.ts.URL)
if err != nil {
t.Fatal(err)
@ -200,11 +193,10 @@ func TestPostFormRequestFormat(t *testing.T) {
}
}
func TestClientRedirects(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestClientRedirects(t *testing.T) { run(t, testClientRedirects) }
func testClientRedirects(t *testing.T, mode testMode) {
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts = newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
n, _ := strconv.Atoi(r.FormValue("n"))
// Test Referer header. (7 is arbitrary position to test at)
if n == 7 {
@ -217,8 +209,7 @@ func TestClientRedirects(t *testing.T) {
return
}
fmt.Fprintf(w, "n=%d", n)
}))
defer ts.Close()
})).ts
c := ts.Client()
_, err := c.Get(ts.URL)
@ -299,13 +290,11 @@ func TestClientRedirects(t *testing.T) {
}
// Tests that Client redirects' contexts are derived from the original request's context.
func TestClientRedirectContext(t *testing.T) {
setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
func TestClientRedirectsContext(t *testing.T) { run(t, testClientRedirectsContext) }
func testClientRedirectsContext(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
Redirect(w, r, "/", StatusTemporaryRedirect)
}))
defer ts.Close()
})).ts
ctx, cancel := context.WithCancel(context.Background())
c := ts.Client()
@ -373,7 +362,9 @@ func TestPostRedirects(t *testing.T) {
`POST /?code=404 "c404"`,
}
want := strings.Join(wantSegments, "\n")
testRedirectsByMethod(t, "POST", postRedirectTests, want)
run(t, func(t *testing.T, mode testMode) {
testRedirectsByMethod(t, mode, "POST", postRedirectTests, want)
})
}
func TestDeleteRedirects(t *testing.T) {
@ -410,17 +401,18 @@ func TestDeleteRedirects(t *testing.T) {
`DELETE /?code=404 "c404"`,
}
want := strings.Join(wantSegments, "\n")
testRedirectsByMethod(t, "DELETE", deleteRedirectTests, want)
run(t, func(t *testing.T, mode testMode) {
testRedirectsByMethod(t, mode, "DELETE", deleteRedirectTests, want)
})
}
func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, want string) {
defer afterTest(t)
func testRedirectsByMethod(t *testing.T, mode testMode, method string, table []redirectTest, want string) {
var log struct {
sync.Mutex
bytes.Buffer
}
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts = newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
log.Lock()
slurp, _ := io.ReadAll(r.Body)
fmt.Fprintf(&log.Buffer, "%s %s %q", r.Method, r.RequestURI, slurp)
@ -445,8 +437,7 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa
}
w.WriteHeader(code)
}
}))
defer ts.Close()
})).ts
c := ts.Client()
for _, tt := range table {
@ -491,12 +482,11 @@ func removeCommonLines(a, b string) (asuffix, bsuffix string, commonLines int) {
}
}
func TestClientRedirectUseResponse(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestClientRedirectUseResponse(t *testing.T) { run(t, testClientRedirectUseResponse) }
func testClientRedirectUseResponse(t *testing.T, mode testMode) {
const body = "Hello, world."
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts = newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
if strings.Contains(r.URL.Path, "/other") {
io.WriteString(w, "wrong body")
} else {
@ -504,8 +494,7 @@ func TestClientRedirectUseResponse(t *testing.T) {
w.WriteHeader(StatusFound)
io.WriteString(w, body)
}
}))
defer ts.Close()
})).ts
c := ts.Client()
c.CheckRedirect = func(req *Request, via []*Request) error {
@ -533,18 +522,16 @@ func TestClientRedirectUseResponse(t *testing.T) {
// Issues 17773 and 49281: don't follow a 3xx if the response doesn't
// have a Location header.
func TestClientRedirectNoLocation(t *testing.T) {
func TestClientRedirectNoLocation(t *testing.T) { run(t, testClientRedirectNoLocation) }
func testClientRedirectNoLocation(t *testing.T, mode testMode) {
for _, code := range []int{301, 308} {
t.Run(fmt.Sprint(code), func(t *testing.T) {
setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Foo", "Bar")
w.WriteHeader(code)
}))
defer ts.Close()
c := ts.Client()
res, err := c.Get(ts.URL)
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
}
@ -560,15 +547,13 @@ func TestClientRedirectNoLocation(t *testing.T) {
}
// Don't follow a 307/308 if we can't resent the request body.
func TestClientRedirect308NoGetBody(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestClientRedirect308NoGetBody(t *testing.T) { run(t, testClientRedirect308NoGetBody) }
func testClientRedirect308NoGetBody(t *testing.T, mode testMode) {
const fakeURL = "https://localhost:1234/" // won't be hit
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Location", fakeURL)
w.WriteHeader(308)
}))
defer ts.Close()
})).ts
req, err := NewRequest("POST", ts.URL, strings.NewReader("some body"))
if err != nil {
t.Fatal(err)
@ -659,12 +644,10 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie {
return j.perURL[u.Host]
}
func TestRedirectCookiesJar(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestRedirectCookiesJar(t *testing.T) { run(t, testRedirectCookiesJar) }
func testRedirectCookiesJar(t *testing.T, mode testMode) {
var ts *httptest.Server
ts = httptest.NewServer(echoCookiesRedirectHandler)
defer ts.Close()
ts = newClientServerTest(t, mode, echoCookiesRedirectHandler).ts
c := ts.Client()
c.Jar = new(TestJar)
u, _ := url.Parse(ts.URL)
@ -696,9 +679,9 @@ func matchReturnedCookies(t *testing.T, expected, given []*Cookie) {
}
}
func TestJarCalls(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
func TestJarCalls(t *testing.T) { run(t, testJarCalls, []testMode{http1Mode}) }
func testJarCalls(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
pathSuffix := r.RequestURI[1:]
if r.RequestURI == "/nosetcookie" {
return // don't set cookies for this path
@ -707,8 +690,7 @@ func TestJarCalls(t *testing.T) {
if r.RequestURI == "/" {
Redirect(w, r, "http://secondhost.fake/secondpath", 302)
}
}))
defer ts.Close()
})).ts
jar := new(RecordingJar)
c := ts.Client()
c.Jar = jar
@ -757,20 +739,16 @@ func (j *RecordingJar) logf(format string, args ...any) {
fmt.Fprintf(&j.log, format, args...)
}
func TestStreamingGet_h1(t *testing.T) { testStreamingGet(t, h1Mode) }
func TestStreamingGet_h2(t *testing.T) { testStreamingGet(t, h2Mode) }
func testStreamingGet(t *testing.T, h2 bool) {
defer afterTest(t)
func TestStreamingGet(t *testing.T) { run(t, testStreamingGet) }
func testStreamingGet(t *testing.T, mode testMode) {
say := make(chan string)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.(Flusher).Flush()
for str := range say {
w.Write([]byte(str))
w.(Flusher).Flush()
}
}))
defer cst.close()
c := cst.c
res, err := c.Get(cst.ts.URL)
@ -811,11 +789,10 @@ func (c *writeCountingConn) Write(p []byte) (int, error) {
// TestClientWrites verifies that client requests are buffered and we
// don't send a TCP packet per line of the http request + body.
func TestClientWrites(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
defer ts.Close()
func TestClientWrites(t *testing.T) { run(t, testClientWrites, []testMode{http1Mode}) }
func testClientWrites(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
})).ts
writes := 0
dialer := func(netz string, addr string) (net.Conn, error) {
@ -847,11 +824,12 @@ func TestClientWrites(t *testing.T) {
}
func TestClientInsecureTransport(t *testing.T) {
setParallel(t)
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
run(t, testClientInsecureTransport, []testMode{https1Mode, http2Mode})
}
func testClientInsecureTransport(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
}))
})).ts
errc := make(chanWriter, 10) // but only expecting 1
ts.Config.ErrorLog = log.New(errc, "", 0)
defer ts.Close()
@ -898,15 +876,15 @@ func TestClientErrorWithRequestURI(t *testing.T) {
}
func TestClientWithCorrectTLSServerName(t *testing.T) {
defer afterTest(t)
run(t, testClientWithCorrectTLSServerName, []testMode{https1Mode, http2Mode})
}
func testClientWithCorrectTLSServerName(t *testing.T, mode testMode) {
const serverName = "example.com"
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS.ServerName != serverName {
t.Errorf("expected client to set ServerName %q, got: %q", serverName, r.TLS.ServerName)
}
}))
defer ts.Close()
})).ts
c := ts.Client()
c.Transport.(*Transport).TLSClientConfig.ServerName = serverName
@ -916,9 +894,10 @@ func TestClientWithCorrectTLSServerName(t *testing.T) {
}
func TestClientWithIncorrectTLSServerName(t *testing.T) {
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
run(t, testClientWithIncorrectTLSServerName, []testMode{https1Mode, http2Mode})
}
func testClientWithIncorrectTLSServerName(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {})).ts
errc := make(chanWriter, 10) // but only expecting 1
ts.Config.ErrorLog = log.New(errc, "", 0)
@ -951,11 +930,12 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
//
// The httptest.Server has a cert with "example.com" as its name.
func TestTransportUsesTLSConfigServerName(t *testing.T) {
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
run(t, testTransportUsesTLSConfigServerName, []testMode{https1Mode, http2Mode})
}
func testTransportUsesTLSConfigServerName(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
}))
defer ts.Close()
})).ts
c := ts.Client()
tr := c.Transport.(*Transport)
@ -971,11 +951,12 @@ func TestTransportUsesTLSConfigServerName(t *testing.T) {
}
func TestResponseSetsTLSConnectionState(t *testing.T) {
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
run(t, testResponseSetsTLSConnectionState, []testMode{https1Mode})
}
func testResponseSetsTLSConnectionState(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
}))
defer ts.Close()
})).ts
c := ts.Client()
tr := c.Transport.(*Transport)
@ -1001,10 +982,11 @@ func TestResponseSetsTLSConnectionState(t *testing.T) {
// to determine that the server is speaking HTTP.
// See golang.org/issue/11111.
func TestHTTPSClientDetectsHTTPServer(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
run(t, testHTTPSClientDetectsHTTPServer, []testMode{http1Mode})
}
func testHTTPSClientDetectsHTTPServer(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {})).ts
ts.Config.ErrorLog = quietLog
defer ts.Close()
_, err := Get(strings.Replace(ts.URL, "http", "https", 1))
if got := err.Error(); !strings.Contains(got, "HTTP response to HTTPS client") {
@ -1013,22 +995,13 @@ func TestHTTPSClientDetectsHTTPServer(t *testing.T) {
}
// Verify Response.ContentLength is populated. https://golang.org/issue/4126
func TestClientHeadContentLength_h1(t *testing.T) {
testClientHeadContentLength(t, h1Mode)
}
func TestClientHeadContentLength_h2(t *testing.T) {
testClientHeadContentLength(t, h2Mode)
}
func testClientHeadContentLength(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestClientHeadContentLength(t *testing.T) { run(t, testClientHeadContentLength) }
func testClientHeadContentLength(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
if v := r.FormValue("cl"); v != "" {
w.Header().Set("Content-Length", v)
}
}))
defer cst.close()
tests := []struct {
suffix string
want int64
@ -1056,11 +1029,10 @@ func testClientHeadContentLength(t *testing.T, h2 bool) {
}
}
func TestEmptyPasswordAuth(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestEmptyPasswordAuth(t *testing.T) { run(t, testEmptyPasswordAuth) }
func testEmptyPasswordAuth(t *testing.T, mode testMode) {
gopher := "gopher"
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
auth := r.Header.Get("Authorization")
if strings.HasPrefix(auth, "Basic ") {
encoded := auth[6:]
@ -1076,7 +1048,7 @@ func TestEmptyPasswordAuth(t *testing.T) {
} else {
t.Errorf("Invalid auth %q", auth)
}
}))
})).ts
defer ts.Close()
req, err := NewRequest("GET", ts.URL, nil)
if err != nil {
@ -1205,19 +1177,14 @@ func TestStripPasswordFromError(t *testing.T) {
}
}
func TestClientTimeout_h1(t *testing.T) { testClientTimeout(t, h1Mode) }
func TestClientTimeout_h2(t *testing.T) { testClientTimeout(t, h2Mode) }
func testClientTimeout(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
func TestClientTimeout(t *testing.T) { run(t, testClientTimeout) }
func testClientTimeout(t *testing.T, mode testMode) {
var (
mu sync.Mutex
nonce string // a unique per-request string
sawSlowNonce bool // true if the handler saw /slow?nonce=<nonce>
)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
_ = r.ParseForm()
if r.URL.Path == "/" {
Redirect(w, r, "/slow?nonce="+r.Form.Get("nonce"), StatusFound)
@ -1238,7 +1205,6 @@ func testClientTimeout(t *testing.T, h2 bool) {
return
}
}))
defer cst.close()
// Try to trigger a timeout after reading part of the response body.
// The initial timeout is emprically usually long enough on a decently fast
@ -1308,18 +1274,13 @@ func testClientTimeout(t *testing.T, h2 bool) {
}
}
func TestClientTimeout_Headers_h1(t *testing.T) { testClientTimeout_Headers(t, h1Mode) }
func TestClientTimeout_Headers_h2(t *testing.T) { testClientTimeout_Headers(t, h2Mode) }
// Client.Timeout firing before getting to the body
func testClientTimeout_Headers(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
func TestClientTimeout_Headers(t *testing.T) { run(t, testClientTimeout_Headers) }
func testClientTimeout_Headers(t *testing.T, mode testMode) {
donec := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
<-donec
}), optQuietLog)
defer cst.close()
// Note that we use a channel send here and not a close.
// The race detector doesn't know that we're waiting for a timeout
// and thinks that the waitgroup inside httptest.Server is added to concurrently
@ -1355,18 +1316,15 @@ func testClientTimeout_Headers(t *testing.T, h2 bool) {
// Issue 16094: if Client.Timeout is set but not hit, a Timeout error shouldn't be
// returned.
func TestClientTimeoutCancel(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestClientTimeoutCancel(t *testing.T) { run(t, testClientTimeoutCancel) }
func testClientTimeoutCancel(t *testing.T, mode testMode) {
testDone := make(chan struct{})
ctx, cancel := context.WithCancel(context.Background())
cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.(Flusher).Flush()
<-testDone
}))
defer cst.close()
defer close(testDone)
cst.c.Timeout = 1 * time.Hour
@ -1383,18 +1341,12 @@ func TestClientTimeoutCancel(t *testing.T) {
}
}
func TestClientTimeoutDoesNotExpire_h1(t *testing.T) { testClientTimeoutDoesNotExpire(t, h1Mode) }
func TestClientTimeoutDoesNotExpire_h2(t *testing.T) { testClientTimeoutDoesNotExpire(t, h2Mode) }
// Issue 49366: if Client.Timeout is set but not hit, no error should be returned.
func testClientTimeoutDoesNotExpire(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestClientTimeoutDoesNotExpire(t *testing.T) { run(t, testClientTimeoutDoesNotExpire) }
func testClientTimeoutDoesNotExpire(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("body"))
}))
defer cst.close()
cst.c.Timeout = 1 * time.Hour
req, _ := NewRequest("GET", cst.ts.URL, nil)
@ -1410,19 +1362,15 @@ func testClientTimeoutDoesNotExpire(t *testing.T, h2 bool) {
}
}
func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) }
func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) }
func testClientRedirectEatsBody(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
func TestClientRedirectEatsBody_h1(t *testing.T) { run(t, testClientRedirectEatsBody) }
func testClientRedirectEatsBody(t *testing.T, mode testMode) {
saw := make(chan string, 2)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
saw <- r.RemoteAddr
if r.URL.Path == "/" {
Redirect(w, r, "/foo", StatusFound) // which includes a body
}
}))
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
@ -1522,13 +1470,14 @@ func TestClientRedirectResponseWithoutRequest(t *testing.T) {
}
// Issue 4800: copy (some) headers when Client follows a redirect.
func TestClientCopyHeadersOnRedirect(t *testing.T) {
func TestClientCopyHeadersOnRedirect(t *testing.T) { run(t, testClientCopyHeadersOnRedirect) }
func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) {
const (
ua = "some-agent/1.2"
xfoo = "foo-val"
)
var ts2URL string
ts1 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts1 := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
want := Header{
"User-Agent": []string{ua},
"X-Foo": []string{xfoo},
@ -1543,12 +1492,10 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) {
} else {
w.Header().Set("Result", "ok")
}
}))
defer ts1.Close()
ts2 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
})).ts
ts2 := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
Redirect(w, r, ts1.URL, StatusFound)
}))
defer ts2.Close()
})).ts
ts2URL = ts2.URL
c := ts1.Client()
@ -1583,22 +1530,24 @@ func TestClientCopyHeadersOnRedirect(t *testing.T) {
}
// Issue 22233: copy host when Client follows a relative redirect.
func TestClientCopyHostOnRedirect(t *testing.T) {
func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) }
func testClientCopyHostOnRedirect(t *testing.T, mode testMode) {
// Virtual hostname: should not receive any request.
virtual := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
virtual := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
t.Errorf("Virtual host received request %v", r.URL)
w.WriteHeader(403)
io.WriteString(w, "should not see this response")
}))
})).ts
defer virtual.Close()
virtualHost := strings.TrimPrefix(virtual.URL, "http://")
virtualHost = strings.TrimPrefix(virtualHost, "https://")
t.Logf("Virtual host is %v", virtualHost)
// Actual hostname: should not receive any request.
const wantBody = "response body"
var tsURL string
var tsHost string
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
switch r.URL.Path {
case "/":
// Relative redirect.
@ -1630,10 +1579,10 @@ func TestClientCopyHostOnRedirect(t *testing.T) {
t.Errorf("Serving unexpected path %q", r.URL.Path)
w.WriteHeader(404)
}
}))
defer ts.Close()
})).ts
tsURL = ts.URL
tsHost = strings.TrimPrefix(ts.URL, "http://")
tsHost = strings.TrimPrefix(tsHost, "https://")
t.Logf("Server host is %v", tsHost)
c := ts.Client()
@ -1653,7 +1602,8 @@ func TestClientCopyHostOnRedirect(t *testing.T) {
}
// Issue 17494: cookies should be altered when Client follows redirects.
func TestClientAltersCookiesOnRedirect(t *testing.T) {
func TestClientAltersCookiesOnRedirect(t *testing.T) { run(t, testClientAltersCookiesOnRedirect) }
func testClientAltersCookiesOnRedirect(t *testing.T, mode testMode) {
cookieMap := func(cs []*Cookie) map[string][]string {
m := make(map[string][]string)
for _, c := range cs {
@ -1662,7 +1612,7 @@ func TestClientAltersCookiesOnRedirect(t *testing.T) {
return m
}
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
var want map[string][]string
got := cookieMap(r.Cookies())
@ -1717,8 +1667,7 @@ func TestClientAltersCookiesOnRedirect(t *testing.T) {
if !reflect.DeepEqual(got, want) {
t.Errorf("redirect %s, Cookie = %v, want %v", c.Value, got, want)
}
}))
defer ts.Close()
})).ts
jar, _ := cookiejar.New(nil)
c := ts.Client()
@ -1790,10 +1739,8 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
}
}
func TestClientRedirectTypes(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestClientRedirectTypes(t *testing.T) { run(t, testClientRedirectTypes) }
func testClientRedirectTypes(t *testing.T, mode testMode) {
tests := [...]struct {
method string
serverStatus int
@ -1838,11 +1785,10 @@ func TestClientRedirectTypes(t *testing.T) {
handlerc := make(chan HandlerFunc, 1)
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
h := <-handlerc
h(rw, req)
}))
defer ts.Close()
})).ts
c := ts.Client()
for i, tt := range tests {
@ -1898,18 +1844,16 @@ func (b issue18239Body) Close() error {
// Issue 18239: make sure the Transport doesn't retry requests with bodies
// if Request.GetBody is not defined.
func TestTransportBodyReadError(t *testing.T) {
setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
func TestTransportBodyReadError(t *testing.T) { run(t, testTransportBodyReadError) }
func testTransportBodyReadError(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
if r.URL.Path == "/ping" {
return
}
buf := make([]byte, 1)
n, err := r.Body.Read(buf)
w.Header().Set("X-Body-Read", fmt.Sprintf("%v, %v", n, err))
}))
defer ts.Close()
})).ts
c := ts.Client()
tr := c.Transport.(*Transport)
@ -1993,22 +1937,13 @@ func TestClientPropagatesTimeoutToContext(t *testing.T) {
c.Get("https://example.tld/")
}
func TestClientDoCanceledVsTimeout_h1(t *testing.T) {
testClientDoCanceledVsTimeout(t, h1Mode)
}
func TestClientDoCanceledVsTimeout_h2(t *testing.T) {
testClientDoCanceledVsTimeout(t, h2Mode)
}
// Issue 33545: lock-in the behavior promised by Client.Do's
// docs about request cancellation vs timing out.
func testClientDoCanceledVsTimeout(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestClientDoCanceledVsTimeout(t *testing.T) { run(t, testClientDoCanceledVsTimeout) }
func testClientDoCanceledVsTimeout(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello, World!"))
}))
defer cst.close()
cases := []string{"timeout", "canceled"}
@ -2084,13 +2019,11 @@ func TestClientPopulatesNilResponseBody(t *testing.T) {
}
// Issue 40382: Client calls Close multiple times on Request.Body.
func TestClientCallsCloseOnlyOnce(t *testing.T) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestClientCallsCloseOnlyOnce(t *testing.T) { run(t, testClientCallsCloseOnlyOnce) }
func testClientCallsCloseOnlyOnce(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusNoContent)
}))
defer cst.close()
// Issue occurred non-deterministically: needed to occur after a successful
// write (into TCP buffer) but before end of body.
@ -2140,17 +2073,15 @@ func (b *issue40382Body) Close() error {
return nil
}
func TestProbeZeroLengthBody(t *testing.T) {
setParallel(t)
defer afterTest(t)
func TestProbeZeroLengthBody(t *testing.T) { run(t, testProbeZeroLengthBody) }
func testProbeZeroLengthBody(t *testing.T, mode testMode) {
reqc := make(chan struct{})
cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, 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

View File

@ -35,8 +35,65 @@ import (
"time"
)
type testMode string
const (
http1Mode = testMode("h1") // HTTP/1.1
https1Mode = testMode("https1") // HTTPS/1.1
http2Mode = testMode("h2") // HTTP/2
)
type testNotParallelOpt struct{}
var (
testNotParallel = testNotParallelOpt{}
)
type TBRun[T any] interface {
testing.TB
Run(string, func(T)) bool
}
// run runs a client/server test in a variety of test configurations.
//
// Tests execute in HTTP/1.1 and HTTP/2 modes by default.
// To run in a different set of configurations, pass a []testMode option.
//
// Tests call t.Parallel() by default.
// To disable parallel execution, pass the testNotParallel option.
func run[T TBRun[T]](t T, f func(t T, mode testMode), opts ...any) {
t.Helper()
modes := []testMode{http1Mode, http2Mode}
parallel := true
for _, opt := range opts {
switch opt := opt.(type) {
case []testMode:
modes = opt
case testNotParallelOpt:
parallel = false
default:
t.Fatalf("unknown option type %T", opt)
}
}
if t, ok := any(t).(*testing.T); ok && parallel {
setParallel(t)
}
for _, mode := range modes {
t.Run(string(mode), func(t T) {
t.Helper()
if t, ok := any(t).(*testing.T); ok && parallel {
setParallel(t)
}
t.Cleanup(func() {
afterTest(t)
})
f(t, mode)
})
}
}
type clientServerTest struct {
t *testing.T
t testing.TB
h2 bool
h Handler
ts *httptest.Server
@ -69,11 +126,6 @@ func (t *clientServerTest) scheme() string {
return "http"
}
const (
h1Mode = false
h2Mode = true
)
var optQuietLog = func(ts *httptest.Server) {
ts.Config.ErrorLog = quietLog
}
@ -84,23 +136,33 @@ func optWithServerLog(lg *log.Logger) func(*httptest.Server) {
}
}
func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...any) *clientServerTest {
if h2 {
// newClientServerTest creates and starts an httptest.Server.
//
// The mode parameter selects the implementation to test:
// HTTP/1, HTTP/2, etc. Tests using newClientServerTest should use
// the 'run' function, which will start a subtests for each tested mode.
//
// The vararg opts parameter can include functions to configure the
// test server or transport.
//
// func(*httptest.Server) // run before starting the server
// func(*http.Transport)
func newClientServerTest(t testing.TB, mode testMode, h Handler, opts ...any) *clientServerTest {
if mode == http2Mode {
CondSkipHTTP2(t)
}
cst := &clientServerTest{
t: t,
h2: h2,
h2: mode == http2Mode,
h: h,
tr: &Transport{},
}
cst.c = &Client{Transport: cst.tr}
cst.ts = httptest.NewUnstartedServer(h)
var transportFuncs []func(*Transport)
for _, opt := range opts {
switch opt := opt.(type) {
case func(*Transport):
opt(cst.tr)
transportFuncs = append(transportFuncs, opt)
case func(*httptest.Server):
opt(cst.ts)
default:
@ -108,60 +170,84 @@ func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...any) *clientS
}
}
if !h2 {
switch mode {
case http1Mode:
cst.ts.Start()
return cst
case https1Mode:
cst.ts.StartTLS()
case http2Mode:
ExportHttp2ConfigureServer(cst.ts.Config, nil)
cst.ts.TLS = cst.ts.Config.TLSConfig
cst.ts.StartTLS()
default:
t.Fatalf("unknown test mode %v", mode)
}
ExportHttp2ConfigureServer(cst.ts.Config, nil)
cst.ts.TLS = cst.ts.Config.TLSConfig
cst.ts.StartTLS()
cst.tr.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
cst.c = cst.ts.Client()
cst.tr = cst.c.Transport.(*Transport)
if mode == http2Mode {
if err := ExportHttp2ConfigureTransport(cst.tr); err != nil {
t.Fatal(err)
}
}
if err := ExportHttp2ConfigureTransport(cst.tr); err != nil {
t.Fatal(err)
for _, f := range transportFuncs {
f(cst.tr)
}
t.Cleanup(func() {
cst.close()
})
return cst
}
// Testing the newClientServerTest helper itself.
func TestNewClientServerTest(t *testing.T) {
run(t, testNewClientServerTest, []testMode{http1Mode, https1Mode, http2Mode})
}
func testNewClientServerTest(t *testing.T, mode testMode) {
var got struct {
sync.Mutex
log []string
proto string
hasTLS bool
}
h := HandlerFunc(func(w ResponseWriter, r *Request) {
got.Lock()
defer got.Unlock()
got.log = append(got.log, r.Proto)
got.proto = r.Proto
got.hasTLS = r.TLS != nil
})
for _, v := range [2]bool{false, true} {
cst := newClientServerTest(t, v, h)
if _, err := cst.c.Head(cst.ts.URL); err != nil {
t.Fatal(err)
}
cst.close()
cst := newClientServerTest(t, mode, h)
if _, err := cst.c.Head(cst.ts.URL); err != nil {
t.Fatal(err)
}
got.Lock() // no need to unlock
if want := []string{"HTTP/1.1", "HTTP/2.0"}; !reflect.DeepEqual(got.log, want) {
t.Errorf("got %q; want %q", got.log, want)
var wantProto string
var wantTLS bool
switch mode {
case http1Mode:
wantProto = "HTTP/1.1"
wantTLS = false
case https1Mode:
wantProto = "HTTP/1.1"
wantTLS = true
case http2Mode:
wantProto = "HTTP/2.0"
wantTLS = true
}
if got.proto != wantProto {
t.Errorf("req.Proto = %q, want %q", got.proto, wantProto)
}
if got.hasTLS != wantTLS {
t.Errorf("req.TLS set: %v, want %v", got.hasTLS, wantTLS)
}
}
func TestChunkedResponseHeaders_h1(t *testing.T) { testChunkedResponseHeaders(t, h1Mode) }
func TestChunkedResponseHeaders_h2(t *testing.T) { testChunkedResponseHeaders(t, h2Mode) }
func testChunkedResponseHeaders(t *testing.T, h2 bool) {
defer afterTest(t)
func TestChunkedResponseHeaders(t *testing.T) { run(t, testChunkedResponseHeaders) }
func testChunkedResponseHeaders(t *testing.T, mode testMode) {
log.SetOutput(io.Discard) // is noisy otherwise
defer log.SetOutput(os.Stderr)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
w.(Flusher).Flush()
fmt.Fprintf(w, "I am a chunked response.")
}))
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
@ -172,7 +258,7 @@ func testChunkedResponseHeaders(t *testing.T, h2 bool) {
t.Errorf("expected ContentLength of %d; got %d", e, g)
}
wantTE := []string{"chunked"}
if h2 {
if mode == http2Mode {
wantTE = nil
}
if !reflect.DeepEqual(res.TransferEncoding, wantTE) {
@ -204,9 +290,9 @@ func (tt h12Compare) reqFunc() reqFunc {
func (tt h12Compare) run(t *testing.T) {
setParallel(t)
cst1 := newClientServerTest(t, false, HandlerFunc(tt.Handler), tt.Opts...)
cst1 := newClientServerTest(t, http1Mode, HandlerFunc(tt.Handler), tt.Opts...)
defer cst1.close()
cst2 := newClientServerTest(t, true, HandlerFunc(tt.Handler), tt.Opts...)
cst2 := newClientServerTest(t, http2Mode, HandlerFunc(tt.Handler), tt.Opts...)
defer cst2.close()
res1, err := tt.reqFunc()(cst1.c, cst1.ts.URL)
@ -459,12 +545,9 @@ func TestH12_AutoGzip_Disabled(t *testing.T) {
// Test304Responses verifies that 304s don't declare that they're
// chunking in their response headers and aren't allowed to produce
// output.
func Test304Responses_h1(t *testing.T) { test304Responses(t, h1Mode) }
func Test304Responses_h2(t *testing.T) { test304Responses(t, h2Mode) }
func test304Responses(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func Test304Responses(t *testing.T) { run(t, test304Responses) }
func test304Responses(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusNotModified)
_, err := w.Write([]byte("illegal body"))
if err != ErrBodyNotAllowed {
@ -528,20 +611,17 @@ func h12requestContentLength(t *testing.T, bodyfn func() io.Reader, wantLen int6
// Tests that closing the Request.Cancel channel also while still
// reading the response body. Issue 13159.
func TestCancelRequestMidBody_h1(t *testing.T) { testCancelRequestMidBody(t, h1Mode) }
func TestCancelRequestMidBody_h2(t *testing.T) { testCancelRequestMidBody(t, h2Mode) }
func testCancelRequestMidBody(t *testing.T, h2 bool) {
defer afterTest(t)
func TestCancelRequestMidBody(t *testing.T) { run(t, testCancelRequestMidBody) }
func testCancelRequestMidBody(t *testing.T, mode testMode) {
unblock := make(chan bool)
didFlush := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
io.WriteString(w, "Hello")
w.(Flusher).Flush()
didFlush <- true
<-unblock
io.WriteString(w, ", world.")
}))
defer cst.close()
defer close(unblock)
req, _ := NewRequest("GET", cst.ts.URL, nil)
@ -577,12 +657,9 @@ func testCancelRequestMidBody(t *testing.T, h2 bool) {
}
// Tests that clients can send trailers to a server and that the server can read them.
func TestTrailersClientToServer_h1(t *testing.T) { testTrailersClientToServer(t, h1Mode) }
func TestTrailersClientToServer_h2(t *testing.T) { testTrailersClientToServer(t, h2Mode) }
func testTrailersClientToServer(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestTrailersClientToServer(t *testing.T) { run(t, testTrailersClientToServer) }
func testTrailersClientToServer(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
var decl []string
for k := range r.Trailer {
decl = append(decl, k)
@ -605,7 +682,6 @@ func testTrailersClientToServer(t *testing.T, h2 bool) {
r.Trailer.Get("Client-Trailer-B"))
}
}))
defer cst.close()
var req *Request
req, _ = NewRequest("POST", cst.ts.URL, io.MultiReader(
@ -632,15 +708,20 @@ func testTrailersClientToServer(t *testing.T, h2 bool) {
}
// Tests that servers send trailers to a client and that the client can read them.
func TestTrailersServerToClient_h1(t *testing.T) { testTrailersServerToClient(t, h1Mode, false) }
func TestTrailersServerToClient_h2(t *testing.T) { testTrailersServerToClient(t, h2Mode, false) }
func TestTrailersServerToClient_Flush_h1(t *testing.T) { testTrailersServerToClient(t, h1Mode, true) }
func TestTrailersServerToClient_Flush_h2(t *testing.T) { testTrailersServerToClient(t, h2Mode, true) }
func TestTrailersServerToClient(t *testing.T) {
run(t, func(t *testing.T, mode testMode) {
testTrailersServerToClient(t, mode, false)
})
}
func TestTrailersServerToClientFlush(t *testing.T) {
run(t, func(t *testing.T, mode testMode) {
testTrailersServerToClient(t, mode, true)
})
}
func testTrailersServerToClient(t *testing.T, h2, flush bool) {
defer afterTest(t)
func testTrailersServerToClient(t *testing.T, mode testMode, flush bool) {
const body = "Some body"
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B")
w.Header().Add("Trailer", "Server-Trailer-C")
@ -657,7 +738,6 @@ func testTrailersServerToClient(t *testing.T, h2, flush bool) {
w.Header().Set("Server-Trailer-C", "valuec") // skipping B
w.Header().Set("Server-Trailer-NotDeclared", "should be omitted")
}))
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
@ -668,7 +748,7 @@ func testTrailersServerToClient(t *testing.T, h2, flush bool) {
"Content-Type": {"text/plain; charset=utf-8"},
}
wantLen := -1
if h2 && !flush {
if mode == http2Mode && !flush {
// In HTTP/1.1, any use of trailers forces HTTP/1.1
// chunking and a flush at the first write. That's
// unnecessary with HTTP/2's framing, so the server
@ -708,16 +788,12 @@ func testTrailersServerToClient(t *testing.T, h2, flush bool) {
}
// Don't allow a Body.Read after Body.Close. Issue 13648.
func TestResponseBodyReadAfterClose_h1(t *testing.T) { testResponseBodyReadAfterClose(t, h1Mode) }
func TestResponseBodyReadAfterClose_h2(t *testing.T) { testResponseBodyReadAfterClose(t, h2Mode) }
func testResponseBodyReadAfterClose(t *testing.T, h2 bool) {
defer afterTest(t)
func TestResponseBodyReadAfterClose(t *testing.T) { run(t, testResponseBodyReadAfterClose) }
func testResponseBodyReadAfterClose(t *testing.T, mode testMode) {
const body = "Some body"
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
io.WriteString(w, body)
}))
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
@ -729,13 +805,11 @@ func testResponseBodyReadAfterClose(t *testing.T, h2 bool) {
}
}
func TestConcurrentReadWriteReqBody_h1(t *testing.T) { testConcurrentReadWriteReqBody(t, h1Mode) }
func TestConcurrentReadWriteReqBody_h2(t *testing.T) { testConcurrentReadWriteReqBody(t, h2Mode) }
func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) {
defer afterTest(t)
func TestConcurrentReadWriteReqBody(t *testing.T) { run(t, testConcurrentReadWriteReqBody) }
func testConcurrentReadWriteReqBody(t *testing.T, mode testMode) {
const reqBody = "some request body"
const resBody = "some response body"
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
var wg sync.WaitGroup
wg.Add(2)
didRead := make(chan bool, 1)
@ -754,7 +828,7 @@ func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) {
// Write in another goroutine.
go func() {
defer wg.Done()
if !h2 {
if mode != http2Mode {
// our HTTP/1 implementation intentionally
// doesn't permit writes during read (mostly
// due to it being undefined); if that is ever
@ -765,7 +839,6 @@ func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) {
}()
wg.Wait()
}))
defer cst.close()
req, _ := NewRequest("POST", cst.ts.URL, strings.NewReader(reqBody))
req.Header.Add("Expect", "100-continue") // just to complicate things
res, err := cst.c.Do(req)
@ -782,15 +855,12 @@ func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) {
}
}
func TestConnectRequest_h1(t *testing.T) { testConnectRequest(t, h1Mode) }
func TestConnectRequest_h2(t *testing.T) { testConnectRequest(t, h2Mode) }
func testConnectRequest(t *testing.T, h2 bool) {
defer afterTest(t)
func TestConnectRequest(t *testing.T) { run(t, testConnectRequest) }
func testConnectRequest(t *testing.T, mode testMode) {
gotc := make(chan *Request, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
gotc <- r
}))
defer cst.close()
u, err := url.Parse(cst.ts.URL)
if err != nil {
@ -840,17 +910,14 @@ func testConnectRequest(t *testing.T, h2 bool) {
}
}
func TestTransportUserAgent_h1(t *testing.T) { testTransportUserAgent(t, h1Mode) }
func TestTransportUserAgent_h2(t *testing.T) { testTransportUserAgent(t, h2Mode) }
func testTransportUserAgent(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestTransportUserAgent(t *testing.T) { run(t, testTransportUserAgent) }
func testTransportUserAgent(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%q", r.Header["User-Agent"])
}))
defer cst.close()
either := func(a, b string) string {
if h2 {
if mode == http2Mode {
return b
}
return a
@ -901,19 +968,22 @@ func testTransportUserAgent(t *testing.T, h2 bool) {
}
}
func TestStarRequestFoo_h1(t *testing.T) { testStarRequest(t, "FOO", h1Mode) }
func TestStarRequestFoo_h2(t *testing.T) { testStarRequest(t, "FOO", h2Mode) }
func TestStarRequestOptions_h1(t *testing.T) { testStarRequest(t, "OPTIONS", h1Mode) }
func TestStarRequestOptions_h2(t *testing.T) { testStarRequest(t, "OPTIONS", h2Mode) }
func testStarRequest(t *testing.T, method string, h2 bool) {
defer afterTest(t)
func TestStarRequestMethod(t *testing.T) {
for _, method := range []string{"FOO", "OPTIONS"} {
t.Run(method, func(t *testing.T) {
run(t, func(t *testing.T, mode testMode) {
testStarRequest(t, method, mode)
})
})
}
}
func testStarRequest(t *testing.T, method string, mode testMode) {
gotc := make(chan *Request, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("foo", "bar")
gotc <- r
w.(Flusher).Flush()
}))
defer cst.close()
u, err := url.Parse(cst.ts.URL)
if err != nil {
@ -972,9 +1042,10 @@ func testStarRequest(t *testing.T, method string, h2 bool) {
// Issue 13957
func TestTransportDiscardsUnneededConns(t *testing.T) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
run(t, testTransportDiscardsUnneededConns, []testMode{http2Mode})
}
func testTransportDiscardsUnneededConns(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Hello, %v", r.RemoteAddr)
}))
defer cst.close()
@ -1058,20 +1129,19 @@ func TestTransportDiscardsUnneededConns(t *testing.T) {
}
// tests that Transport doesn't retain a pointer to the provided request.
func TestTransportGCRequest_Body_h1(t *testing.T) { testTransportGCRequest(t, h1Mode, true) }
func TestTransportGCRequest_Body_h2(t *testing.T) { testTransportGCRequest(t, h2Mode, true) }
func TestTransportGCRequest_NoBody_h1(t *testing.T) { testTransportGCRequest(t, h1Mode, false) }
func TestTransportGCRequest_NoBody_h2(t *testing.T) { testTransportGCRequest(t, h2Mode, false) }
func testTransportGCRequest(t *testing.T, h2, body bool) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestTransportGCRequest(t *testing.T) {
run(t, func(t *testing.T, mode testMode) {
t.Run("Body", func(t *testing.T) { testTransportGCRequest(t, mode, true) })
t.Run("NoBody", func(t *testing.T) { testTransportGCRequest(t, mode, false) })
})
}
func testTransportGCRequest(t *testing.T, mode testMode, body bool) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
io.ReadAll(r.Body)
if body {
io.WriteString(w, "Hello.")
}
}))
defer cst.close()
didGC := make(chan struct{})
(func() {
@ -1103,19 +1173,11 @@ func testTransportGCRequest(t *testing.T, h2, body bool) {
}
}
func TestTransportRejectsInvalidHeaders_h1(t *testing.T) {
testTransportRejectsInvalidHeaders(t, h1Mode)
}
func TestTransportRejectsInvalidHeaders_h2(t *testing.T) {
testTransportRejectsInvalidHeaders(t, h2Mode)
}
func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestTransportRejectsInvalidHeaders(t *testing.T) { run(t, testTransportRejectsInvalidHeaders) }
func testTransportRejectsInvalidHeaders(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Handler saw headers: %q", r.Header)
}), optQuietLog)
defer cst.close()
cst.tr.DisableKeepAlives = true
tests := []struct {
@ -1161,27 +1223,22 @@ func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) {
}
}
func TestInterruptWithPanic_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, "boom") }
func TestInterruptWithPanic_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, "boom") }
func TestInterruptWithPanic_nil_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, nil) }
func TestInterruptWithPanic_nil_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, nil) }
func TestInterruptWithPanic_ErrAbortHandler_h1(t *testing.T) {
testInterruptWithPanic(t, h1Mode, ErrAbortHandler)
func TestInterruptWithPanic(t *testing.T) {
run(t, func(t *testing.T, mode testMode) {
t.Run("boom", func(t *testing.T) { testInterruptWithPanic(t, mode, "boom") })
t.Run("nil", func(t *testing.T) { testInterruptWithPanic(t, mode, nil) })
t.Run("ErrAbortHandler", func(t *testing.T) { testInterruptWithPanic(t, mode, ErrAbortHandler) })
})
}
func TestInterruptWithPanic_ErrAbortHandler_h2(t *testing.T) {
testInterruptWithPanic(t, h2Mode, ErrAbortHandler)
}
func testInterruptWithPanic(t *testing.T, h2 bool, panicValue any) {
setParallel(t)
func testInterruptWithPanic(t *testing.T, mode testMode, panicValue any) {
const msg = "hello"
defer afterTest(t)
testDone := make(chan struct{})
defer close(testDone)
var errorLog lockedBytesBuffer
gotHeaders := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
io.WriteString(w, msg)
w.(Flusher).Flush()
@ -1193,7 +1250,6 @@ func testInterruptWithPanic(t *testing.T, h2 bool, panicValue any) {
}), func(ts *httptest.Server) {
ts.Config.ErrorLog = log.New(&errorLog, "", 0)
})
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
@ -1274,15 +1330,11 @@ func TestH12_AutoGzipWithDumpResponse(t *testing.T) {
}
// Issue 14607
func TestCloseIdleConnections_h1(t *testing.T) { testCloseIdleConnections(t, h1Mode) }
func TestCloseIdleConnections_h2(t *testing.T) { testCloseIdleConnections(t, h2Mode) }
func testCloseIdleConnections(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestCloseIdleConnections(t *testing.T) { run(t, testCloseIdleConnections) }
func testCloseIdleConnections(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("X-Addr", r.RemoteAddr)
}))
defer cst.close()
get := func() string {
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
@ -1320,15 +1372,11 @@ func (r testErrorReader) Read(p []byte) (n int, err error) {
return 0, io.EOF
}
func TestNoSniffExpectRequestBody_h1(t *testing.T) { testNoSniffExpectRequestBody(t, h1Mode) }
func TestNoSniffExpectRequestBody_h2(t *testing.T) { testNoSniffExpectRequestBody(t, h2Mode) }
func testNoSniffExpectRequestBody(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestNoSniffExpectRequestBody(t *testing.T) { run(t, testNoSniffExpectRequestBody) }
func testNoSniffExpectRequestBody(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusUnauthorized)
}))
defer cst.close()
// Set ExpectContinueTimeout non-zero so RoundTrip won't try to write it.
cst.tr.ExpectContinueTimeout = 10 * time.Second
@ -1349,18 +1397,15 @@ func testNoSniffExpectRequestBody(t *testing.T, h2 bool) {
}
}
func TestServerUndeclaredTrailers_h1(t *testing.T) { testServerUndeclaredTrailers(t, h1Mode) }
func TestServerUndeclaredTrailers_h2(t *testing.T) { testServerUndeclaredTrailers(t, h2Mode) }
func testServerUndeclaredTrailers(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServerUndeclaredTrailers(t *testing.T) { run(t, testServerUndeclaredTrailers) }
func testServerUndeclaredTrailers(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Foo", "Bar")
w.Header().Set("Trailer:Foo", "Baz")
w.(Flusher).Flush()
w.Header().Add("Trailer:Foo", "Baz2")
w.Header().Set("Trailer:Bar", "Quux")
}))
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
@ -1381,8 +1426,10 @@ func testServerUndeclaredTrailers(t *testing.T, h2 bool) {
}
func TestBadResponseAfterReadingBody(t *testing.T) {
defer afterTest(t)
cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) {
run(t, testBadResponseAfterReadingBody, []testMode{http1Mode})
}
func testBadResponseAfterReadingBody(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
_, err := io.Copy(io.Discard, r.Body)
if err != nil {
t.Fatal(err)
@ -1394,7 +1441,6 @@ func TestBadResponseAfterReadingBody(t *testing.T) {
defer c.Close()
fmt.Fprintln(c, "some bogus crap")
}))
defer cst.close()
closes := 0
res, err := cst.c.Post(cst.ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
@ -1407,12 +1453,10 @@ func TestBadResponseAfterReadingBody(t *testing.T) {
}
}
func TestWriteHeader0_h1(t *testing.T) { testWriteHeader0(t, h1Mode) }
func TestWriteHeader0_h2(t *testing.T) { testWriteHeader0(t, h2Mode) }
func testWriteHeader0(t *testing.T, h2 bool) {
defer afterTest(t)
func TestWriteHeader0(t *testing.T) { run(t, testWriteHeader0) }
func testWriteHeader0(t *testing.T, mode testMode) {
gotpanic := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
defer close(gotpanic)
defer func() {
if e := recover(); e != nil {
@ -1431,7 +1475,6 @@ func testWriteHeader0(t *testing.T, h2 bool) {
}()
w.WriteHeader(0)
}))
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
@ -1446,15 +1489,17 @@ func testWriteHeader0(t *testing.T, h2 bool) {
// Issue 23010: don't be super strict checking WriteHeader's code if
// it's not even valid to call WriteHeader then anyway.
func TestWriteHeaderNoCodeCheck_h1(t *testing.T) { testWriteHeaderAfterWrite(t, h1Mode, false) }
func TestWriteHeaderNoCodeCheck_h1hijack(t *testing.T) { testWriteHeaderAfterWrite(t, h1Mode, true) }
func TestWriteHeaderNoCodeCheck_h2(t *testing.T) { testWriteHeaderAfterWrite(t, h2Mode, false) }
func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) {
setParallel(t)
defer afterTest(t)
func TestWriteHeaderNoCodeCheck(t *testing.T) {
run(t, func(t *testing.T, mode testMode) {
testWriteHeaderAfterWrite(t, mode, false)
})
}
func TestWriteHeaderNoCodeCheck_h1hijack(t *testing.T) {
testWriteHeaderAfterWrite(t, http1Mode, true)
}
func testWriteHeaderAfterWrite(t *testing.T, mode testMode, hijack bool) {
var errorLog lockedBytesBuffer
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
if hijack {
conn, _, _ := w.(Hijacker).Hijack()
defer conn.Close()
@ -1470,7 +1515,6 @@ func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) {
}), func(ts *httptest.Server) {
ts.Config.ErrorLog = log.New(&errorLog, "", 0)
})
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
@ -1485,7 +1529,7 @@ func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) {
}
// Also check the stderr output:
if h2 {
if mode == http2Mode {
// TODO: also emit this log message for HTTP/2?
// We historically haven't, so don't check.
return
@ -1501,14 +1545,14 @@ func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) {
}
func TestBidiStreamReverseProxy(t *testing.T) {
setParallel(t)
defer afterTest(t)
backend := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
run(t, testBidiStreamReverseProxy, []testMode{http2Mode})
}
func testBidiStreamReverseProxy(t *testing.T, mode testMode) {
backend := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
if _, err := io.Copy(w, r.Body); err != nil {
log.Printf("bidi backend copy: %v", err)
}
}))
defer backend.close()
backURL, err := url.Parse(backend.ts.URL)
if err != nil {
@ -1516,10 +1560,9 @@ func TestBidiStreamReverseProxy(t *testing.T) {
}
rp := httputil.NewSingleHostReverseProxy(backURL)
rp.Transport = backend.tr
proxy := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
proxy := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
rp.ServeHTTP(w, r)
}))
defer proxy.close()
bodyRes := make(chan any, 1) // error or hash.Hash
pr, pw := io.Pipe()
@ -1586,15 +1629,10 @@ func TestH12_WebSocketUpgrade(t *testing.T) {
}.run(t)
}
func TestIdentityTransferEncoding_h1(t *testing.T) { testIdentityTransferEncoding(t, h1Mode) }
func TestIdentityTransferEncoding_h2(t *testing.T) { testIdentityTransferEncoding(t, h2Mode) }
func testIdentityTransferEncoding(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
func TestIdentityTransferEncoding(t *testing.T) { run(t, testIdentityTransferEncoding) }
func testIdentityTransferEncoding(t *testing.T, mode testMode) {
const body = "body"
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
gotBody, _ := io.ReadAll(r.Body)
if got, want := string(gotBody), body; got != want {
t.Errorf("got request body = %q; want %q", got, want)
@ -1604,7 +1642,6 @@ func testIdentityTransferEncoding(t *testing.T, h2 bool) {
w.(Flusher).Flush()
io.WriteString(w, body)
}))
defer cst.close()
req, _ := NewRequest("GET", cst.ts.URL, strings.NewReader(body))
res, err := cst.c.Do(req)
if err != nil {
@ -1620,14 +1657,11 @@ func testIdentityTransferEncoding(t *testing.T, h2 bool) {
}
}
func TestEarlyHintsRequest_h1(t *testing.T) { testEarlyHintsRequest(t, h1Mode) }
func TestEarlyHintsRequest_h2(t *testing.T) { testEarlyHintsRequest(t, h2Mode) }
func testEarlyHintsRequest(t *testing.T, h2 bool) {
defer afterTest(t)
func TestEarlyHintsRequest(t *testing.T) { run(t, testEarlyHintsRequest) }
func testEarlyHintsRequest(t *testing.T, mode testMode) {
var wg sync.WaitGroup
wg.Add(1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
h := w.Header()
h.Add("Content-Length", "123") // must be ignored
@ -1642,7 +1676,6 @@ func testEarlyHintsRequest(t *testing.T, h2 bool) {
w.Write([]byte("Hello"))
}))
defer cst.close()
checkLinkHeaders := func(t *testing.T, expected, got []string) {
t.Helper()

View File

@ -60,7 +60,7 @@ func init() {
}
}
func CondSkipHTTP2(t *testing.T) {
func CondSkipHTTP2(t testing.TB) {
if omitBundledHTTP2 {
t.Skip("skipping HTTP/2 test when nethttpomithttp2 build tag in use")
}
@ -72,8 +72,6 @@ var (
)
func SetReadLoopBeforeNextReadHook(f func()) {
testHookMu.Lock()
defer testHookMu.Unlock()
unnilTestHook(&f)
testHookReadLoopBeforeNextRead = f
}

View File

@ -68,13 +68,11 @@ var ServeFileRangeTests = []struct {
{r: "bytes=100-1000", code: StatusRequestedRangeNotSatisfiable},
}
func TestServeFile(t *testing.T) {
setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServeFile(t *testing.T) { run(t, testServeFile) }
func testServeFile(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/file")
}))
defer ts.Close()
})).ts
c := ts.Client()
var err error
@ -228,13 +226,12 @@ var fsRedirectTestData = []struct {
{"/test/testdata/file/", "/test/testdata/file"},
}
func TestFSRedirect(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
defer ts.Close()
func TestFSRedirect(t *testing.T) { run(t, testFSRedirect) }
func testFSRedirect(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, StripPrefix("/test", FileServer(Dir(".")))).ts
for _, data := range fsRedirectTestData {
res, err := Get(ts.URL + data.original)
res, err := ts.Client().Get(ts.URL + data.original)
if err != nil {
t.Fatal(err)
}
@ -278,8 +275,8 @@ func TestFileServerCleans(t *testing.T) {
}
}
func TestFileServerEscapesNames(t *testing.T) {
defer afterTest(t)
func TestFileServerEscapesNames(t *testing.T) { run(t, testFileServerEscapesNames) }
func testFileServerEscapesNames(t *testing.T, mode testMode) {
const dirListPrefix = "<pre>\n"
const dirListSuffix = "\n</pre>\n"
tests := []struct {
@ -304,11 +301,10 @@ func TestFileServerEscapesNames(t *testing.T) {
fs[fmt.Sprintf("/%d/%s", i, test.name)] = testFile
}
ts := httptest.NewServer(FileServer(&fs))
defer ts.Close()
ts := newClientServerTest(t, mode, FileServer(&fs)).ts
for i, test := range tests {
url := fmt.Sprintf("%s/%d", ts.URL, i)
res, err := Get(url)
res, err := ts.Client().Get(url)
if err != nil {
t.Fatalf("test %q: Get: %v", test.name, err)
}
@ -327,8 +323,8 @@ func TestFileServerEscapesNames(t *testing.T) {
}
}
func TestFileServerSortsNames(t *testing.T) {
defer afterTest(t)
func TestFileServerSortsNames(t *testing.T) { run(t, testFileServerSortsNames) }
func testFileServerSortsNames(t *testing.T, mode testMode) {
const contents = "I am a fake file"
dirMod := time.Unix(123, 0).UTC()
fileMod := time.Unix(1000000000, 0).UTC()
@ -351,10 +347,9 @@ func TestFileServerSortsNames(t *testing.T) {
},
}
ts := httptest.NewServer(FileServer(&fs))
defer ts.Close()
ts := newClientServerTest(t, mode, FileServer(&fs)).ts
res, err := Get(ts.URL)
res, err := ts.Client().Get(ts.URL)
if err != nil {
t.Fatalf("Get: %v", err)
}
@ -377,16 +372,15 @@ func mustRemoveAll(dir string) {
}
}
func TestFileServerImplicitLeadingSlash(t *testing.T) {
defer afterTest(t)
func TestFileServerImplicitLeadingSlash(t *testing.T) { run(t, testFileServerImplicitLeadingSlash) }
func testFileServerImplicitLeadingSlash(t *testing.T, mode testMode) {
tempDir := t.TempDir()
if err := os.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
ts := httptest.NewServer(StripPrefix("/bar/", FileServer(Dir(tempDir))))
defer ts.Close()
ts := newClientServerTest(t, mode, StripPrefix("/bar/", FileServer(Dir(tempDir)))).ts
get := func(suffix string) string {
res, err := Get(ts.URL + suffix)
res, err := ts.Client().Get(ts.URL + suffix)
if err != nil {
t.Fatalf("Get %s: %v", suffix, err)
}
@ -405,11 +399,10 @@ func TestFileServerImplicitLeadingSlash(t *testing.T) {
}
}
func TestFileServerMethodOptions(t *testing.T) {
defer afterTest(t)
func TestFileServerMethodOptions(t *testing.T) { run(t, testFileServerMethodOptions) }
func testFileServerMethodOptions(t *testing.T, mode testMode) {
const want = "GET, HEAD, OPTIONS"
ts := httptest.NewServer(FileServer(Dir(".")))
defer ts.Close()
ts := newClientServerTest(t, mode, FileServer(Dir("."))).ts
tests := []struct {
method string
@ -496,10 +489,10 @@ func TestEmptyDirOpenCWD(t *testing.T) {
test(Dir("./"))
}
func TestServeFileContentType(t *testing.T) {
defer afterTest(t)
func TestServeFileContentType(t *testing.T) { run(t, testServeFileContentType) }
func testServeFileContentType(t *testing.T, mode testMode) {
const ctype = "icecream/chocolate"
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
switch r.FormValue("override") {
case "1":
w.Header().Set("Content-Type", ctype)
@ -508,10 +501,9 @@ func TestServeFileContentType(t *testing.T) {
w.Header()["Content-Type"] = []string{}
}
ServeFile(w, r, "testdata/file")
}))
defer ts.Close()
})).ts
get := func(override string, want []string) {
resp, err := Get(ts.URL + "?override=" + override)
resp, err := ts.Client().Get(ts.URL + "?override=" + override)
if err != nil {
t.Fatal(err)
}
@ -525,13 +517,12 @@ func TestServeFileContentType(t *testing.T) {
get("2", nil)
}
func TestServeFileMimeType(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServeFileMimeType(t *testing.T) { run(t, testServeFileMimeType) }
func testServeFileMimeType(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/style.css")
}))
defer ts.Close()
resp, err := Get(ts.URL)
})).ts
resp, err := ts.Client().Get(ts.URL)
if err != nil {
t.Fatal(err)
}
@ -542,13 +533,12 @@ func TestServeFileMimeType(t *testing.T) {
}
}
func TestServeFileFromCWD(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServeFileFromCWD(t *testing.T) { run(t, testServeFileFromCWD) }
func testServeFileFromCWD(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "fs_test.go")
}))
defer ts.Close()
r, err := Get(ts.URL)
})).ts
r, err := ts.Client().Get(ts.URL)
if err != nil {
t.Fatal(err)
}
@ -559,14 +549,13 @@ func TestServeFileFromCWD(t *testing.T) {
}
// Issue 13996
func TestServeDirWithoutTrailingSlash(t *testing.T) {
func TestServeDirWithoutTrailingSlash(t *testing.T) { run(t, testServeDirWithoutTrailingSlash) }
func testServeDirWithoutTrailingSlash(t *testing.T, mode testMode) {
e := "/testdata/"
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, ".")
}))
defer ts.Close()
r, err := Get(ts.URL + "/testdata")
})).ts
r, err := ts.Client().Get(ts.URL + "/testdata")
if err != nil {
t.Fatal(err)
}
@ -578,11 +567,9 @@ func TestServeDirWithoutTrailingSlash(t *testing.T) {
// Tests that ServeFile doesn't add a Content-Length if a Content-Encoding is
// specified.
func TestServeFileWithContentEncoding_h1(t *testing.T) { testServeFileWithContentEncoding(t, h1Mode) }
func TestServeFileWithContentEncoding_h2(t *testing.T) { testServeFileWithContentEncoding(t, h2Mode) }
func testServeFileWithContentEncoding(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServeFileWithContentEncoding(t *testing.T) { run(t, testServeFileWithContentEncoding) }
func testServeFileWithContentEncoding(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Encoding", "foo")
ServeFile(w, r, "testdata/file")
@ -595,7 +582,6 @@ func testServeFileWithContentEncoding(t *testing.T, h2 bool) {
// Content-Length and test ServeFile only, flush here.
w.(Flusher).Flush()
}))
defer cst.close()
resp, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
@ -608,11 +594,9 @@ func testServeFileWithContentEncoding(t *testing.T, h2 bool) {
// Tests that ServeFile does not generate representation metadata when
// file has not been modified, as per RFC 7232 section 4.1.
func TestServeFileNotModified_h1(t *testing.T) { testServeFileNotModified(t, h1Mode) }
func TestServeFileNotModified_h2(t *testing.T) { testServeFileNotModified(t, h2Mode) }
func testServeFileNotModified(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServeFileNotModified(t *testing.T) { run(t, testServeFileNotModified) }
func testServeFileNotModified(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Encoding", "foo")
w.Header().Set("Etag", `"123"`)
@ -627,7 +611,6 @@ func testServeFileNotModified(t *testing.T, h2 bool) {
// Content-Length and test ServeFile only, flush here.
w.(Flusher).Flush()
}))
defer cst.close()
req, err := NewRequest("GET", cst.ts.URL, nil)
if err != nil {
t.Fatal(err)
@ -660,9 +643,8 @@ func testServeFileNotModified(t *testing.T, h2 bool) {
}
}
func TestServeIndexHtml(t *testing.T) {
defer afterTest(t)
func TestServeIndexHtml(t *testing.T) { run(t, testServeIndexHtml) }
func testServeIndexHtml(t *testing.T, mode testMode) {
for i := 0; i < 2; i++ {
var h Handler
var name string
@ -676,11 +658,10 @@ func TestServeIndexHtml(t *testing.T) {
}
t.Run(name, func(t *testing.T) {
const want = "index.html says hello\n"
ts := httptest.NewServer(h)
defer ts.Close()
ts := newClientServerTest(t, mode, h).ts
for _, path := range []string{"/testdata/", "/testdata/index.html"} {
res, err := Get(ts.URL + path)
res, err := ts.Client().Get(ts.URL + path)
if err != nil {
t.Fatal(err)
}
@ -697,14 +678,14 @@ func TestServeIndexHtml(t *testing.T) {
}
}
func TestServeIndexHtmlFS(t *testing.T) {
defer afterTest(t)
func TestServeIndexHtmlFS(t *testing.T) { run(t, testServeIndexHtmlFS) }
func testServeIndexHtmlFS(t *testing.T, mode testMode) {
const want = "index.html says hello\n"
ts := httptest.NewServer(FileServer(Dir(".")))
ts := newClientServerTest(t, mode, FileServer(Dir("."))).ts
defer ts.Close()
for _, path := range []string{"/testdata/", "/testdata/index.html"} {
res, err := Get(ts.URL + path)
res, err := ts.Client().Get(ts.URL + path)
if err != nil {
t.Fatal(err)
}
@ -719,10 +700,9 @@ func TestServeIndexHtmlFS(t *testing.T) {
}
}
func TestFileServerZeroByte(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(FileServer(Dir(".")))
defer ts.Close()
func TestFileServerZeroByte(t *testing.T) { run(t, testFileServerZeroByte) }
func testFileServerZeroByte(t *testing.T, mode testMode) {
ts := newClientServerTest(t, mode, FileServer(Dir("."))).ts
c, err := net.Dial("tcp", ts.Listener.Addr().String())
if err != nil {
@ -809,8 +789,8 @@ func (fsys fakeFS) Open(name string) (File, error) {
return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil
}
func TestDirectoryIfNotModified(t *testing.T) {
defer afterTest(t)
func TestDirectoryIfNotModified(t *testing.T) { run(t, testDirectoryIfNotModified) }
func testDirectoryIfNotModified(t *testing.T, mode testMode) {
const indexContents = "I am a fake index.html file"
fileMod := time.Unix(1000000000, 0).UTC()
fileModStr := fileMod.Format(TimeFormat)
@ -829,10 +809,9 @@ func TestDirectoryIfNotModified(t *testing.T) {
"/index.html": indexFile,
}
ts := httptest.NewServer(FileServer(fs))
defer ts.Close()
ts := newClientServerTest(t, mode, FileServer(fs)).ts
res, err := Get(ts.URL)
res, err := ts.Client().Get(ts.URL)
if err != nil {
t.Fatal(err)
}
@ -884,8 +863,8 @@ func mustStat(t *testing.T, fileName string) fs.FileInfo {
return fi
}
func TestServeContent(t *testing.T) {
defer afterTest(t)
func TestServeContent(t *testing.T) { run(t, testServeContent) }
func testServeContent(t *testing.T, mode testMode) {
type serveParam struct {
name string
modtime time.Time
@ -894,7 +873,7 @@ func TestServeContent(t *testing.T) {
etag string
}
servec := make(chan serveParam, 1)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
p := <-servec
if p.etag != "" {
w.Header().Set("ETag", p.etag)
@ -903,8 +882,7 @@ func TestServeContent(t *testing.T) {
w.Header().Set("Content-Type", p.contentType)
}
ServeContent(w, r, p.name, p.modtime, p.content)
}))
defer ts.Close()
})).ts
type testCase struct {
// One of file or content must be set:
@ -1213,8 +1191,8 @@ type issue12991File struct{ File }
func (issue12991File) Stat() (fs.FileInfo, error) { return nil, fs.ErrPermission }
func (issue12991File) Close() error { return nil }
func TestServeContentErrorMessages(t *testing.T) {
defer afterTest(t)
func TestServeContentErrorMessages(t *testing.T) { run(t, testServeContentErrorMessages) }
func testServeContentErrorMessages(t *testing.T, mode testMode) {
fs := fakeFS{
"/500": &fakeFileInfo{
err: errors.New("random error"),
@ -1223,8 +1201,7 @@ func TestServeContentErrorMessages(t *testing.T) {
err: &fs.PathError{Err: fs.ErrPermission},
},
}
ts := httptest.NewServer(FileServer(fs))
defer ts.Close()
ts := newClientServerTest(t, mode, FileServer(fs)).ts
c := ts.Client()
for _, code := range []int{403, 404, 500} {
res, err := c.Get(fmt.Sprintf("%s/%d", ts.URL, code))
@ -1342,20 +1319,20 @@ func TestLinuxSendfileChild(*testing.T) {
// Issues 18984, 49552: tests that requests for paths beyond files return not-found errors
func TestFileServerNotDirError(t *testing.T) {
defer afterTest(t)
t.Run("Dir", func(t *testing.T) {
testFileServerNotDirError(t, func(path string) FileSystem { return Dir(path) })
})
t.Run("FS", func(t *testing.T) {
testFileServerNotDirError(t, func(path string) FileSystem { return FS(os.DirFS(path)) })
run(t, func(t *testing.T, mode testMode) {
t.Run("Dir", func(t *testing.T) {
testFileServerNotDirError(t, mode, func(path string) FileSystem { return Dir(path) })
})
t.Run("FS", func(t *testing.T) {
testFileServerNotDirError(t, mode, func(path string) FileSystem { return FS(os.DirFS(path)) })
})
})
}
func testFileServerNotDirError(t *testing.T, newfs func(string) FileSystem) {
ts := httptest.NewServer(FileServer(newfs("testdata")))
defer ts.Close()
func testFileServerNotDirError(t *testing.T, mode testMode, newfs func(string) FileSystem) {
ts := newClientServerTest(t, mode, FileServer(newfs("testdata"))).ts
res, err := Get(ts.URL + "/index.html/not-a-file")
res, err := ts.Client().Get(ts.URL + "/index.html/not-a-file")
if err != nil {
t.Fatal(err)
}
@ -1459,19 +1436,11 @@ func Test_scanETag(t *testing.T) {
// Issue 40940: Ensure that we only accept non-negative suffix-lengths
// in "Range": "bytes=-N", and should reject "bytes=--2".
func TestServeFileRejectsInvalidSuffixLengths_h1(t *testing.T) {
testServeFileRejectsInvalidSuffixLengths(t, h1Mode)
func TestServeFileRejectsInvalidSuffixLengths(t *testing.T) {
run(t, testServeFileRejectsInvalidSuffixLengths, []testMode{http1Mode, https1Mode, http2Mode})
}
func TestServeFileRejectsInvalidSuffixLengths_h2(t *testing.T) {
testServeFileRejectsInvalidSuffixLengths(t, h2Mode)
}
func testServeFileRejectsInvalidSuffixLengths(t *testing.T, h2 bool) {
defer afterTest(t)
cst := httptest.NewUnstartedServer(FileServer(Dir("testdata")))
cst.EnableHTTP2 = h2
cst.StartTLS()
defer cst.Close()
func testServeFileRejectsInvalidSuffixLengths(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, FileServer(Dir("testdata"))).ts
tests := []struct {
r string

View File

@ -15,7 +15,6 @@ import (
"math"
"mime/multipart"
. "net/http"
"net/http/httptest"
"net/url"
"os"
"reflect"
@ -289,10 +288,11 @@ Content-Type: text/plain
// the payload size and the internal leeway buffer size of 10MiB overflows, that we
// correctly return an error.
func TestMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T) {
defer afterTest(t)
run(t, testMaxInt64ForMultipartFormMaxMemoryOverflow)
}
func testMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T, mode testMode) {
payloadSize := 1 << 10
cst := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
// The combination of:
// MaxInt64 + payloadSize + (internal spare of 10MiB)
// triggers the overflow. See issue https://golang.org/issue/40430/
@ -300,8 +300,7 @@ func TestMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T) {
Error(rw, err.Error(), StatusBadRequest)
return
}
}))
defer cst.Close()
})).ts
fBuf := new(bytes.Buffer)
mw := multipart.NewWriter(fBuf)
mf, err := mw.CreateFormFile("file", "myfile.txt")
@ -329,11 +328,9 @@ func TestMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T) {
}
}
func TestRedirect_h1(t *testing.T) { testRedirect(t, h1Mode) }
func TestRedirect_h2(t *testing.T) { testRedirect(t, h2Mode) }
func testRedirect(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestRequestRedirect(t *testing.T) { run(t, testRequestRedirect) }
func testRequestRedirect(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
switch r.URL.Path {
case "/":
w.Header().Set("Location", "/foo/")
@ -344,7 +341,6 @@ func testRedirect(t *testing.T, h2 bool) {
w.WriteHeader(StatusBadRequest)
}
}))
defer cst.close()
var end = regexp.MustCompile("/foo/$")
r, err := cst.c.Get(cst.ts.URL)
@ -1035,19 +1031,10 @@ func TestRequestCloneTransferEncoding(t *testing.T) {
}
}
func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) {
testNoPanicWithBasicAuth(t, h1Mode)
}
func TestNoPanicOnRoundTripWithBasicAuth_h2(t *testing.T) {
testNoPanicWithBasicAuth(t, h2Mode)
}
// Issue 34878: verify we don't panic when including basic auth (Go 1.13 regression)
func testNoPanicWithBasicAuth(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer cst.close()
func TestNoPanicOnRoundTripWithBasicAuth(t *testing.T) { run(t, testNoPanicWithBasicAuth) }
func testNoPanicWithBasicAuth(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}))
u, err := url.Parse(cst.ts.URL)
if err != nil {
@ -1328,11 +1315,6 @@ Host: localhost:8080
`)
}
const (
withTLS = true
noTLS = false
)
func BenchmarkFileAndServer_1KB(b *testing.B) {
benchmarkFileAndServer(b, 1<<10)
}
@ -1360,16 +1342,12 @@ func benchmarkFileAndServer(b *testing.B, n int64) {
b.Fatalf("Failed to copy %d bytes: %v", n, err)
}
b.Run("NoTLS", func(b *testing.B) {
runFileAndServerBenchmarks(b, noTLS, f, n)
})
b.Run("TLS", func(b *testing.B) {
runFileAndServerBenchmarks(b, withTLS, f, n)
})
run(b, func(b *testing.B, mode testMode) {
runFileAndServerBenchmarks(b, mode, f, n)
}, []testMode{http1Mode, https1Mode, http2Mode})
}
func runFileAndServerBenchmarks(b *testing.B, tlsOption bool, f *os.File, n int64) {
func runFileAndServerBenchmarks(b *testing.B, mode testMode, f *os.File, n int64) {
handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
defer req.Body.Close()
nc, err := io.Copy(io.Discard, req.Body)
@ -1382,14 +1360,8 @@ func runFileAndServerBenchmarks(b *testing.B, tlsOption bool, f *os.File, n int6
}
})
var cst *httptest.Server
if tlsOption == withTLS {
cst = httptest.NewTLSServer(handler)
} else {
cst = httptest.NewServer(handler)
}
cst := newClientServerTest(b, mode, handler).ts
defer cst.Close()
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Perform some setup.

File diff suppressed because it is too large Load Diff

View File

@ -88,13 +88,9 @@ func TestDetectContentType(t *testing.T) {
}
}
func TestServerContentType_h1(t *testing.T) { testServerContentType(t, h1Mode) }
func TestServerContentType_h2(t *testing.T) { testServerContentType(t, h2Mode) }
func testServerContentType(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServerContentTypeSniff(t *testing.T) { run(t, testServerContentTypeSniff) }
func testServerContentTypeSniff(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
i, _ := strconv.Atoi(r.FormValue("i"))
tt := sniffTests[i]
n, err := w.Write(tt.data)
@ -134,15 +130,12 @@ func testServerContentType(t *testing.T, h2 bool) {
// Issue 5953: shouldn't sniff if the handler set a Content-Type header,
// even if it's the empty string.
func TestServerIssue5953_h1(t *testing.T) { testServerIssue5953(t, h1Mode) }
func TestServerIssue5953_h2(t *testing.T) { testServerIssue5953(t, h2Mode) }
func testServerIssue5953(t *testing.T, h2 bool) {
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestServerIssue5953(t *testing.T) { run(t, testServerIssue5953) }
func testServerIssue5953(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header()["Content-Type"] = []string{""}
fmt.Fprintf(w, "<html><head></head><body>hi</body></html>")
}))
defer cst.close()
resp, err := cst.c.Get(cst.ts.URL)
if err != nil {
@ -173,11 +166,8 @@ func (b *byteAtATimeReader) Read(p []byte) (n int, err error) {
return 1, nil
}
func TestContentTypeWithVariousSources_h1(t *testing.T) { testContentTypeWithVariousSources(t, h1Mode) }
func TestContentTypeWithVariousSources_h2(t *testing.T) { testContentTypeWithVariousSources(t, h2Mode) }
func testContentTypeWithVariousSources(t *testing.T, h2 bool) {
defer afterTest(t)
func TestContentTypeWithVariousSources(t *testing.T) { run(t, testContentTypeWithVariousSources) }
func testContentTypeWithVariousSources(t *testing.T, mode testMode) {
const (
input = "\n<html>\n\t<head>\n"
expected = "text/html; charset=utf-8"
@ -239,8 +229,7 @@ func testContentTypeWithVariousSources(t *testing.T, h2 bool) {
},
}} {
t.Run(test.name, func(t *testing.T) {
cst := newClientServerTest(t, h2, HandlerFunc(test.handler))
defer cst.close()
cst := newClientServerTest(t, mode, HandlerFunc(test.handler))
resp, err := cst.c.Get(cst.ts.URL)
if err != nil {
@ -265,12 +254,9 @@ func testContentTypeWithVariousSources(t *testing.T, h2 bool) {
}
}
func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) }
func TestSniffWriteSize_h2(t *testing.T) { testSniffWriteSize(t, h2Mode) }
func testSniffWriteSize(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
func TestSniffWriteSize(t *testing.T) { run(t, testSniffWriteSize) }
func testSniffWriteSize(t *testing.T, mode testMode) {
cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
size, _ := strconv.Atoi(r.FormValue("size"))
written, err := io.WriteString(w, strings.Repeat("a", size))
if err != nil {
@ -281,7 +267,6 @@ func testSniffWriteSize(t *testing.T, h2 bool) {
t.Errorf("write of %d bytes wrote %d bytes", size, written)
}
}))
defer cst.close()
for _, size := range []int{0, 1, 200, 600, 999, 1000, 1023, 1024, 512 << 10, 1 << 20} {
res, err := cst.c.Get(fmt.Sprintf("%s/?size=%d", cst.ts.URL, size))
if err != nil {

File diff suppressed because it is too large Load Diff