Source file
src/net/http/serve_test.go
1
2
3
4
5
6
7 package http_test
8
9 import (
10 "bufio"
11 "bytes"
12 "compress/gzip"
13 "compress/zlib"
14 "context"
15 crand "crypto/rand"
16 "crypto/tls"
17 "crypto/x509"
18 "encoding/json"
19 "errors"
20 "fmt"
21 "internal/nettest"
22 "internal/testenv"
23 "io"
24 "log"
25 "math/rand"
26 "mime/multipart"
27 "net"
28 . "net/http"
29 "net/http/httptest"
30 "net/http/httptrace"
31 "net/http/httputil"
32 "net/http/internal"
33 "net/http/internal/testcert"
34 "net/url"
35 "os"
36 "path/filepath"
37 "reflect"
38 "regexp"
39 "runtime"
40 "slices"
41 "strconv"
42 "strings"
43 "sync"
44 "sync/atomic"
45 "syscall"
46 "testing"
47 "testing/synctest"
48 "time"
49 )
50
51 type dummyAddr string
52 type oneConnListener struct {
53 conn net.Conn
54 }
55
56 func (l *oneConnListener) Accept() (c net.Conn, err error) {
57 c = l.conn
58 if c == nil {
59 err = io.EOF
60 return
61 }
62 err = nil
63 l.conn = nil
64 return
65 }
66
67 func (l *oneConnListener) Close() error {
68 return nil
69 }
70
71 func (l *oneConnListener) Addr() net.Addr {
72 return dummyAddr("test-address")
73 }
74
75 func (a dummyAddr) Network() string {
76 return string(a)
77 }
78
79 func (a dummyAddr) String() string {
80 return string(a)
81 }
82
83 type noopConn struct{}
84
85 func (noopConn) LocalAddr() net.Addr { return dummyAddr("local-addr") }
86 func (noopConn) RemoteAddr() net.Addr { return dummyAddr("remote-addr") }
87 func (noopConn) SetDeadline(t time.Time) error { return nil }
88 func (noopConn) SetReadDeadline(t time.Time) error { return nil }
89 func (noopConn) SetWriteDeadline(t time.Time) error { return nil }
90
91 type rwTestConn struct {
92 io.Reader
93 io.Writer
94 noopConn
95
96 closeFunc func() error
97 closec chan bool
98 }
99
100 func (c *rwTestConn) Close() error {
101 if c.closeFunc != nil {
102 return c.closeFunc()
103 }
104 select {
105 case c.closec <- true:
106 default:
107 }
108 return nil
109 }
110
111 type testConn struct {
112 readMu sync.Mutex
113 readBuf bytes.Buffer
114 writeBuf bytes.Buffer
115 closec chan bool
116 noopConn
117 }
118
119 func newTestConn() *testConn {
120 return &testConn{closec: make(chan bool, 1)}
121 }
122
123 func (c *testConn) Read(b []byte) (int, error) {
124 c.readMu.Lock()
125 defer c.readMu.Unlock()
126 return c.readBuf.Read(b)
127 }
128
129 func (c *testConn) Write(b []byte) (int, error) {
130 return c.writeBuf.Write(b)
131 }
132
133 func (c *testConn) Close() error {
134 select {
135 case c.closec <- true:
136 default:
137 }
138 return nil
139 }
140
141
142
143 func reqBytes(req string) []byte {
144 return []byte(strings.ReplaceAll(strings.TrimSpace(req), "\n", "\r\n") + "\r\n\r\n")
145 }
146
147 type handlerTest struct {
148 logbuf bytes.Buffer
149 handler Handler
150 }
151
152 func newHandlerTest(h Handler) handlerTest {
153 return handlerTest{handler: h}
154 }
155
156 func (ht *handlerTest) rawResponse(req string) string {
157 reqb := reqBytes(req)
158 var output strings.Builder
159 conn := &rwTestConn{
160 Reader: bytes.NewReader(reqb),
161 Writer: &output,
162 closec: make(chan bool, 1),
163 }
164 ln := &oneConnListener{conn: conn}
165 srv := &Server{
166 ErrorLog: log.New(&ht.logbuf, "", 0),
167 Handler: ht.handler,
168 }
169 go srv.Serve(ln)
170 <-conn.closec
171 return output.String()
172 }
173
174 func TestConsumingBodyOnNextConn(t *testing.T) {
175 t.Parallel()
176 conn := new(testConn)
177 for i := 0; i < 2; i++ {
178 conn.readBuf.Write([]byte(
179 "POST / HTTP/1.1\r\n" +
180 "Host: test\r\n" +
181 "Content-Length: 11\r\n" +
182 "\r\n" +
183 "foo=1&bar=1"))
184 }
185
186 reqNum := 0
187 ch := make(chan *Request)
188 servech := make(chan error)
189 listener := &oneConnListener{conn}
190 handler := func(res ResponseWriter, req *Request) {
191 reqNum++
192 ch <- req
193 }
194
195 go func() {
196 servech <- Serve(listener, HandlerFunc(handler))
197 }()
198
199 var req *Request
200 req = <-ch
201 if req == nil {
202 t.Fatal("Got nil first request.")
203 }
204 if req.Method != "POST" {
205 t.Errorf("For request #1's method, got %q; expected %q",
206 req.Method, "POST")
207 }
208
209 req = <-ch
210 if req == nil {
211 t.Fatal("Got nil first request.")
212 }
213 if req.Method != "POST" {
214 t.Errorf("For request #2's method, got %q; expected %q",
215 req.Method, "POST")
216 }
217
218 if serveerr := <-servech; serveerr != io.EOF {
219 t.Errorf("Serve returned %q; expected EOF", serveerr)
220 }
221 }
222
223 type stringHandler string
224
225 func (s stringHandler) ServeHTTP(w ResponseWriter, r *Request) {
226 w.Header().Set("Result", string(s))
227 }
228
229 var handlers = []struct {
230 pattern string
231 msg string
232 }{
233 {"/", "Default"},
234 {"/someDir/", "someDir"},
235 {"/#/", "hash"},
236 {"someHost.com/someDir/", "someHost.com/someDir"},
237 }
238
239 var vtests = []struct {
240 url string
241 expected string
242 }{
243 {"http://localhost/someDir/apage", "someDir"},
244 {"http://localhost/%23/apage", "hash"},
245 {"http://localhost/otherDir/apage", "Default"},
246 {"http://someHost.com/someDir/apage", "someHost.com/someDir"},
247 {"http://otherHost.com/someDir/apage", "someDir"},
248 {"http://otherHost.com/aDir/apage", "Default"},
249
250 {"http://localhost/someDir", "/someDir/"},
251 {"http://localhost/%23", "/%23/"},
252 {"http://someHost.com/someDir", "/someDir/"},
253 }
254
255 func TestHostHandlers(t *testing.T) { runSynctest(t, testHostHandlers, []testMode{http1Mode}) }
256 func testHostHandlers(t *testing.T, mode testMode) {
257 mux := NewServeMux()
258 for _, h := range handlers {
259 mux.Handle(h.pattern, stringHandler(h.msg))
260 }
261 cst := newClientServerTest(t, mode, mux)
262
263 conn, _ := cst.dialNettest()
264 defer conn.Close()
265 cc := httputil.NewClientConn(conn, nil)
266 for _, vt := range vtests {
267 var r *Response
268 var req Request
269 var err error
270 if req.URL, err = url.Parse(vt.url); err != nil {
271 t.Errorf("cannot parse url: %v", err)
272 continue
273 }
274 if err := cc.Write(&req); err != nil {
275 t.Errorf("writing request: %v", err)
276 continue
277 }
278 r, err = cc.Read(&req)
279 if err != nil {
280 t.Errorf("reading response: %v", err)
281 continue
282 }
283 switch r.StatusCode {
284 case StatusOK:
285 s := r.Header.Get("Result")
286 if s != vt.expected {
287 t.Errorf("Get(%q) = %q, want %q", vt.url, s, vt.expected)
288 }
289 case StatusTemporaryRedirect:
290 s := r.Header.Get("Location")
291 if s != vt.expected {
292 t.Errorf("Get(%q) = %q, want %q", vt.url, s, vt.expected)
293 }
294 default:
295 t.Errorf("Get(%q) unhandled status code %d", vt.url, r.StatusCode)
296 }
297 }
298 }
299
300 var serveMuxRegister = []struct {
301 pattern string
302 h Handler
303 }{
304 {"/dir/", serve(200)},
305 {"/search", serve(201)},
306 {"codesearch.google.com/search", serve(202)},
307 {"codesearch.google.com/", serve(203)},
308 {"example.com/", HandlerFunc(checkQueryStringHandler)},
309 {"/pkg/bar/extra%2fpath", serve(200)},
310 }
311
312
313 func serve(code int) HandlerFunc {
314 return func(w ResponseWriter, r *Request) {
315 w.WriteHeader(code)
316 }
317 }
318
319
320
321
322 func checkQueryStringHandler(w ResponseWriter, r *Request) {
323 u := *r.URL
324 u.Scheme = "http"
325 u.Host = r.Host
326 u.RawQuery = ""
327 if "http://"+r.URL.RawQuery == u.String() {
328 w.WriteHeader(200)
329 } else {
330 w.WriteHeader(500)
331 }
332 }
333
334 var serveMuxTests = []struct {
335 method string
336 host string
337 path string
338 code int
339 pattern string
340 }{
341 {"GET", "google.com", "/", 404, ""},
342 {"GET", "google.com", "/dir", 307, "/dir/"},
343 {"GET", "google.com", "/dir/", 200, "/dir/"},
344 {"GET", "google.com", "/dir/file", 200, "/dir/"},
345 {"GET", "google.com", "/search", 201, "/search"},
346 {"GET", "google.com", "/search/", 404, ""},
347 {"GET", "google.com", "/search/foo", 404, ""},
348 {"GET", "codesearch.google.com", "/search", 202, "codesearch.google.com/search"},
349 {"GET", "codesearch.google.com", "/search/", 203, "codesearch.google.com/"},
350 {"GET", "codesearch.google.com", "/search/foo", 203, "codesearch.google.com/"},
351 {"GET", "codesearch.google.com", "/", 203, "codesearch.google.com/"},
352 {"GET", "codesearch.google.com:443", "/", 203, "codesearch.google.com/"},
353 {"GET", "images.google.com", "/search", 201, "/search"},
354 {"GET", "images.google.com", "/search/", 404, ""},
355 {"GET", "images.google.com", "/search/foo", 404, ""},
356 {"GET", "google.com", "/../search", 307, "/search"},
357 {"GET", "google.com", "/dir/..", 307, ""},
358 {"GET", "google.com", "/dir/..", 307, ""},
359 {"GET", "google.com", "/dir/./file", 307, "/dir/"},
360
361
362
363 {"CONNECT", "google.com", "/dir", 307, "/dir/"},
364 {"CONNECT", "google.com", "/../search", 404, ""},
365 {"CONNECT", "google.com", "/dir/..", 200, "/dir/"},
366 {"CONNECT", "google.com", "/dir/..", 200, "/dir/"},
367 {"CONNECT", "google.com", "/dir/./file", 200, "/dir/"},
368 }
369
370 func TestServeMuxHandler(t *testing.T) {
371 t.Parallel()
372 mux := NewServeMux()
373 for _, e := range serveMuxRegister {
374 mux.Handle(e.pattern, e.h)
375 }
376
377 for _, tt := range serveMuxTests {
378 r := &Request{
379 Method: tt.method,
380 Host: tt.host,
381 URL: &url.URL{
382 Path: tt.path,
383 },
384 }
385 h, pattern := mux.Handler(r)
386 rr := httptest.NewRecorder()
387 h.ServeHTTP(rr, r)
388 if pattern != tt.pattern || rr.Code != tt.code {
389 t.Errorf("%s %s %s = %d, %q, want %d, %q", tt.method, tt.host, tt.path, rr.Code, pattern, tt.code, tt.pattern)
390 }
391 }
392 }
393
394
395 func TestServeMuxHandlerTrailingSlash(t *testing.T) {
396 t.Parallel()
397 mux := NewServeMux()
398 const original = "/{x}/"
399 mux.Handle(original, NotFoundHandler())
400 r, _ := NewRequest("POST", "/foo", nil)
401 _, p := mux.Handler(r)
402 if p != original {
403 t.Errorf("got %q, want %q", p, original)
404 }
405 }
406
407
408 func TestServeMuxHandleFuncWithNilHandler(t *testing.T) {
409 t.Parallel()
410 defer func() {
411 if err := recover(); err == nil {
412 t.Error("expected call to mux.HandleFunc to panic")
413 }
414 }()
415 mux := NewServeMux()
416 mux.HandleFunc("/", nil)
417 }
418
419 var serveMuxTests2 = []struct {
420 method string
421 host string
422 url string
423 code int
424 redirOk bool
425 }{
426 {"GET", "google.com", "/", 404, false},
427 {"GET", "example.com", "/test/?example.com/test/", 200, false},
428 {"GET", "example.com", "test/?example.com/test/", 200, true},
429 {"GET", "google.com", "/pkg/bar//extra%2fpath", 200, true},
430 {"GET", "google.com", "/dir/b%2fc/..", 200, true},
431 {"GET", "google.com", "/doesnotexist/b%2fc/..", 404, true},
432 }
433
434
435
436 func TestServeMuxHandlerRedirects(t *testing.T) {
437 t.Parallel()
438 mux := NewServeMux()
439 for _, e := range serveMuxRegister {
440 mux.Handle(e.pattern, e.h)
441 }
442
443 for _, tt := range serveMuxTests2 {
444 tries := 1
445 turl := tt.url
446 for {
447 u, e := url.Parse(turl)
448 if e != nil {
449 t.Fatal(e)
450 }
451 r := &Request{
452 Method: tt.method,
453 Host: tt.host,
454 URL: u,
455 }
456 h, _ := mux.Handler(r)
457 rr := httptest.NewRecorder()
458 h.ServeHTTP(rr, r)
459 if rr.Code != 307 {
460 if rr.Code != tt.code {
461 t.Errorf("%s %s %s = %d, want %d", tt.method, tt.host, tt.url, rr.Code, tt.code)
462 }
463 break
464 }
465 if !tt.redirOk {
466 t.Errorf("%s %s %s, unexpected redirect", tt.method, tt.host, tt.url)
467 break
468 }
469 turl = rr.HeaderMap.Get("Location")
470 tries--
471 }
472 if tries < 0 {
473 t.Errorf("%s %s %s, too many redirects", tt.method, tt.host, tt.url)
474 }
475 }
476 }
477
478 func TestServeMuxHandlerRedirectPost(t *testing.T) {
479 t.Parallel()
480 mux := NewServeMux()
481 mux.HandleFunc("POST /test/", func(w ResponseWriter, r *Request) {
482 w.WriteHeader(200)
483 })
484
485 var code, retries int
486 startURL := "http://example.com/test"
487 reqURL := startURL
488 for retries = 0; retries <= 1; retries++ {
489 r := httptest.NewRequest("POST", reqURL, strings.NewReader("hello world"))
490 h, _ := mux.Handler(r)
491 rr := httptest.NewRecorder()
492 h.ServeHTTP(rr, r)
493 code = rr.Code
494 switch rr.Code {
495 case 307:
496 reqURL = rr.Result().Header.Get("Location")
497 continue
498 case 200:
499
500 default:
501 t.Errorf("unhandled response code: %v", rr.Code)
502 }
503 }
504 if code != 200 {
505 t.Errorf("POST %s = %d after %d retries, want = 200", startURL, code, retries)
506 }
507 }
508
509
510 func TestMuxRedirectLeadingSlashes(t *testing.T) {
511 t.Parallel()
512 paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
513 for _, path := range paths {
514 req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
515 if err != nil {
516 t.Errorf("%s", err)
517 }
518 mux := NewServeMux()
519 resp := httptest.NewRecorder()
520
521 mux.ServeHTTP(resp, req)
522
523 if loc, expected := resp.Header().Get("Location"), "/foo.txt"; loc != expected {
524 t.Errorf("Expected Location header set to %q; got %q", expected, loc)
525 return
526 }
527
528 if code, expected := resp.Code, StatusTemporaryRedirect; code != expected {
529 t.Errorf("Expected response code of StatusPermanentRedirect; got %d", code)
530 return
531 }
532 }
533 }
534
535
536
537
538
539 func TestServeWithSlashRedirectKeepsQueryString(t *testing.T) {
540 runSynctest(t, testServeWithSlashRedirectKeepsQueryString, []testMode{http1Mode})
541 }
542 func testServeWithSlashRedirectKeepsQueryString(t *testing.T, mode testMode) {
543 writeBackQuery := func(w ResponseWriter, r *Request) {
544 if r.Method == "CONNECT" {
545 w.WriteHeader(400)
546 }
547 fmt.Fprintf(w, "%s", r.URL.RawQuery)
548 }
549
550 mux := NewServeMux()
551 mux.HandleFunc("/testOne", writeBackQuery)
552 mux.HandleFunc("/testTwo/", writeBackQuery)
553 mux.HandleFunc("/testThree", writeBackQuery)
554 mux.HandleFunc("/testThree/", func(w ResponseWriter, r *Request) {
555 w.WriteHeader(400)
556 fmt.Fprintf(w, "%s:bar", r.URL.RawQuery)
557 })
558
559 ts := newClientServerTest(t, mode, mux).ts
560
561 tests := [...]struct {
562 path string
563 method string
564 want string
565 statusOk bool
566 }{
567 0: {"/testOne?this=that", "GET", "this=that", true},
568 1: {"/testTwo?foo=bar", "GET", "foo=bar", true},
569 2: {"/testTwo?a=1&b=2&a=3", "GET", "a=1&b=2&a=3", true},
570 3: {"/testTwo?", "GET", "", true},
571 4: {"/testThree?foo", "GET", "foo", true},
572 5: {"/testThree/?foo", "GET", "foo:bar", true},
573 6: {"/testThree?foo", "CONNECT", "foo", true},
574 7: {"/testThree/?foo", "CONNECT", "foo:bar", true},
575
576
577 8: {"/testOne/foo/..?foo", "GET", "foo", true},
578 9: {"/testOne/foo/..?foo", "CONNECT", "404 page not found\n", false},
579 }
580
581 for i, tt := range tests {
582 req, _ := NewRequest(tt.method, ts.URL+tt.path, nil)
583 res, err := ts.Client().Do(req)
584 if err != nil {
585 continue
586 }
587 slurp, _ := io.ReadAll(res.Body)
588 res.Body.Close()
589 if !tt.statusOk {
590 if got, want := res.StatusCode, 404; got != want {
591 t.Errorf("#%d: Status = %d; want = %d", i, got, want)
592 }
593 }
594 if got, want := string(slurp), tt.want; got != want {
595 t.Errorf("#%d: Body = %q; want = %q", i, got, want)
596 }
597 }
598 }
599
600 func TestServeWithSlashRedirectForHostPatterns(t *testing.T) {
601 t.Parallel()
602
603 mux := NewServeMux()
604 mux.Handle("example.com/pkg/foo/", stringHandler("example.com/pkg/foo/"))
605 mux.Handle("example.com/pkg/bar", stringHandler("example.com/pkg/bar"))
606 mux.Handle("example.com/pkg/bar/", stringHandler("example.com/pkg/bar/"))
607 mux.Handle("example.com:3000/pkg/connect/", stringHandler("example.com:3000/pkg/connect/"))
608 mux.Handle("example.com:9000/", stringHandler("example.com:9000/"))
609 mux.Handle("/pkg/baz/", stringHandler("/pkg/baz/"))
610 mux.Handle("example.com/a%2fb/", stringHandler("example.com/a%2fb/"))
611
612 tests := []struct {
613 method string
614 url string
615 code int
616 loc string
617 want string
618 }{
619 {"GET", "http://example.com/", 404, "", ""},
620 {"GET", "http://example.com/pkg/foo", 307, "/pkg/foo/", ""},
621 {"GET", "http://example.com/pkg/bar", 200, "", "example.com/pkg/bar"},
622 {"GET", "http://example.com/pkg/bar/", 200, "", "example.com/pkg/bar/"},
623 {"GET", "http://example.com/pkg/baz", 307, "/pkg/baz/", ""},
624 {"GET", "http://example.com:3000/pkg/foo", 307, "/pkg/foo/", ""},
625 {"CONNECT", "http://example.com/", 404, "", ""},
626 {"CONNECT", "http://example.com:3000/", 404, "", ""},
627 {"CONNECT", "http://example.com:9000/", 200, "", "example.com:9000/"},
628 {"CONNECT", "http://example.com/pkg/foo", 307, "/pkg/foo/", ""},
629 {"CONNECT", "http://example.com:3000/pkg/foo", 404, "", ""},
630 {"CONNECT", "http://example.com:3000/pkg/baz", 307, "/pkg/baz/", ""},
631 {"CONNECT", "http://example.com:3000/pkg/connect", 307, "/pkg/connect/", ""},
632 {"GET", "http://example.com/a%2fb", 307, "/a%2fb/", ""},
633 }
634
635 for i, tt := range tests {
636 req, _ := NewRequest(tt.method, tt.url, nil)
637 w := httptest.NewRecorder()
638 mux.ServeHTTP(w, req)
639
640 if got, want := w.Code, tt.code; got != want {
641 t.Errorf("#%d: Status = %d; want = %d", i, got, want)
642 }
643
644 if tt.code == 307 {
645 if got, want := w.HeaderMap.Get("Location"), tt.loc; got != want {
646 t.Errorf("#%d: Location = %q; want = %q", i, got, want)
647 }
648 } else {
649 if got, want := w.HeaderMap.Get("Result"), tt.want; got != want {
650 t.Errorf("#%d: Result = %q; want = %q", i, got, want)
651 }
652 }
653 }
654 }
655
656
657
658
659 func TestMuxNoSlashRedirectWithTrailingSlash(t *testing.T) {
660 mux := NewServeMux()
661 mux.HandleFunc("/{x}/", func(w ResponseWriter, r *Request) {
662 fmt.Fprintln(w, "ok")
663 })
664 w := httptest.NewRecorder()
665 req, _ := NewRequest("GET", "/", nil)
666 mux.ServeHTTP(w, req)
667 if g, w := w.Code, 404; g != w {
668 t.Errorf("got %d, want %d", g, w)
669 }
670 }
671
672
673
674
675 func TestMuxNoSlash405WithTrailingSlash(t *testing.T) {
676 mux := NewServeMux()
677 mux.HandleFunc("GET /{x}/", func(w ResponseWriter, r *Request) {
678 fmt.Fprintln(w, "ok")
679 })
680 w := httptest.NewRecorder()
681 req, _ := NewRequest("GET", "/", nil)
682 mux.ServeHTTP(w, req)
683 if g, w := w.Code, 404; g != w {
684 t.Errorf("got %d, want %d", g, w)
685 }
686 }
687
688 func TestShouldRedirectConcurrency(t *testing.T) { runSynctest(t, testShouldRedirectConcurrency) }
689 func testShouldRedirectConcurrency(t *testing.T, mode testMode) {
690 mux := NewServeMux()
691 newClientServerTest(t, mode, mux)
692 mux.HandleFunc("/", func(w ResponseWriter, r *Request) {})
693 }
694
695 func BenchmarkServeMux(b *testing.B) { benchmarkServeMux(b, true) }
696 func BenchmarkServeMux_SkipServe(b *testing.B) { benchmarkServeMux(b, false) }
697 func benchmarkServeMux(b *testing.B, runHandler bool) {
698 type test struct {
699 path string
700 code int
701 req *Request
702 }
703
704
705 var tests []test
706 endpoints := []string{"search", "dir", "file", "change", "count", "s"}
707 for _, e := range endpoints {
708 for i := 200; i < 230; i++ {
709 p := fmt.Sprintf("/%s/%d/", e, i)
710 tests = append(tests, test{
711 path: p,
712 code: i,
713 req: &Request{Method: "GET", Host: "localhost", URL: &url.URL{Path: p}},
714 })
715 }
716 }
717 mux := NewServeMux()
718 for _, tt := range tests {
719 mux.Handle(tt.path, serve(tt.code))
720 }
721
722 rw := httptest.NewRecorder()
723 b.ReportAllocs()
724 b.ResetTimer()
725 for i := 0; i < b.N; i++ {
726 for _, tt := range tests {
727 *rw = httptest.ResponseRecorder{}
728 h, pattern := mux.Handler(tt.req)
729 if runHandler {
730 h.ServeHTTP(rw, tt.req)
731 if pattern != tt.path || rw.Code != tt.code {
732 b.Fatalf("got %d, %q, want %d, %q", rw.Code, pattern, tt.code, tt.path)
733 }
734 }
735 }
736 }
737 }
738
739 func TestServerTimeouts(t *testing.T) { runSynctest(t, testServerTimeouts, []testMode{http1Mode}) }
740 func testServerTimeouts(t *testing.T, mode testMode) {
741 timeout := 10 * time.Second
742
743 var reqNum atomic.Int32
744 cst := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) {
745 fmt.Fprintf(res, "req=%d", reqNum.Add(1))
746 }), func(ts *httptest.Server) {
747 ts.Config.ReadTimeout = timeout
748 ts.Config.WriteTimeout = timeout
749 })
750 defer cst.close()
751 ts := cst.ts
752
753
754 c := ts.Client()
755 r, err := c.Get(ts.URL)
756 if err != nil {
757 t.Fatalf("http Get #1: %v", err)
758 }
759 got, err := io.ReadAll(r.Body)
760 expected := "req=1"
761 if string(got) != expected || err != nil {
762 t.Fatalf("Unexpected response for request #1; got %q ,%v; expected %q, nil",
763 string(got), err, expected)
764 }
765
766
767 t1 := time.Now()
768 conn, _ := cst.dialNettest()
769 buf := make([]byte, 1)
770 n, err := conn.Read(buf)
771 conn.Close()
772 latency := time.Since(t1)
773 if n != 0 || err != io.EOF {
774 t.Fatalf("Read = %v, %v, wanted %v, %v", n, err, 0, io.EOF)
775 }
776 if latency != timeout {
777 t.Fatalf("got EOF after %s, want %s", latency, timeout)
778 }
779
780
781
782
783 r, err = c.Get(ts.URL)
784 if err != nil {
785 t.Fatalf("http Get #2: %v", err)
786 }
787 got, err = io.ReadAll(r.Body)
788 r.Body.Close()
789 expected = "req=2"
790 if string(got) != expected || err != nil {
791 t.Fatalf("Get #2 got %q, %v, want %q, nil", string(got), err, expected)
792 }
793
794 conn, _ = cst.dialNettest()
795 if err != nil {
796 t.Fatalf("long Dial: %v", err)
797 }
798 defer conn.Close()
799 go io.Copy(io.Discard, conn)
800 for i := 0; i < 5; i++ {
801 _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"))
802 if err != nil {
803 t.Fatalf("on write %d: %v", i, err)
804 }
805 time.Sleep(timeout / 2)
806 }
807 }
808
809 func TestServerUnencryptedHTTP2HeaderTimeout(t *testing.T) {
810 for _, test := range []struct {
811 name string
812 f func(*nettest.Conn)
813 }{{
814 name: "client sends nothing",
815 f: func(conn *nettest.Conn) {
816 },
817 }, {
818 name: "client sends slowly",
819 f: func(conn *nettest.Conn) {
820
821 conn.Write([]byte("PRI"))
822 time.Sleep(100 * time.Millisecond)
823 conn.Write([]byte(" * "))
824 time.Sleep(100 * time.Millisecond)
825 conn.Write([]byte("HTT"))
826 time.Sleep(100 * time.Millisecond)
827 },
828 }, {
829 name: "header read expires",
830 f: func(conn *nettest.Conn) {
831
832
833 time.Sleep(100 * time.Millisecond)
834 conn.Write([]byte("GET / HTTP/1.1\r\nHost: example.tld\r\n"))
835 },
836 }} {
837 t.Run(test.name, func(t *testing.T) {
838 synctest.Test(t, func(t *testing.T) {
839 listener := nettest.NewListener()
840 defer listener.Close()
841
842 srv := &Server{
843 Protocols: new(Protocols),
844 ReadHeaderTimeout: 1 * time.Second,
845 }
846 srv.Protocols.SetHTTP1(true)
847 srv.Protocols.SetUnencryptedHTTP2(true)
848 go srv.Serve(listener)
849
850 conn := listener.NewConn()
851 go test.f(conn)
852
853 start := time.Now()
854 _, err := io.ReadAll(conn)
855 if err != nil {
856 t.Errorf("ReadAll from server: %v, want EOF", err)
857 }
858 if got, want := time.Since(start), srv.ReadHeaderTimeout; got != want {
859 t.Errorf("connection closed after %v, want %v", got, want)
860 }
861 })
862 })
863 }
864 }
865
866
867
868
869 func TestServerRequestContextOutlivesIdleServeGoroutine(t *testing.T) {
870 runSynctest(t, testServerRequestContextOutlivesIdleServeGoroutine,
871 testAddMode{http2UnencryptedMode})
872 }
873 func testServerRequestContextOutlivesIdleServeGoroutine(t *testing.T, mode testMode) {
874 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
875
876
877 select {
878 case <-r.Context().Done():
879 w.WriteHeader(500)
880 fmt.Fprintf(w, "request context done early: %v", r.Context().Err())
881 case <-time.After(5 * time.Second):
882 io.WriteString(w, "ok")
883 }
884 }))
885 res, err := cst.c.Get(cst.ts.URL)
886 if err != nil {
887 t.Fatal(err)
888 }
889 defer res.Body.Close()
890 body, err := io.ReadAll(res.Body)
891 if err != nil {
892 t.Fatal(err)
893 }
894 if res.StatusCode != 200 || string(body) != "ok" {
895 t.Fatalf("got %d %q, want 200 %q", res.StatusCode, body, "ok")
896 }
897 }
898
899 func TestServerReadHeaderTimeoutIsCleared(t *testing.T) {
900 runSynctest(t, testServerReadHeaderTimeoutIsCleared,
901 testAddMode{http2UnencryptedMode})
902 }
903 func testServerReadHeaderTimeoutIsCleared(t *testing.T, mode testMode) {
904 const timeout = time.Second
905 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
906 w.WriteHeader(200)
907 NewResponseController(w).Flush()
908 time.Sleep(2 * timeout)
909 io.WriteString(w, "ok")
910 }), func(s *Server) {
911 s.ReadHeaderTimeout = timeout
912 })
913
914 res, err := cst.c.Get(cst.ts.URL)
915 if err != nil {
916 t.Fatal(err)
917 }
918 got, err := io.ReadAll(res.Body)
919 res.Body.Close()
920 if err != nil {
921 t.Fatalf("reading response body after ReadHeaderTimeout: %v", err)
922 }
923 if want := "ok"; string(got) != want {
924 t.Fatalf("response body = %q, want %q", got, want)
925 }
926 }
927
928 func TestServerReadTimeout(t *testing.T) { runSynctest(t, testServerReadTimeout) }
929 func testServerReadTimeout(t *testing.T, mode testMode) {
930 respBody := "response body"
931 for timeout := 5 * time.Millisecond; ; timeout *= 2 {
932 cst := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) {
933 _, err := io.Copy(io.Discard, req.Body)
934 if !errors.Is(err, os.ErrDeadlineExceeded) {
935 t.Errorf("server timed out reading request body: got err %v; want os.ErrDeadlineExceeded", err)
936 }
937 res.Write([]byte(respBody))
938 }), func(ts *httptest.Server) {
939 ts.Config.ReadHeaderTimeout = -1
940 ts.Config.ReadTimeout = timeout
941 t.Logf("Server.Config.ReadTimeout = %v", timeout)
942 })
943
944 var retries atomic.Int32
945 cst.c.Transport.(*Transport).Proxy = func(*Request) (*url.URL, error) {
946 if retries.Add(1) != 1 {
947 return nil, errors.New("too many retries")
948 }
949 return nil, nil
950 }
951
952 pr, pw := io.Pipe()
953 res, err := cst.c.Post(cst.ts.URL, "text/apocryphal", pr)
954 if err != nil {
955 t.Logf("Get error, retrying: %v", err)
956 cst.close()
957 continue
958 }
959 defer res.Body.Close()
960 got, err := io.ReadAll(res.Body)
961 if string(got) != respBody || err != nil {
962 t.Errorf("client read response body: %q, %v; want %q, nil", string(got), err, respBody)
963 }
964 pw.Close()
965 break
966 }
967 }
968
969 func TestServerNoReadTimeout(t *testing.T) { runSynctest(t, testServerNoReadTimeout) }
970 func testServerNoReadTimeout(t *testing.T, mode testMode) {
971 reqBody := "Hello, Gophers!"
972 resBody := "Hi, Gophers!"
973 for _, timeout := range []time.Duration{0, -1} {
974 cst := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) {
975 ctl := NewResponseController(res)
976 ctl.EnableFullDuplex()
977 res.WriteHeader(StatusOK)
978
979
980 if err := ctl.Flush(); err != nil {
981 t.Errorf("server flush response: %v", err)
982 return
983 }
984 got, err := io.ReadAll(req.Body)
985 if string(got) != reqBody || err != nil {
986 t.Errorf("server read request body: %v; got %q, want %q", err, got, reqBody)
987 }
988 res.Write([]byte(resBody))
989 }), func(ts *httptest.Server) {
990 ts.Config.ReadTimeout = timeout
991 t.Logf("Server.Config.ReadTimeout = %d", timeout)
992 })
993
994 pr, pw := io.Pipe()
995 res, err := cst.c.Post(cst.ts.URL, "text/plain", pr)
996 if err != nil {
997 t.Fatal(err)
998 }
999 defer res.Body.Close()
1000
1001
1002 time.Sleep(10 * time.Millisecond)
1003 pw.Write([]byte(reqBody))
1004 pw.Close()
1005
1006 got, err := io.ReadAll(res.Body)
1007 if string(got) != resBody || err != nil {
1008 t.Errorf("client read response body: %v; got %v, want %q", err, got, resBody)
1009 }
1010 }
1011 }
1012
1013 func TestServerWriteTimeout(t *testing.T) { runSynctest(t, testServerWriteTimeout) }
1014 func testServerWriteTimeout(t *testing.T, mode testMode) {
1015 const timeout = 1 * time.Second
1016 handlerDone := false
1017 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, req *Request) {
1018 if n, err := io.Copy(w, neverEnding('a')); !errors.Is(err, os.ErrDeadlineExceeded) {
1019 t.Errorf("handler: io.Copy(w, ...) = %v, %v; wanted os.ErrDeadlineExceeded", n, err)
1020 }
1021 handlerDone = true
1022 }), func(ts *httptest.Server) {
1023 ts.Config.WriteTimeout = timeout
1024 }, func(tr *Transport) {
1025 tr.HTTP2 = &HTTP2Config{
1026 MaxReceiveBufferPerStream: 1024,
1027 }
1028 })
1029
1030 cst.setDialNettestHook(func(nc *nettest.Conn) {
1031 nc.SetReadBufferSize(1)
1032 })
1033
1034 resp, err := cst.c.Get(cst.ts.URL)
1035 if err != nil {
1036 t.Fatalf("Get: %v", err)
1037 }
1038 defer resp.Body.Close()
1039
1040 buf := make([]byte, 16)
1041 if _, err := io.ReadFull(resp.Body, buf); err != nil {
1042 t.Fatalf("client reading %v bytes of body: %v, want success", len(buf), err)
1043 }
1044 if got, want := string(buf), strings.Repeat("a", len(buf)); got != want {
1045 t.Fatalf("client read %q, want %q", got, want)
1046 }
1047
1048 synctest.Sleep(timeout + time.Nanosecond)
1049 if !handlerDone {
1050 t.Errorf("handler still running after timeout")
1051 }
1052 if _, err := io.Copy(io.Discard, resp.Body); err == nil {
1053 t.Errorf("client reading from truncated request body: got nil error, want non-nil")
1054 }
1055 }
1056
1057 func TestServerNoWriteTimeout(t *testing.T) { runSynctest(t, testServerNoWriteTimeout) }
1058 func testServerNoWriteTimeout(t *testing.T, mode testMode) {
1059 sendBuf := bytes.Repeat([]byte("a"), 1024)
1060 sent := 0
1061 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, req *Request) {
1062 for {
1063 n, err := w.Write(sendBuf)
1064 if err != nil {
1065 break
1066 }
1067 sent += n
1068 }
1069 }), func(tr *Transport) {
1070 tr.HTTP2 = &HTTP2Config{
1071 MaxReceiveBufferPerStream: 4096,
1072 }
1073 })
1074
1075 cst.setDialNettestHook(func(nc *nettest.Conn) {
1076 nc.SetReadBufferSize(1024)
1077 })
1078
1079 resp, err := cst.c.Get(cst.ts.URL)
1080 if err != nil {
1081 t.Fatalf("Get: %v", err)
1082 }
1083 defer resp.Body.Close()
1084
1085
1086
1087 synctest.Sleep(10 * time.Second)
1088 sendBuf = bytes.Repeat([]byte("b"), len(sendBuf))
1089
1090
1091 skip := int64(sent + len(sendBuf))
1092 if _, err := io.CopyN(io.Discard, resp.Body, skip); err != nil {
1093 t.Fatalf("client reading %v bytes of body: %v, want success", skip, err)
1094 }
1095
1096
1097 readBuf := make([]byte, len(sendBuf))
1098 if _, err := io.ReadFull(resp.Body, readBuf); err != nil {
1099 t.Fatalf("client reading post-sleep body: %v, want success", err)
1100 }
1101 if !bytes.Equal(readBuf, sendBuf) {
1102 t.Fatalf("client reading post-sleep body: body content mismatch")
1103 }
1104 }
1105
1106
1107 func TestWriteDeadlineExtendedOnNewRequest(t *testing.T) {
1108 runSynctest(t, testWriteDeadlineExtendedOnNewRequest)
1109 }
1110 func testWriteDeadlineExtendedOnNewRequest(t *testing.T, mode testMode) {
1111 ts := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) {}),
1112 func(ts *httptest.Server) {
1113 ts.Config.WriteTimeout = 250 * time.Millisecond
1114 },
1115 ).ts
1116
1117 c := ts.Client()
1118
1119 for i := 1; i <= 3; i++ {
1120 req, err := NewRequest("GET", ts.URL, nil)
1121 if err != nil {
1122 t.Fatal(err)
1123 }
1124
1125 r, err := c.Do(req)
1126 if err != nil {
1127 t.Fatalf("http2 Get #%d: %v", i, err)
1128 }
1129 r.Body.Close()
1130 time.Sleep(ts.Config.WriteTimeout / 2)
1131 }
1132 }
1133
1134
1135 func TestWriteDeadlineEnforcedPerStream(t *testing.T) {
1136 runSynctest(t, testWriteDeadlineEnforcedPerStream)
1137 }
1138 func testWriteDeadlineEnforcedPerStream(t *testing.T, mode testMode) {
1139 timeout := 1 * time.Second
1140
1141 firstRequest := make(chan bool, 1)
1142 cst := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) {
1143 select {
1144 case firstRequest <- true:
1145
1146 default:
1147
1148 time.Sleep(timeout)
1149 }
1150 }), func(ts *httptest.Server) {
1151 ts.Config.WriteTimeout = timeout / 2
1152 })
1153 defer cst.close()
1154 ts := cst.ts
1155
1156 c := ts.Client()
1157
1158 req, err := NewRequest("GET", ts.URL, nil)
1159 if err != nil {
1160 t.Fatalf("NewRequest: %v", err)
1161 }
1162 r, err := c.Do(req)
1163 if err != nil {
1164 t.Fatalf("Get #1: %v", err)
1165 }
1166 r.Body.Close()
1167
1168 req, err = NewRequest("GET", ts.URL, nil)
1169 if err != nil {
1170 t.Fatalf("NewRequest: %v", err)
1171 }
1172 r, err = c.Do(req)
1173 if err == nil {
1174 r.Body.Close()
1175 t.Fatalf("Get #2 expected error, got nil")
1176 }
1177 if mode == http2Mode {
1178 expected := "stream ID 3; INTERNAL_ERROR"
1179 if !strings.Contains(err.Error(), expected) {
1180 t.Fatalf("http2 Get #2: expected error to contain %q, got %q", expected, err)
1181 }
1182 }
1183 time.Sleep(timeout)
1184 }
1185
1186
1187 func TestNoWriteDeadline(t *testing.T) { runSynctest(t, testNoWriteDeadline) }
1188 func testNoWriteDeadline(t *testing.T, mode testMode) {
1189 timeout := time.Second
1190
1191 firstRequest := make(chan bool, 1)
1192 cst := newClientServerTest(t, mode, HandlerFunc(func(res ResponseWriter, req *Request) {
1193 select {
1194 case firstRequest <- true:
1195
1196 default:
1197
1198 time.Sleep(timeout)
1199 }
1200 }))
1201 defer cst.close()
1202 ts := cst.ts
1203
1204 c := ts.Client()
1205
1206 for i := 0; i < 2; i++ {
1207 req, err := NewRequest("GET", ts.URL, nil)
1208 if err != nil {
1209 t.Fatalf("NewRequest: %v", err)
1210 }
1211 r, err := c.Do(req)
1212 if err != nil {
1213 t.Fatalf("Get #%d: %v", i, err)
1214 }
1215 r.Body.Close()
1216 }
1217 }
1218
1219
1220
1221
1222 func TestOnlyWriteTimeout(t *testing.T) {
1223 var (
1224 mu sync.RWMutex
1225 conn net.Conn
1226 )
1227 var afterTimeoutErrc = make(chan error, 1)
1228 ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, req *Request) {
1229 buf := make([]byte, 512<<10)
1230 _, err := w.Write(buf)
1231 if err != nil {
1232 t.Errorf("handler Write error: %v", err)
1233 return
1234 }
1235 mu.RLock()
1236 defer mu.RUnlock()
1237 if conn == nil {
1238 t.Error("no established connection found")
1239 return
1240 }
1241 conn.SetWriteDeadline(time.Now().Add(-30 * time.Second))
1242 _, err = w.Write(buf)
1243 afterTimeoutErrc <- err
1244 }))
1245 ts.Listener = trackLastConnListener{ts.Listener, &mu, &conn}
1246 ts.Start()
1247 defer ts.Close()
1248 c := ts.Client()
1249
1250 err := func() error {
1251 res, err := c.Get(ts.URL)
1252 if err != nil {
1253 return err
1254 }
1255 _, err = io.Copy(io.Discard, res.Body)
1256 res.Body.Close()
1257 return err
1258 }()
1259 if err == nil {
1260 t.Errorf("expected an error copying body from Get request")
1261 }
1262
1263 if err := <-afterTimeoutErrc; err == nil {
1264 t.Error("expected write error after timeout")
1265 }
1266 }
1267
1268
1269 type trackLastConnListener struct {
1270 net.Listener
1271
1272 mu *sync.RWMutex
1273 last *net.Conn
1274 }
1275
1276 func (l trackLastConnListener) Accept() (c net.Conn, err error) {
1277 c, err = l.Listener.Accept()
1278 if err == nil {
1279 l.mu.Lock()
1280 *l.last = c
1281 l.mu.Unlock()
1282 }
1283 return
1284 }
1285
1286
1287 func TestIdentityResponse(t *testing.T) { runSynctest(t, testIdentityResponse) }
1288 func testIdentityResponse(t *testing.T, mode testMode) {
1289 if mode == http2Mode {
1290 t.Skip("https://go.dev/issue/56019")
1291 }
1292
1293 handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
1294 rw.Header().Set("Content-Length", "3")
1295 rw.Header().Set("Transfer-Encoding", req.FormValue("te"))
1296 switch {
1297 case req.FormValue("overwrite") == "1":
1298 _, err := rw.Write([]byte("foo TOO LONG"))
1299 if err != ErrContentLength {
1300 t.Errorf("expected ErrContentLength; got %v", err)
1301 }
1302 default:
1303 rw.Write([]byte("foo"))
1304 }
1305 })
1306
1307 ts := newClientServerTest(t, mode, handler).ts
1308 c := ts.Client()
1309
1310
1311
1312
1313
1314 for _, te := range []string{"", "identity"} {
1315 url := ts.URL + "/?te=" + te
1316 res, err := c.Get(url)
1317 if err != nil {
1318 t.Fatalf("error with Get of %s: %v", url, err)
1319 }
1320 if cl, expected := res.ContentLength, int64(3); cl != expected {
1321 t.Errorf("for %s expected res.ContentLength of %d; got %d", url, expected, cl)
1322 }
1323 if cl, expected := res.Header.Get("Content-Length"), "3"; cl != expected {
1324 t.Errorf("for %s expected Content-Length header of %q; got %q", url, expected, cl)
1325 }
1326 if tl, expected := len(res.TransferEncoding), 0; tl != expected {
1327 t.Errorf("for %s expected len(res.TransferEncoding) of %d; got %d (%v)",
1328 url, expected, tl, res.TransferEncoding)
1329 }
1330 res.Body.Close()
1331 }
1332
1333
1334 url := ts.URL + "/?overwrite=1"
1335 res, err := c.Get(url)
1336 if err != nil {
1337 t.Fatalf("error with Get of %s: %v", url, err)
1338 }
1339 res.Body.Close()
1340 }
1341
1342 func TestHTTP1ServerIdentityResponse(t *testing.T) {
1343 synctest.Test(t, func(t *testing.T) {
1344
1345
1346 st := newHTTP1ServerTest(t, func(w ResponseWriter, req *Request) {
1347 w.Header().Set("Content-Length", "500")
1348 w.Write([]byte("too short"))
1349 })
1350
1351 conn := st.dial()
1352 conn.writeMessage(
1353 "GET / HTTP/1.1",
1354 "Host: foo",
1355 "",
1356 )
1357 conn.readResponse()
1358 conn.wantBytes([]byte("too short"))
1359 conn.wantClosed()
1360 })
1361 }
1362
1363 func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
1364 t.Parallel()
1365 synctest.Test(t, func(t *testing.T) {
1366 cst := newClientServerTest(t, http1Mode, h)
1367
1368 conn, _ := cst.dialNettest()
1369 defer conn.Close()
1370
1371 _, err := fmt.Fprint(conn, req)
1372 if err != nil {
1373 t.Fatal("print error:", err)
1374 }
1375
1376 r := bufio.NewReader(conn)
1377 res, err := ReadResponse(r, &Request{Method: "GET"})
1378 if err != nil {
1379 t.Fatal("ReadResponse error:", err)
1380 }
1381
1382 _, err = io.ReadAll(r)
1383 if err != nil {
1384 t.Fatal("read error:", err)
1385 }
1386
1387 if !res.Close {
1388 t.Errorf("Response.Close = false; want true")
1389 }
1390 })
1391 }
1392
1393 func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) {
1394 t.Parallel()
1395 synctest.Test(t, func(t *testing.T) {
1396 cst := newClientServerTest(t, http1Mode, handler)
1397 conn, _ := cst.dialNettest()
1398 defer conn.Close()
1399 br := bufio.NewReader(conn)
1400 for i := 0; i < 2; i++ {
1401 if _, err := io.WriteString(conn, req); err != nil {
1402 t.Fatal(err)
1403 }
1404 res, err := ReadResponse(br, nil)
1405 if err != nil {
1406 t.Fatalf("res %d: %v", i+1, err)
1407 }
1408 if _, err := io.Copy(io.Discard, res.Body); err != nil {
1409 t.Fatalf("res %d body copy: %v", i+1, err)
1410 }
1411 res.Body.Close()
1412 }
1413 })
1414 }
1415
1416
1417 func TestServeHTTP10Close(t *testing.T) {
1418 testTCPConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
1419 ServeFile(w, r, "testdata/file")
1420 }))
1421 }
1422
1423
1424 func TestClientCanClose(t *testing.T) {
1425 testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
1426
1427 }))
1428 }
1429
1430
1431
1432 func TestHandlersCanSetConnectionClose11(t *testing.T) {
1433 testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
1434 w.Header().Set("Connection", "close")
1435 }))
1436 }
1437
1438 func TestHandlersCanSetConnectionClose10(t *testing.T) {
1439 testTCPConnectionCloses(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
1440 w.Header().Set("Connection", "close")
1441 }))
1442 }
1443
1444 func TestHTTP2UpgradeClosesConnection(t *testing.T) {
1445 testTCPConnectionCloses(t, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
1446
1447
1448 }))
1449 }
1450
1451 func send204(w ResponseWriter, r *Request) { w.WriteHeader(204) }
1452 func send304(w ResponseWriter, r *Request) { w.WriteHeader(304) }
1453
1454
1455 func TestHTTP10KeepAlive204Response(t *testing.T) {
1456 testTCPConnectionStaysOpen(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(send204))
1457 }
1458
1459 func TestHTTP11KeepAlive204Response(t *testing.T) {
1460 testTCPConnectionStaysOpen(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n", HandlerFunc(send204))
1461 }
1462
1463 func TestHTTP10KeepAlive304Response(t *testing.T) {
1464 testTCPConnectionStaysOpen(t,
1465 "GET / HTTP/1.0\r\nConnection: keep-alive\r\nIf-Modified-Since: Mon, 02 Jan 2006 15:04:05 GMT\r\n\r\n",
1466 HandlerFunc(send304))
1467 }
1468
1469
1470 func TestKeepAliveFinalChunkWithEOF(t *testing.T) { runSynctest(t, testKeepAliveFinalChunkWithEOF) }
1471 func testKeepAliveFinalChunkWithEOF(t *testing.T, mode testMode) {
1472 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1473 w.(Flusher).Flush()
1474 w.Write([]byte("{\"Addr\": \"" + r.RemoteAddr + "\"}"))
1475 }))
1476 type data struct {
1477 Addr string
1478 }
1479 var addrs [2]data
1480 for i := range addrs {
1481 res, err := cst.c.Get(cst.ts.URL)
1482 if err != nil {
1483 t.Fatal(err)
1484 }
1485 if err := json.NewDecoder(res.Body).Decode(&addrs[i]); err != nil {
1486 t.Fatal(err)
1487 }
1488 if addrs[i].Addr == "" {
1489 t.Fatal("no address")
1490 }
1491 res.Body.Close()
1492 }
1493 if addrs[0] != addrs[1] {
1494 t.Fatalf("connection not reused")
1495 }
1496 }
1497
1498 func TestSetsRemoteAddr(t *testing.T) { runSynctest(t, testSetsRemoteAddr) }
1499 func testSetsRemoteAddr(t *testing.T, mode testMode) {
1500 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1501 fmt.Fprintf(w, "%s", r.RemoteAddr)
1502 }))
1503
1504 res, err := cst.c.Get(cst.ts.URL)
1505 if err != nil {
1506 t.Fatalf("Get error: %v", err)
1507 }
1508 body, err := io.ReadAll(res.Body)
1509 if err != nil {
1510 t.Fatalf("ReadAll error: %v", err)
1511 }
1512 ip := string(body)
1513
1514
1515
1516 want := "192.0.2.1"
1517 if !strings.HasPrefix(ip, want+":") && !strings.HasPrefix(ip, "[::1]:") {
1518 t.Fatalf("got RemoteAddr %q, want %q", ip, want)
1519 }
1520 }
1521
1522 type blockingRemoteAddrListener struct {
1523 net.Listener
1524 conns chan<- net.Conn
1525 }
1526
1527 func (l *blockingRemoteAddrListener) Accept() (net.Conn, error) {
1528 c, err := l.Listener.Accept()
1529 if err != nil {
1530 return nil, err
1531 }
1532 brac := &blockingRemoteAddrConn{
1533 Conn: c,
1534 addrs: make(chan net.Addr, 1),
1535 }
1536 l.conns <- brac
1537 return brac, nil
1538 }
1539
1540 type blockingRemoteAddrConn struct {
1541 net.Conn
1542 addrs chan net.Addr
1543 }
1544
1545 func (c *blockingRemoteAddrConn) RemoteAddr() net.Addr {
1546 return <-c.addrs
1547 }
1548
1549
1550 func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
1551 conns := make(chan net.Conn)
1552 ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
1553 fmt.Fprintf(w, "RA:%s", r.RemoteAddr)
1554 }))
1555 ts.Listener = &blockingRemoteAddrListener{
1556 Listener: ts.Listener,
1557 conns: conns,
1558 }
1559 ts.Start()
1560 defer ts.Close()
1561
1562 c := ts.Client()
1563
1564 c.Transport.(*Transport).DisableKeepAlives = true
1565
1566 fetch := func(num int, response chan<- string) {
1567 resp, err := c.Get(ts.URL)
1568 if err != nil {
1569 t.Errorf("Request %d: %v", num, err)
1570 response <- ""
1571 return
1572 }
1573 defer resp.Body.Close()
1574 body, err := io.ReadAll(resp.Body)
1575 if err != nil {
1576 t.Errorf("Request %d: %v", num, err)
1577 response <- ""
1578 return
1579 }
1580 response <- string(body)
1581 }
1582
1583
1584 response1c := make(chan string, 1)
1585 go fetch(1, response1c)
1586
1587
1588 conn1 := <-conns
1589
1590
1591 response2c := make(chan string, 1)
1592 go fetch(2, response2c)
1593 conn2 := <-conns
1594
1595
1596 conn2.(*blockingRemoteAddrConn).addrs <- &net.TCPAddr{
1597 IP: net.ParseIP("12.12.12.12"), Port: 12}
1598
1599
1600 response2 := <-response2c
1601 if g, e := response2, "RA:12.12.12.12:12"; g != e {
1602 t.Fatalf("response 2 addr = %q; want %q", g, e)
1603 }
1604
1605
1606 conn1.(*blockingRemoteAddrConn).addrs <- &net.TCPAddr{
1607 IP: net.ParseIP("21.21.21.21"), Port: 21}
1608
1609
1610 response1 := <-response1c
1611 if g, e := response1, "RA:21.21.21.21:21"; g != e {
1612 t.Fatalf("response 1 addr = %q; want %q", g, e)
1613 }
1614 }
1615
1616
1617
1618 func TestHeadResponses(t *testing.T) { runSynctest(t, testHeadResponses) }
1619 func testHeadResponses(t *testing.T, mode testMode) {
1620 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1621 _, err := w.Write([]byte("<html>"))
1622 if err != nil {
1623 t.Errorf("ResponseWriter.Write: %v", err)
1624 }
1625
1626
1627 _, err = io.Copy(w, struct{ io.Reader }{strings.NewReader("789a")})
1628 if err != nil {
1629 t.Errorf("Copy(ResponseWriter, ...): %v", err)
1630 }
1631 }))
1632 res, err := cst.c.Head(cst.ts.URL)
1633 if err != nil {
1634 t.Error(err)
1635 }
1636 if len(res.TransferEncoding) > 0 {
1637 t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
1638 }
1639 if ct := res.Header.Get("Content-Type"); ct != "text/html; charset=utf-8" {
1640 t.Errorf("Content-Type: %q; want text/html; charset=utf-8", ct)
1641 }
1642
1643 if v := res.ContentLength; v != 10 && mode != http3Mode {
1644 t.Errorf("Content-Length: %d; want 10", v)
1645 }
1646 body, err := io.ReadAll(res.Body)
1647 if err != nil {
1648 t.Error(err)
1649 }
1650 if len(body) > 0 {
1651 t.Errorf("got unexpected body %q", string(body))
1652 }
1653 }
1654
1655
1656
1657 func TestHeadReaderFrom(t *testing.T) { runSynctest(t, testHeadReaderFrom, []testMode{http1Mode}) }
1658 func testHeadReaderFrom(t *testing.T, mode testMode) {
1659
1660 wantBody := strings.Repeat("a", 4096)
1661 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1662 w.(io.ReaderFrom).ReadFrom(strings.NewReader(wantBody))
1663 }))
1664 res, err := cst.c.Head(cst.ts.URL)
1665 if err != nil {
1666 t.Fatal(err)
1667 }
1668 res.Body.Close()
1669 res, err = cst.c.Get(cst.ts.URL)
1670 if err != nil {
1671 t.Fatal(err)
1672 }
1673 gotBody, err := io.ReadAll(res.Body)
1674 res.Body.Close()
1675 if err != nil {
1676 t.Fatal(err)
1677 }
1678 if string(gotBody) != wantBody {
1679 t.Errorf("got unexpected body len=%v, want %v", len(gotBody), len(wantBody))
1680 }
1681 }
1682
1683
1684
1685 func TestReaderFromTooLong(t *testing.T) {
1686 runNoSynctest(t, testReaderFromTooLong, []testMode{http1Mode})
1687 }
1688 func testReaderFromTooLong(t *testing.T, mode testMode) {
1689 contentLen := 600
1690 tests := []struct {
1691 name string
1692 reader io.Reader
1693 wantHandlerErr error
1694 }{
1695 {
1696 name: "reader of correct length",
1697 reader: strings.NewReader(strings.Repeat("a", contentLen)),
1698 },
1699 {
1700 name: "wrapped reader of correct outer length",
1701 reader: io.LimitReader(strings.NewReader(strings.Repeat("a", 2*contentLen)), int64(contentLen)),
1702 },
1703 {
1704 name: "wrapped reader of correct inner length",
1705 reader: io.LimitReader(io.LimitReader(strings.NewReader(strings.Repeat("a", 2*contentLen)), int64(contentLen)), int64(2*contentLen)),
1706 },
1707 {
1708 name: "reader that is too long",
1709 reader: strings.NewReader(strings.Repeat("a", 2*contentLen)),
1710 wantHandlerErr: ErrContentLength,
1711 },
1712 {
1713 name: "wrapped reader that is too long",
1714 reader: io.LimitReader(strings.NewReader(strings.Repeat("a", 2*contentLen)), int64(2*contentLen)),
1715 wantHandlerErr: ErrContentLength,
1716 },
1717 }
1718
1719 for _, tc := range tests {
1720 t.Run(tc.name, func(t *testing.T) {
1721
1722
1723 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1724 w.Header().Set("Content-Length", strconv.Itoa(contentLen))
1725 n, err := w.(io.ReaderFrom).ReadFrom(tc.reader)
1726 if int(n) != contentLen || !errors.Is(err, tc.wantHandlerErr) {
1727 t.Errorf("got %v, %v from w.ReadFrom; want %v, %v", n, err, contentLen, tc.wantHandlerErr)
1728 }
1729 }), optRealNet)
1730 res, err := cst.c.Get(cst.ts.URL)
1731 if err != nil {
1732 t.Fatal(err)
1733 }
1734 defer res.Body.Close()
1735 gotBody, err := io.ReadAll(res.Body)
1736 if err != nil {
1737 t.Fatal(err)
1738 }
1739 if len(gotBody) != contentLen {
1740 t.Errorf("got unexpected body len=%v, want %v", len(gotBody), contentLen)
1741 }
1742 })
1743 }
1744 }
1745
1746 func TestTLSHandshakeTimeout(t *testing.T) {
1747 runSynctest(t, testTLSHandshakeTimeout, []testMode{https1Mode, http2Mode})
1748 }
1749 func testTLSHandshakeTimeout(t *testing.T, mode testMode) {
1750 errLog := new(strings.Builder)
1751 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}),
1752 func(ts *httptest.Server) {
1753 ts.Config.ReadTimeout = 250 * time.Millisecond
1754 ts.Config.ErrorLog = log.New(errLog, "", 0)
1755 },
1756 )
1757
1758 start := time.Now()
1759 _, conn := cst.dialNettest()
1760 var buf [1]byte
1761 n, err := conn.Read(buf[:])
1762 if err == nil || n != 0 {
1763 t.Errorf("Read = %d, %v; want an error and no bytes", n, err)
1764 }
1765 conn.Close()
1766 if got, want := time.Since(start), cst.ts.Config.ReadTimeout; got != want {
1767 t.Errorf("read took %v, want TLS handshake timeout after %v", got, want)
1768 }
1769
1770 cst.close()
1771 if v := errLog.String(); !strings.Contains(v, "timeout") && !strings.Contains(v, "TLS handshake") {
1772 t.Errorf("expected a TLS handshake timeout error; got %q", v)
1773 }
1774 }
1775
1776 func TestTLSServer(t *testing.T) { runSynctest(t, testTLSServer, []testMode{https1Mode, http2Mode}) }
1777 func testTLSServer(t *testing.T, mode testMode) {
1778 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1779 if r.TLS != nil {
1780 w.Header().Set("X-TLS-Set", "true")
1781 if r.TLS.HandshakeComplete {
1782 w.Header().Set("X-TLS-HandshakeComplete", "true")
1783 }
1784 }
1785 }), func(ts *httptest.Server) {
1786 ts.Config.ErrorLog = log.New(io.Discard, "", 0)
1787 })
1788 ts := cst.ts
1789
1790
1791
1792
1793
1794
1795 _, idleConn := cst.dialNettest()
1796 defer idleConn.Close()
1797
1798 if !strings.HasPrefix(ts.URL, "https://") {
1799 t.Errorf("expected test TLS server to start with https://, got %q", ts.URL)
1800 return
1801 }
1802 client := ts.Client()
1803 res, err := client.Get(ts.URL)
1804 if err != nil {
1805 t.Error(err)
1806 return
1807 }
1808 if res == nil {
1809 t.Errorf("got nil Response")
1810 return
1811 }
1812 defer res.Body.Close()
1813 if res.Header.Get("X-TLS-Set") != "true" {
1814 t.Errorf("expected X-TLS-Set response header")
1815 return
1816 }
1817 if res.Header.Get("X-TLS-HandshakeComplete") != "true" {
1818 t.Errorf("expected X-TLS-HandshakeComplete header")
1819 }
1820 }
1821
1822 type fakeConnectionStateConn struct {
1823 net.Conn
1824 }
1825
1826 func (fcsc *fakeConnectionStateConn) ConnectionState() tls.ConnectionState {
1827 return tls.ConnectionState{
1828 ServerName: "example.com",
1829 }
1830 }
1831
1832 func TestTLSServerWithoutTLSConn(t *testing.T) {
1833
1834 pr, pw := net.Pipe()
1835 c := make(chan int)
1836 listener := &oneConnListener{&fakeConnectionStateConn{pr}}
1837 server := &Server{
1838 Handler: HandlerFunc(func(writer ResponseWriter, request *Request) {
1839 if request.TLS == nil {
1840 t.Fatal("request.TLS is nil, expected not nil")
1841 }
1842 if request.TLS.ServerName != "example.com" {
1843 t.Fatalf("request.TLS.ServerName is %s, expected %s", request.TLS.ServerName, "example.com")
1844 }
1845 writer.Header().Set("X-TLS-ServerName", "example.com")
1846 }),
1847 }
1848
1849
1850 go func() {
1851 req, _ := NewRequest(MethodGet, "https://example.com", nil)
1852 req.Write(pw)
1853
1854 resp, _ := ReadResponse(bufio.NewReader(pw), req)
1855 if hdr := resp.Header.Get("X-TLS-ServerName"); hdr != "example.com" {
1856 t.Errorf("response header X-TLS-ServerName is %s, expected %s", hdr, "example.com")
1857 }
1858 close(c)
1859 pw.Close()
1860 }()
1861
1862 server.Serve(listener)
1863
1864
1865 <-c
1866 pr.Close()
1867 }
1868
1869 func TestServeTLS(t *testing.T) {
1870 CondSkipHTTP2(t)
1871
1872 defer SetTestHookServerServe(nil)
1873
1874 cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
1875 if err != nil {
1876 t.Fatal(err)
1877 }
1878 tlsConf := &tls.Config{
1879 Certificates: []tls.Certificate{cert},
1880 }
1881
1882 ln := newLocalListener(t)
1883 defer ln.Close()
1884 addr := ln.Addr().String()
1885
1886 serving := make(chan bool, 1)
1887 SetTestHookServerServe(func(s *Server, ln net.Listener) {
1888 serving <- true
1889 })
1890 handler := HandlerFunc(func(w ResponseWriter, r *Request) {})
1891 s := &Server{
1892 Addr: addr,
1893 TLSConfig: tlsConf,
1894 Handler: handler,
1895 }
1896 errc := make(chan error, 1)
1897 go func() { errc <- s.ServeTLS(ln, "", "") }()
1898 select {
1899 case err := <-errc:
1900 t.Fatalf("ServeTLS: %v", err)
1901 case <-serving:
1902 }
1903
1904 c, err := tls.Dial("tcp", ln.Addr().String(), &tls.Config{
1905 InsecureSkipVerify: true,
1906 NextProtos: []string{"h2", "http/1.1"},
1907 })
1908 if err != nil {
1909 t.Fatal(err)
1910 }
1911 defer c.Close()
1912 if got, want := c.ConnectionState().NegotiatedProtocol, "h2"; got != want {
1913 t.Errorf("NegotiatedProtocol = %q; want %q", got, want)
1914 }
1915 if got, want := c.ConnectionState().NegotiatedProtocolIsMutual, true; got != want {
1916 t.Errorf("NegotiatedProtocolIsMutual = %v; want %v", got, want)
1917 }
1918 }
1919
1920
1921 func TestTLSServerRejectHTTPRequests(t *testing.T) {
1922 runSynctest(t, testTLSServerRejectHTTPRequests, []testMode{https1Mode, http2Mode})
1923 }
1924 func testTLSServerRejectHTTPRequests(t *testing.T, mode testMode) {
1925 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1926 t.Error("unexpected HTTPS request")
1927 }), func(ts *httptest.Server) {
1928 var errBuf bytes.Buffer
1929 ts.Config.ErrorLog = log.New(&errBuf, "", 0)
1930 })
1931 _, conn := cst.dialNettest()
1932 defer conn.Close()
1933 io.WriteString(conn, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
1934 slurp, err := io.ReadAll(conn)
1935 if err != nil {
1936 t.Fatal(err)
1937 }
1938 const wantPrefix = "HTTP/1.0 400 Bad Request\r\n"
1939 if !strings.HasPrefix(string(slurp), wantPrefix) {
1940 t.Errorf("response = %q; wanted prefix %q", slurp, wantPrefix)
1941 }
1942 }
1943
1944
1945 func TestAutomaticHTTP2_Serve_NoTLSConfig(t *testing.T) {
1946 testAutomaticHTTP2_Serve(t, nil, true)
1947 }
1948
1949 func TestAutomaticHTTP2_Serve_NonH2TLSConfig(t *testing.T) {
1950 testAutomaticHTTP2_Serve(t, &tls.Config{}, false)
1951 }
1952
1953 func TestAutomaticHTTP2_Serve_H2TLSConfig(t *testing.T) {
1954 testAutomaticHTTP2_Serve(t, &tls.Config{NextProtos: []string{"h2"}}, true)
1955 }
1956
1957 func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) {
1958 CondSkipHTTP2(t)
1959 t.Parallel()
1960 ln := newLocalListener(t)
1961 ln.Close()
1962 var s Server
1963 s.TLSConfig = tlsConf
1964 if err := s.Serve(ln); err == nil {
1965 t.Fatal("expected an error")
1966 }
1967 gotH2 := s.TLSNextProto["h2"] != nil
1968 if gotH2 != wantH2 {
1969 t.Errorf("http2 configured = %v; want %v", gotH2, wantH2)
1970 }
1971 }
1972
1973 func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) {
1974 CondSkipHTTP2(t)
1975 t.Parallel()
1976 ln := newLocalListener(t)
1977 ln.Close()
1978 var s Server
1979
1980
1981 s.TLSConfig = &tls.Config{
1982 NextProtos: []string{"h2"},
1983 }
1984 if err := s.Serve(ln); err == nil {
1985 t.Fatal("expected an error")
1986 }
1987 on := s.TLSNextProto["h2"] != nil
1988 if !on {
1989 t.Errorf("http2 wasn't automatically enabled")
1990 }
1991 }
1992
1993 func TestAutomaticHTTP2_ListenAndServe(t *testing.T) {
1994 cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
1995 if err != nil {
1996 t.Fatal(err)
1997 }
1998 testAutomaticHTTP2_ListenAndServe(t, &tls.Config{
1999 Certificates: []tls.Certificate{cert},
2000 })
2001 }
2002
2003 func TestAutomaticHTTP2_ListenAndServe_GetCertificate(t *testing.T) {
2004 cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
2005 if err != nil {
2006 t.Fatal(err)
2007 }
2008 testAutomaticHTTP2_ListenAndServe(t, &tls.Config{
2009 GetCertificate: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
2010 return &cert, nil
2011 },
2012 })
2013 }
2014
2015 func TestAutomaticHTTP2_ListenAndServe_GetConfigForClient(t *testing.T) {
2016 cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
2017 if err != nil {
2018 t.Fatal(err)
2019 }
2020 conf := &tls.Config{
2021
2022
2023 NextProtos: []string{"h2"},
2024 Certificates: []tls.Certificate{cert},
2025 }
2026 testAutomaticHTTP2_ListenAndServe(t, &tls.Config{
2027 GetConfigForClient: func(clientHello *tls.ClientHelloInfo) (*tls.Config, error) {
2028 return conf, nil
2029 },
2030 })
2031 }
2032
2033 func testAutomaticHTTP2_ListenAndServe(t *testing.T, tlsConf *tls.Config) {
2034 CondSkipHTTP2(t)
2035
2036 defer SetTestHookServerServe(nil)
2037 var ok bool
2038 var s *Server
2039 const maxTries = 5
2040 var ln net.Listener
2041 Try:
2042 for try := 0; try < maxTries; try++ {
2043 ln = newLocalListener(t)
2044 addr := ln.Addr().String()
2045 ln.Close()
2046 t.Logf("Got %v", addr)
2047 lnc := make(chan net.Listener, 1)
2048 SetTestHookServerServe(func(s *Server, ln net.Listener) {
2049 lnc <- ln
2050 })
2051 s = &Server{
2052 Addr: addr,
2053 TLSConfig: tlsConf,
2054 }
2055 errc := make(chan error, 1)
2056 go func() { errc <- s.ListenAndServeTLS("", "") }()
2057 select {
2058 case err := <-errc:
2059 t.Logf("On try #%v: %v", try+1, err)
2060 continue
2061 case ln = <-lnc:
2062 ok = true
2063 t.Logf("Listening on %v", ln.Addr().String())
2064 break Try
2065 }
2066 }
2067 if !ok {
2068 t.Fatalf("Failed to start up after %d tries", maxTries)
2069 }
2070 defer ln.Close()
2071 c, err := tls.Dial("tcp", ln.Addr().String(), &tls.Config{
2072 InsecureSkipVerify: true,
2073 NextProtos: []string{"h2", "http/1.1"},
2074 })
2075 if err != nil {
2076 t.Fatal(err)
2077 }
2078 defer c.Close()
2079 if got, want := c.ConnectionState().NegotiatedProtocol, "h2"; got != want {
2080 t.Errorf("NegotiatedProtocol = %q; want %q", got, want)
2081 }
2082 if got, want := c.ConnectionState().NegotiatedProtocolIsMutual, true; got != want {
2083 t.Errorf("NegotiatedProtocolIsMutual = %v; want %v", got, want)
2084 }
2085 }
2086
2087 type serverExpectTest struct {
2088 contentLength int
2089 chunked bool
2090 expectation string
2091 readBody bool
2092 expectedResponse string
2093 }
2094
2095 func expectTest(contentLength int, expectation string, readBody bool, expectedResponse string) serverExpectTest {
2096 return serverExpectTest{
2097 contentLength: contentLength,
2098 expectation: expectation,
2099 readBody: readBody,
2100 expectedResponse: expectedResponse,
2101 }
2102 }
2103
2104 var serverExpectTests = []serverExpectTest{
2105
2106 expectTest(100, "100-continue", true, "100 Continue"),
2107 expectTest(100, "100-cOntInUE", true, "100 Continue"),
2108
2109
2110 expectTest(100, "", true, "200 OK"),
2111
2112
2113
2114 expectTest(100, "100-continue", false, "401 Unauthorized"),
2115
2116 expectTest(100, "", false, "401 Unauthorized"),
2117
2118
2119 expectTest(0, "a-pony", false, "417 Expectation Failed"),
2120
2121
2122 expectTest(0, "100-continue", true, "200 OK"),
2123
2124 expectTest(0, "100-continue", false, "401 Unauthorized"),
2125
2126 {
2127 expectation: "100-continue",
2128 readBody: true,
2129 chunked: true,
2130 expectedResponse: "100 Continue",
2131 },
2132 }
2133
2134
2135
2136 func TestServerExpect(t *testing.T) { runSynctest(t, testServerExpect, []testMode{http1Mode}) }
2137 func testServerExpect(t *testing.T, mode testMode) {
2138 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2139
2140
2141
2142 if strings.Contains(r.URL.RawQuery, "readbody=true") {
2143 io.ReadAll(r.Body)
2144 w.Write([]byte("Hi"))
2145 } else {
2146 w.WriteHeader(StatusUnauthorized)
2147 }
2148 }))
2149
2150 runTest := func(test serverExpectTest) {
2151 conn, _ := cst.dialNettest()
2152 defer conn.Close()
2153
2154
2155
2156 writeBody := test.contentLength != 0 && strings.ToLower(test.expectation) != "100-continue"
2157
2158 wg := sync.WaitGroup{}
2159 wg.Add(1)
2160 defer wg.Wait()
2161
2162 go func() {
2163 defer wg.Done()
2164
2165 contentLen := fmt.Sprintf("Content-Length: %d", test.contentLength)
2166 if test.chunked {
2167 contentLen = "Transfer-Encoding: chunked"
2168 }
2169 _, err := fmt.Fprintf(conn, "POST /?readbody=%v HTTP/1.1\r\n"+
2170 "Connection: close\r\n"+
2171 "%s\r\n"+
2172 "Expect: %s\r\nHost: foo\r\n\r\n",
2173 test.readBody, contentLen, test.expectation)
2174 if err != nil {
2175 t.Errorf("On test %#v, error writing request headers: %v", test, err)
2176 return
2177 }
2178 if writeBody {
2179 var targ io.WriteCloser = struct {
2180 io.Writer
2181 io.Closer
2182 }{
2183 conn,
2184 io.NopCloser(nil),
2185 }
2186 if test.chunked {
2187 targ = httputil.NewChunkedWriter(conn)
2188 }
2189 body := strings.Repeat("A", test.contentLength)
2190 _, err = fmt.Fprint(targ, body)
2191 if err == nil {
2192 err = targ.Close()
2193 }
2194 if err != nil {
2195 if !test.readBody {
2196
2197
2198 t.Logf("On test %#v, acceptable error writing request body: %v", test, err)
2199 return
2200 }
2201 t.Errorf("On test %#v, error writing request body: %v", test, err)
2202 }
2203 }
2204 }()
2205 bufr := bufio.NewReader(conn)
2206 line, err := bufr.ReadString('\n')
2207 if err != nil {
2208 if writeBody && !test.readBody {
2209
2210
2211
2212
2213
2214 t.Logf("On test %#v, acceptable error from ReadString: %v", test, err)
2215 return
2216 }
2217 t.Fatalf("On test %#v, ReadString: %v", test, err)
2218 }
2219 if !strings.Contains(line, test.expectedResponse) {
2220 t.Errorf("On test %#v, got first line = %q; want %q", test, line, test.expectedResponse)
2221 }
2222 }
2223
2224 for _, test := range serverExpectTests {
2225 runTest(test)
2226 }
2227 }
2228
2229
2230
2231 func TestServerUnreadRequestBodyLittle(t *testing.T) {
2232 t.Parallel()
2233 conn := new(testConn)
2234 body := strings.Repeat("x", 100<<10)
2235 conn.readBuf.Write([]byte(fmt.Sprintf(
2236 "POST / HTTP/1.1\r\n"+
2237 "Host: test\r\n"+
2238 "Content-Length: %d\r\n"+
2239 "\r\n", len(body))))
2240 conn.readBuf.Write([]byte(body))
2241
2242 done := make(chan bool)
2243
2244 readBufLen := func() int {
2245 conn.readMu.Lock()
2246 defer conn.readMu.Unlock()
2247 return conn.readBuf.Len()
2248 }
2249
2250 ls := &oneConnListener{conn}
2251 go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
2252 defer close(done)
2253 if bufLen := readBufLen(); bufLen < len(body)/2 {
2254 t.Errorf("on request, read buffer length is %d; expected about 100 KB", bufLen)
2255 }
2256 rw.WriteHeader(200)
2257 rw.(Flusher).Flush()
2258 if g, e := readBufLen(), 0; g != e {
2259 t.Errorf("after WriteHeader, read buffer length is %d; want %d", g, e)
2260 }
2261 if c := rw.Header().Get("Connection"); c != "" {
2262 t.Errorf(`Connection header = %q; want ""`, c)
2263 }
2264 }))
2265 <-done
2266 }
2267
2268
2269
2270
2271 func TestServerUnreadRequestBodyLarge(t *testing.T) {
2272 t.Parallel()
2273 if testing.Short() && testenv.Builder() == "" {
2274 t.Log("skipping in short mode")
2275 }
2276 conn := new(testConn)
2277 body := strings.Repeat("x", 1<<20)
2278 conn.readBuf.Write([]byte(fmt.Sprintf(
2279 "POST / HTTP/1.1\r\n"+
2280 "Host: test\r\n"+
2281 "Content-Length: %d\r\n"+
2282 "\r\n", len(body))))
2283 conn.readBuf.Write([]byte(body))
2284 conn.closec = make(chan bool, 1)
2285
2286 ls := &oneConnListener{conn}
2287 go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
2288 if conn.readBuf.Len() < len(body)/2 {
2289 t.Errorf("on request, read buffer length is %d; expected about 1MB", conn.readBuf.Len())
2290 }
2291 rw.WriteHeader(200)
2292 rw.(Flusher).Flush()
2293 if conn.readBuf.Len() < len(body)/2 {
2294 t.Errorf("post-WriteHeader, read buffer length is %d; expected about 1MB", conn.readBuf.Len())
2295 }
2296 }))
2297 <-conn.closec
2298
2299 if res := conn.writeBuf.String(); !strings.Contains(res, "Connection: close") {
2300 t.Errorf("Expected a Connection: close header; got response: %s", res)
2301 }
2302 }
2303
2304 type handlerBodyCloseTest struct {
2305 bodySize int
2306 bodyChunked bool
2307 reqConnClose bool
2308
2309 wantEOFSearch bool
2310 wantNextReq bool
2311 }
2312
2313 func (t handlerBodyCloseTest) connectionHeader() string {
2314 if t.reqConnClose {
2315 return "Connection: close\r\n"
2316 }
2317 return ""
2318 }
2319
2320 var handlerBodyCloseTests = [...]handlerBodyCloseTest{
2321
2322
2323 0: {
2324 bodySize: 20 << 10,
2325 bodyChunked: false,
2326 reqConnClose: false,
2327 wantEOFSearch: true,
2328 wantNextReq: true,
2329 },
2330
2331
2332
2333 1: {
2334 bodySize: 20 << 10,
2335 bodyChunked: true,
2336 reqConnClose: false,
2337 wantEOFSearch: true,
2338 wantNextReq: true,
2339 },
2340
2341
2342
2343
2344 2: {
2345 bodySize: 20 << 10,
2346 bodyChunked: false,
2347 reqConnClose: true,
2348 wantEOFSearch: false,
2349 wantNextReq: false,
2350 },
2351
2352
2353
2354
2355
2356
2357 3: {
2358 bodySize: 20 << 10,
2359 bodyChunked: true,
2360 reqConnClose: true,
2361 wantEOFSearch: true,
2362 wantNextReq: false,
2363 },
2364
2365
2366 4: {
2367 bodySize: 1 << 20,
2368 bodyChunked: false,
2369 reqConnClose: false,
2370 wantEOFSearch: false,
2371 wantNextReq: false,
2372 },
2373
2374
2375 5: {
2376 bodySize: 1 << 20,
2377 bodyChunked: true,
2378 reqConnClose: false,
2379 wantEOFSearch: true,
2380 wantNextReq: false,
2381 },
2382
2383
2384
2385
2386 6: {
2387 bodySize: 1 << 20,
2388 bodyChunked: true,
2389 reqConnClose: true,
2390 wantEOFSearch: true,
2391 wantNextReq: false,
2392 },
2393
2394
2395
2396 7: {
2397 bodySize: 1 << 20,
2398 bodyChunked: false,
2399 reqConnClose: true,
2400 wantEOFSearch: false,
2401 wantNextReq: false,
2402 },
2403 }
2404
2405 func TestHandlerBodyClose(t *testing.T) {
2406 t.Parallel()
2407 if testing.Short() && testenv.Builder() == "" {
2408 t.Skip("skipping in -short mode")
2409 }
2410 for i, tt := range handlerBodyCloseTests {
2411 testHandlerBodyClose(t, i, tt)
2412 }
2413 }
2414
2415 func testHandlerBodyClose(t *testing.T, i int, tt handlerBodyCloseTest) {
2416 conn := new(testConn)
2417 body := strings.Repeat("x", tt.bodySize)
2418 if tt.bodyChunked {
2419 conn.readBuf.WriteString("POST / HTTP/1.1\r\n" +
2420 "Host: test\r\n" +
2421 tt.connectionHeader() +
2422 "Transfer-Encoding: chunked\r\n" +
2423 "\r\n")
2424 cw := internal.NewChunkedWriter(&conn.readBuf)
2425 io.WriteString(cw, body)
2426 cw.Close()
2427 conn.readBuf.WriteString("\r\n")
2428 } else {
2429 conn.readBuf.Write([]byte(fmt.Sprintf(
2430 "POST / HTTP/1.1\r\n"+
2431 "Host: test\r\n"+
2432 tt.connectionHeader()+
2433 "Content-Length: %d\r\n"+
2434 "\r\n", len(body))))
2435 conn.readBuf.Write([]byte(body))
2436 }
2437 if !tt.reqConnClose {
2438 conn.readBuf.WriteString("GET / HTTP/1.1\r\nHost: test\r\n\r\n")
2439 }
2440 conn.closec = make(chan bool, 1)
2441
2442 readBufLen := func() int {
2443 conn.readMu.Lock()
2444 defer conn.readMu.Unlock()
2445 return conn.readBuf.Len()
2446 }
2447
2448 ls := &oneConnListener{conn}
2449 var numReqs int
2450 var size0, size1 int
2451 go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
2452 numReqs++
2453 if numReqs == 1 {
2454 size0 = readBufLen()
2455 req.Body.Close()
2456 size1 = readBufLen()
2457 }
2458 }))
2459 <-conn.closec
2460 if numReqs < 1 || numReqs > 2 {
2461 t.Fatalf("%d. bug in test. unexpected number of requests = %d", i, numReqs)
2462 }
2463 didSearch := size0 != size1
2464 if didSearch != tt.wantEOFSearch {
2465 t.Errorf("%d. did EOF search = %v; want %v (size went from %d to %d)", i, didSearch, !didSearch, size0, size1)
2466 }
2467 if tt.wantNextReq && numReqs != 2 {
2468 t.Errorf("%d. numReq = %d; want 2", i, numReqs)
2469 }
2470 }
2471
2472
2473
2474 type testHandlerBodyConsumer struct {
2475 name string
2476 f func(io.ReadCloser)
2477 }
2478
2479 var testHandlerBodyConsumers = []testHandlerBodyConsumer{
2480 {"nil", func(io.ReadCloser) {}},
2481 {"close", func(r io.ReadCloser) { r.Close() }},
2482 {"discard", func(r io.ReadCloser) { io.Copy(io.Discard, r) }},
2483 }
2484
2485 func TestRequestBodyReadErrorClosesConnection(t *testing.T) {
2486 t.Parallel()
2487 for _, handler := range testHandlerBodyConsumers {
2488 conn := new(testConn)
2489 conn.readBuf.WriteString("POST /public HTTP/1.1\r\n" +
2490 "Host: test\r\n" +
2491 "Transfer-Encoding: chunked\r\n" +
2492 "\r\n" +
2493 "hax\r\n" +
2494 "GET /secret HTTP/1.1\r\n" +
2495 "Host: test\r\n" +
2496 "\r\n")
2497
2498 conn.closec = make(chan bool, 1)
2499 ls := &oneConnListener{conn}
2500 var numReqs int
2501 go Serve(ls, HandlerFunc(func(_ ResponseWriter, req *Request) {
2502 numReqs++
2503 if strings.Contains(req.URL.Path, "secret") {
2504 t.Error("Request for /secret encountered, should not have happened.")
2505 }
2506 handler.f(req.Body)
2507 }))
2508 <-conn.closec
2509 if numReqs != 1 {
2510 t.Errorf("Handler %v: got %d reqs; want 1", handler.name, numReqs)
2511 }
2512 }
2513 }
2514
2515 func TestInvalidTrailerClosesConnection(t *testing.T) {
2516 t.Parallel()
2517 for _, handler := range testHandlerBodyConsumers {
2518 conn := new(testConn)
2519 conn.readBuf.WriteString("POST /public HTTP/1.1\r\n" +
2520 "Host: test\r\n" +
2521 "Trailer: hack\r\n" +
2522 "Transfer-Encoding: chunked\r\n" +
2523 "\r\n" +
2524 "3\r\n" +
2525 "hax\r\n" +
2526 "0\r\n" +
2527 "I'm not a valid trailer\r\n" +
2528 "GET /secret HTTP/1.1\r\n" +
2529 "Host: test\r\n" +
2530 "\r\n")
2531
2532 conn.closec = make(chan bool, 1)
2533 ln := &oneConnListener{conn}
2534 var numReqs int
2535 go Serve(ln, HandlerFunc(func(_ ResponseWriter, req *Request) {
2536 numReqs++
2537 if strings.Contains(req.URL.Path, "secret") {
2538 t.Errorf("Handler %s, Request for /secret encountered, should not have happened.", handler.name)
2539 }
2540 handler.f(req.Body)
2541 }))
2542 <-conn.closec
2543 if numReqs != 1 {
2544 t.Errorf("Handler %s: got %d reqs; want 1", handler.name, numReqs)
2545 }
2546 }
2547 }
2548
2549
2550
2551
2552 type slowTestConn struct {
2553
2554 script []any
2555 closec chan bool
2556
2557 mu sync.Mutex
2558 rd, wd time.Time
2559 noopConn
2560 }
2561
2562 func (c *slowTestConn) SetDeadline(t time.Time) error {
2563 c.SetReadDeadline(t)
2564 c.SetWriteDeadline(t)
2565 return nil
2566 }
2567
2568 func (c *slowTestConn) SetReadDeadline(t time.Time) error {
2569 c.mu.Lock()
2570 defer c.mu.Unlock()
2571 c.rd = t
2572 return nil
2573 }
2574
2575 func (c *slowTestConn) SetWriteDeadline(t time.Time) error {
2576 c.mu.Lock()
2577 defer c.mu.Unlock()
2578 c.wd = t
2579 return nil
2580 }
2581
2582 func (c *slowTestConn) Read(b []byte) (n int, err error) {
2583 c.mu.Lock()
2584 defer c.mu.Unlock()
2585 restart:
2586 if !c.rd.IsZero() && time.Now().After(c.rd) {
2587 return 0, syscall.ETIMEDOUT
2588 }
2589 if len(c.script) == 0 {
2590 return 0, io.EOF
2591 }
2592
2593 switch cue := c.script[0].(type) {
2594 case time.Duration:
2595 if !c.rd.IsZero() {
2596
2597
2598 if remaining := time.Until(c.rd); remaining < cue {
2599 c.script[0] = cue - remaining
2600 time.Sleep(remaining)
2601 return 0, syscall.ETIMEDOUT
2602 }
2603 }
2604 c.script = c.script[1:]
2605 time.Sleep(cue)
2606 goto restart
2607
2608 case string:
2609 n = copy(b, cue)
2610
2611 if len(cue) > n {
2612 c.script[0] = cue[n:]
2613 } else {
2614 c.script = c.script[1:]
2615 }
2616
2617 default:
2618 panic("unknown cue in slowTestConn script")
2619 }
2620
2621 return
2622 }
2623
2624 func (c *slowTestConn) Close() error {
2625 select {
2626 case c.closec <- true:
2627 default:
2628 }
2629 return nil
2630 }
2631
2632 func (c *slowTestConn) Write(b []byte) (int, error) {
2633 if !c.wd.IsZero() && time.Now().After(c.wd) {
2634 return 0, syscall.ETIMEDOUT
2635 }
2636 return len(b), nil
2637 }
2638
2639 func TestRequestBodyTimeoutClosesConnection(t *testing.T) {
2640 synctest.Test(t, testRequestBodyTimeoutClosesConnection)
2641 }
2642 func testRequestBodyTimeoutClosesConnection(t *testing.T) {
2643 for _, handler := range testHandlerBodyConsumers {
2644 conn := &slowTestConn{
2645 script: []any{
2646 "POST /public HTTP/1.1\r\n" +
2647 "Host: test\r\n" +
2648 "Content-Length: 10000\r\n" +
2649 "\r\n",
2650 "foo bar baz",
2651 600 * time.Millisecond,
2652 "GET /secret HTTP/1.1\r\n" +
2653 "Host: test\r\n" +
2654 "\r\n",
2655 },
2656 closec: make(chan bool, 1),
2657 }
2658 ls := &oneConnListener{conn}
2659
2660 var numReqs int
2661 s := Server{
2662 Handler: HandlerFunc(func(_ ResponseWriter, req *Request) {
2663 numReqs++
2664 if strings.Contains(req.URL.Path, "secret") {
2665 t.Error("Request for /secret encountered, should not have happened.")
2666 }
2667 handler.f(req.Body)
2668 }),
2669 ReadTimeout: 400 * time.Millisecond,
2670 }
2671 go s.Serve(ls)
2672 <-conn.closec
2673
2674 if numReqs != 1 {
2675 t.Errorf("Handler %v: got %d reqs; want 1", handler.name, numReqs)
2676 }
2677 }
2678 }
2679
2680
2681 type cancelableTimeoutContext struct {
2682 context.Context
2683 }
2684
2685 func (c cancelableTimeoutContext) Err() error {
2686 if c.Context.Err() != nil {
2687 return context.DeadlineExceeded
2688 }
2689 return nil
2690 }
2691
2692 func TestTimeoutHandler(t *testing.T) { runSynctest(t, testTimeoutHandler) }
2693 func testTimeoutHandler(t *testing.T, mode testMode) {
2694 sendHi := make(chan bool, 1)
2695 writeErrors := make(chan error, 1)
2696 sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
2697 <-sendHi
2698 _, werr := w.Write([]byte("hi"))
2699 writeErrors <- werr
2700 })
2701 ctx, cancel := context.WithCancel(context.Background())
2702 h := NewTestTimeoutHandler(sayHi, cancelableTimeoutContext{ctx})
2703 cst := newClientServerTest(t, mode, h)
2704
2705
2706 sendHi <- true
2707 res, err := cst.c.Get(cst.ts.URL)
2708 if err != nil {
2709 t.Error(err)
2710 }
2711 if g, e := res.StatusCode, StatusOK; g != e {
2712 t.Errorf("got res.StatusCode %d; expected %d", g, e)
2713 }
2714 body, _ := io.ReadAll(res.Body)
2715 if g, e := string(body), "hi"; g != e {
2716 t.Errorf("got body %q; expected %q", g, e)
2717 }
2718 if g := <-writeErrors; g != nil {
2719 t.Errorf("got unexpected Write error on first request: %v", g)
2720 }
2721
2722
2723 cancel()
2724
2725 res, err = cst.c.Get(cst.ts.URL)
2726 if err != nil {
2727 t.Error(err)
2728 }
2729 if g, e := res.StatusCode, StatusServiceUnavailable; g != e {
2730 t.Errorf("got res.StatusCode %d; expected %d", g, e)
2731 }
2732 body, _ = io.ReadAll(res.Body)
2733 if !strings.Contains(string(body), "<title>Timeout</title>") {
2734 t.Errorf("expected timeout body; got %q", string(body))
2735 }
2736 if g, w := res.Header.Get("Content-Type"), "text/html; charset=utf-8"; g != w {
2737 t.Errorf("response content-type = %q; want %q", g, w)
2738 }
2739
2740
2741
2742 sendHi <- true
2743 if g, e := <-writeErrors, ErrHandlerTimeout; g != e {
2744 t.Errorf("expected Write error of %v; got %v", e, g)
2745 }
2746 }
2747
2748
2749 func TestTimeoutHandlerRace(t *testing.T) { runSynctest(t, testTimeoutHandlerRace) }
2750 func testTimeoutHandlerRace(t *testing.T, mode testMode) {
2751 delayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
2752 ms, _ := strconv.Atoi(r.URL.Path[1:])
2753 if ms == 0 {
2754 ms = 1
2755 }
2756 for i := 0; i < ms; i++ {
2757 w.Write([]byte("hi"))
2758 time.Sleep(time.Millisecond)
2759 }
2760 })
2761
2762 ts := newClientServerTest(t, mode, TimeoutHandler(delayHi, 20*time.Millisecond, "")).ts
2763
2764 c := ts.Client()
2765
2766 var wg sync.WaitGroup
2767 gate := make(chan bool, 10)
2768 n := 50
2769 if testing.Short() {
2770 n = 10
2771 gate = make(chan bool, 3)
2772 }
2773 for i := 0; i < n; i++ {
2774 gate <- true
2775 wg.Add(1)
2776 go func() {
2777 defer wg.Done()
2778 defer func() { <-gate }()
2779 res, err := c.Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50)))
2780 if err == nil {
2781 io.Copy(io.Discard, res.Body)
2782 res.Body.Close()
2783 }
2784 }()
2785 }
2786 wg.Wait()
2787 time.Sleep(50 * time.Millisecond)
2788 }
2789
2790
2791
2792 func TestTimeoutHandlerRaceHeader(t *testing.T) { runSynctest(t, testTimeoutHandlerRaceHeader) }
2793 func testTimeoutHandlerRaceHeader(t *testing.T, mode testMode) {
2794 delay204 := HandlerFunc(func(w ResponseWriter, r *Request) {
2795 w.WriteHeader(204)
2796 })
2797
2798 ts := newClientServerTest(t, mode, TimeoutHandler(delay204, time.Nanosecond, "")).ts
2799
2800 var wg sync.WaitGroup
2801 gate := make(chan bool, 50)
2802 n := 500
2803 if testing.Short() {
2804 n = 10
2805 }
2806
2807 c := ts.Client()
2808 for i := 0; i < n; i++ {
2809 gate <- true
2810 wg.Add(1)
2811 go func() {
2812 defer wg.Done()
2813 defer func() { <-gate }()
2814 res, err := c.Get(ts.URL)
2815 if err != nil {
2816
2817
2818 t.Log(err)
2819 return
2820 }
2821 defer res.Body.Close()
2822 io.Copy(io.Discard, res.Body)
2823 }()
2824 }
2825 wg.Wait()
2826 }
2827
2828
2829 func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) {
2830 runSynctest(t, testTimeoutHandlerRaceHeaderTimeout)
2831 }
2832 func testTimeoutHandlerRaceHeaderTimeout(t *testing.T, mode testMode) {
2833 sendHi := make(chan bool, 1)
2834 writeErrors := make(chan error, 1)
2835 sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
2836 w.Header().Set("Content-Type", "text/plain")
2837 <-sendHi
2838 _, werr := w.Write([]byte("hi"))
2839 writeErrors <- werr
2840 })
2841 ctx, cancel := context.WithCancel(context.Background())
2842 h := NewTestTimeoutHandler(sayHi, cancelableTimeoutContext{ctx})
2843 cst := newClientServerTest(t, mode, h)
2844
2845
2846 sendHi <- true
2847 res, err := cst.c.Get(cst.ts.URL)
2848 if err != nil {
2849 t.Error(err)
2850 }
2851 if g, e := res.StatusCode, StatusOK; g != e {
2852 t.Errorf("got res.StatusCode %d; expected %d", g, e)
2853 }
2854 body, _ := io.ReadAll(res.Body)
2855 if g, e := string(body), "hi"; g != e {
2856 t.Errorf("got body %q; expected %q", g, e)
2857 }
2858 if g := <-writeErrors; g != nil {
2859 t.Errorf("got unexpected Write error on first request: %v", g)
2860 }
2861
2862
2863 cancel()
2864
2865 res, err = cst.c.Get(cst.ts.URL)
2866 if err != nil {
2867 t.Error(err)
2868 }
2869 if g, e := res.StatusCode, StatusServiceUnavailable; g != e {
2870 t.Errorf("got res.StatusCode %d; expected %d", g, e)
2871 }
2872 body, _ = io.ReadAll(res.Body)
2873 if !strings.Contains(string(body), "<title>Timeout</title>") {
2874 t.Errorf("expected timeout body; got %q", string(body))
2875 }
2876
2877
2878
2879 sendHi <- true
2880 if g, e := <-writeErrors, ErrHandlerTimeout; g != e {
2881 t.Errorf("expected Write error of %v; got %v", e, g)
2882 }
2883 }
2884
2885
2886 func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) {
2887 runSynctest(t, testTimeoutHandlerStartTimerWhenServing)
2888 }
2889 func testTimeoutHandlerStartTimerWhenServing(t *testing.T, mode testMode) {
2890 var handler HandlerFunc = func(w ResponseWriter, _ *Request) {
2891 w.WriteHeader(StatusNoContent)
2892 }
2893 timeout := 300 * time.Millisecond
2894 ts := newClientServerTest(t, mode, TimeoutHandler(handler, timeout, "")).ts
2895 defer ts.Close()
2896
2897 c := ts.Client()
2898
2899
2900
2901
2902 time.Sleep(2 * timeout)
2903 res, err := c.Get(ts.URL)
2904 if err != nil {
2905 t.Fatal(err)
2906 }
2907 defer res.Body.Close()
2908 if res.StatusCode != StatusNoContent {
2909 t.Errorf("got res.StatusCode %d, want %v", res.StatusCode, StatusNoContent)
2910 }
2911 }
2912
2913 func TestTimeoutHandlerContextCanceled(t *testing.T) {
2914 runSynctest(t, testTimeoutHandlerContextCanceled)
2915 }
2916 func testTimeoutHandlerContextCanceled(t *testing.T, mode testMode) {
2917 writeErrors := make(chan error, 1)
2918 sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
2919 w.Header().Set("Content-Type", "text/plain")
2920 var err error
2921
2922
2923
2924 for i := 0; i < 100; i++ {
2925 _, err = w.Write([]byte("a"))
2926 if err != nil {
2927 break
2928 }
2929 time.Sleep(1 * time.Millisecond)
2930 }
2931 writeErrors <- err
2932 })
2933 ctx, cancel := context.WithCancel(context.Background())
2934 cancel()
2935 h := NewTestTimeoutHandler(sayHi, ctx)
2936 cst := newClientServerTest(t, mode, h)
2937 defer cst.close()
2938
2939 res, err := cst.c.Get(cst.ts.URL)
2940 if err != nil {
2941 t.Error(err)
2942 }
2943 if g, e := res.StatusCode, StatusServiceUnavailable; g != e {
2944 t.Errorf("got res.StatusCode %d; expected %d", g, e)
2945 }
2946 body, _ := io.ReadAll(res.Body)
2947 if g, e := string(body), ""; g != e {
2948 t.Errorf("got body %q; expected %q", g, e)
2949 }
2950 if g, e := <-writeErrors, context.Canceled; g != e {
2951 t.Errorf("got unexpected Write in handler: %v, want %g", g, e)
2952 }
2953 }
2954
2955
2956 func TestTimeoutHandlerEmptyResponse(t *testing.T) { runSynctest(t, testTimeoutHandlerEmptyResponse) }
2957 func testTimeoutHandlerEmptyResponse(t *testing.T, mode testMode) {
2958 var handler HandlerFunc = func(w ResponseWriter, _ *Request) {
2959
2960 }
2961 timeout := 300 * time.Millisecond
2962 ts := newClientServerTest(t, mode, TimeoutHandler(handler, timeout, "")).ts
2963
2964 c := ts.Client()
2965
2966 res, err := c.Get(ts.URL)
2967 if err != nil {
2968 t.Fatal(err)
2969 }
2970 defer res.Body.Close()
2971 if res.StatusCode != StatusOK {
2972 t.Errorf("got res.StatusCode %d, want %v", res.StatusCode, StatusOK)
2973 }
2974 }
2975
2976
2977 func TestTimeoutHandlerPanicRecovery(t *testing.T) {
2978 wrapper := func(h Handler) Handler {
2979 return TimeoutHandler(h, time.Second, "")
2980 }
2981 runNoSynctest(t, func(t *testing.T, mode testMode) {
2982 testHandlerPanic(t, false, mode, wrapper, ErrAbortHandler)
2983 }, testNotParallel, http3SkippedMode)
2984 }
2985
2986 func TestRedirectBadPath(t *testing.T) {
2987
2988
2989 rr := httptest.NewRecorder()
2990 req := &Request{
2991 Method: "GET",
2992 URL: &url.URL{
2993 Scheme: "http",
2994 Path: "not-empty-but-no-leading-slash",
2995 },
2996 }
2997 Redirect(rr, req, "", 304)
2998 if rr.Code != 304 {
2999 t.Errorf("Code = %d; want 304", rr.Code)
3000 }
3001 }
3002
3003 func TestRedirectEscapedPath(t *testing.T) {
3004 baseURL, redirectURL := "http://example.com/foo%2Fbar/", "qux%2Fbaz"
3005 req := httptest.NewRequest("GET", baseURL, NoBody)
3006
3007 rr := httptest.NewRecorder()
3008 Redirect(rr, req, redirectURL, StatusMovedPermanently)
3009
3010 wantURL := "/foo%2Fbar/qux%2Fbaz"
3011 if got := rr.Result().Header.Get("Location"); got != wantURL {
3012 t.Errorf("Redirect(%s, %s) = %s, want = %s", baseURL, redirectURL, got, wantURL)
3013 }
3014 }
3015
3016
3017 func TestRedirect(t *testing.T) {
3018 req, _ := NewRequest("GET", "http://example.com/qux/", nil)
3019
3020 var tests = []struct {
3021 in string
3022 want string
3023 }{
3024
3025 {"http://foobar.com/baz", "http://foobar.com/baz"},
3026
3027 {"https://foobar.com/baz", "https://foobar.com/baz"},
3028
3029 {"test://foobar.com/baz", "test://foobar.com/baz"},
3030
3031 {"//foobar.com/baz", "//foobar.com/baz"},
3032
3033 {"/foobar.com/baz", "/foobar.com/baz"},
3034
3035 {"foobar.com/baz", "/qux/foobar.com/baz"},
3036
3037 {"../quux/foobar.com/baz", "/quux/foobar.com/baz"},
3038
3039 {"///foobar.com/baz", "/foobar.com/baz"},
3040
3041
3042 {"/foo?next=http://bar.com/", "/foo?next=http://bar.com/"},
3043 {"http://localhost:8080/_ah/login?continue=http://localhost:8080/",
3044 "http://localhost:8080/_ah/login?continue=http://localhost:8080/"},
3045
3046 {"/фубар", "/%d1%84%d1%83%d0%b1%d0%b0%d1%80"},
3047 {"http://foo.com/фубар", "http://foo.com/%d1%84%d1%83%d0%b1%d0%b0%d1%80"},
3048 }
3049
3050 for _, tt := range tests {
3051 rec := httptest.NewRecorder()
3052 Redirect(rec, req, tt.in, 302)
3053 if got, want := rec.Code, 302; got != want {
3054 t.Errorf("Redirect(%q) generated status code %v; want %v", tt.in, got, want)
3055 }
3056 if got := rec.Header().Get("Location"); got != tt.want {
3057 t.Errorf("Redirect(%q) generated Location header %q; want %q", tt.in, got, tt.want)
3058 }
3059 }
3060 }
3061
3062
3063
3064 func TestRedirectContentTypeAndBody(t *testing.T) {
3065 type ctHeader struct {
3066 Values []string
3067 }
3068
3069 var tests = []struct {
3070 method string
3071 ct *ctHeader
3072 wantCT string
3073 wantBody string
3074 }{
3075 {MethodGet, nil, "text/html; charset=utf-8", "<a href=\"/foo\">Found</a>.\n\n"},
3076 {MethodHead, nil, "text/html; charset=utf-8", ""},
3077 {MethodPost, nil, "", ""},
3078 {MethodDelete, nil, "", ""},
3079 {"foo", nil, "", ""},
3080 {MethodGet, &ctHeader{[]string{"application/test"}}, "application/test", ""},
3081 {MethodGet, &ctHeader{[]string{}}, "", ""},
3082 {MethodGet, &ctHeader{nil}, "", ""},
3083 }
3084 for _, tt := range tests {
3085 req := httptest.NewRequest(tt.method, "http://example.com/qux/", nil)
3086 rec := httptest.NewRecorder()
3087 if tt.ct != nil {
3088 rec.Header()["Content-Type"] = tt.ct.Values
3089 }
3090 Redirect(rec, req, "/foo", 302)
3091 if got, want := rec.Code, 302; got != want {
3092 t.Errorf("Redirect(%q, %#v) generated status code %v; want %v", tt.method, tt.ct, got, want)
3093 }
3094 if got, want := rec.Header().Get("Content-Type"), tt.wantCT; got != want {
3095 t.Errorf("Redirect(%q, %#v) generated Content-Type header %q; want %q", tt.method, tt.ct, got, want)
3096 }
3097 resp := rec.Result()
3098 body, err := io.ReadAll(resp.Body)
3099 if err != nil {
3100 t.Fatal(err)
3101 }
3102 if got, want := string(body), tt.wantBody; got != want {
3103 t.Errorf("Redirect(%q, %#v) generated Body %q; want %q", tt.method, tt.ct, got, want)
3104 }
3105 }
3106 }
3107
3108
3109
3110
3111
3112
3113
3114 func TestZeroLengthPostAndResponse(t *testing.T) { runSynctest(t, testZeroLengthPostAndResponse) }
3115
3116 func testZeroLengthPostAndResponse(t *testing.T, mode testMode) {
3117 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, r *Request) {
3118 all, err := io.ReadAll(r.Body)
3119 if err != nil {
3120 t.Fatalf("handler ReadAll: %v", err)
3121 }
3122 if len(all) != 0 {
3123 t.Errorf("handler got %d bytes; expected 0", len(all))
3124 }
3125 rw.Header().Set("Content-Length", "0")
3126 }))
3127
3128 req, err := NewRequest("POST", cst.ts.URL, strings.NewReader(""))
3129 if err != nil {
3130 t.Fatal(err)
3131 }
3132 req.ContentLength = 0
3133
3134 var resp [5]*Response
3135 for i := range resp {
3136 resp[i], err = cst.c.Do(req)
3137 if err != nil {
3138 t.Fatalf("client post #%d: %v", i, err)
3139 }
3140 }
3141
3142 for i := range resp {
3143 all, err := io.ReadAll(resp[i].Body)
3144 if err != nil {
3145 t.Fatalf("req #%d: client ReadAll: %v", i, err)
3146 }
3147 if len(all) != 0 {
3148 t.Errorf("req #%d: client got %d bytes; expected 0", i, len(all))
3149 }
3150 }
3151 }
3152
3153 func TestHandlerPanicNil(t *testing.T) {
3154 runNoSynctest(t, func(t *testing.T, mode testMode) {
3155 testHandlerPanic(t, false, mode, nil, nil)
3156 }, testNotParallel, http3SkippedMode)
3157 }
3158
3159 func TestHandlerPanic(t *testing.T) {
3160 runNoSynctest(t, func(t *testing.T, mode testMode) {
3161 testHandlerPanic(t, false, mode, nil, "intentional death for testing")
3162 }, testNotParallel, http3SkippedMode)
3163 }
3164
3165 func TestHandlerPanicWithHijack(t *testing.T) {
3166
3167 runNoSynctest(t, func(t *testing.T, mode testMode) {
3168 testHandlerPanic(t, true, mode, nil, "intentional death for testing")
3169 }, []testMode{http1Mode})
3170 }
3171
3172 func testHandlerPanic(t *testing.T, withHijack bool, mode testMode, wrapper func(Handler) Handler, panicValue any) {
3173 synctest.Test(t, func(t *testing.T) {
3174 var handler Handler = HandlerFunc(func(w ResponseWriter, r *Request) {
3175 if withHijack {
3176 rwc, _, err := w.(Hijacker).Hijack()
3177 if err != nil {
3178 t.Logf("unexpected error: %v", err)
3179 }
3180 defer rwc.Close()
3181 }
3182 panic(panicValue)
3183 })
3184 if wrapper != nil {
3185 handler = wrapper(handler)
3186 }
3187 var logBuf bytes.Buffer
3188 cst := newClientServerTest(t, mode, handler, func(ts *httptest.Server) {
3189 ts.Config.ErrorLog = log.New(&logBuf, "", 0)
3190 })
3191
3192
3193 cst.ts.Config.Handler = handler
3194
3195 _, err := cst.c.Get(cst.ts.URL)
3196 if err == nil {
3197 t.Logf("expected an error")
3198 }
3199
3200 cst.ts.Close()
3201
3202 synctest.Wait()
3203 if panicValue == ErrAbortHandler {
3204 if got := logBuf.String(); got != "" {
3205 t.Errorf("unexpected log output:\n%v", got)
3206 }
3207 } else if logBuf.String() == "" {
3208 t.Errorf("nothing logged after panic; want something")
3209 }
3210 })
3211 }
3212
3213 type terrorWriter struct{ t *testing.T }
3214
3215 func (w terrorWriter) Write(p []byte) (int, error) {
3216 w.t.Errorf("%s", p)
3217 return len(p), nil
3218 }
3219
3220
3221
3222 func TestServerWriteHijackZeroBytes(t *testing.T) {
3223 runSynctest(t, testServerWriteHijackZeroBytes, []testMode{http1Mode})
3224 }
3225 func testServerWriteHijackZeroBytes(t *testing.T, mode testMode) {
3226 done := make(chan struct{})
3227 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3228 defer close(done)
3229 w.(Flusher).Flush()
3230 conn, _, err := w.(Hijacker).Hijack()
3231 if err != nil {
3232 t.Errorf("Hijack: %v", err)
3233 return
3234 }
3235 defer conn.Close()
3236 _, err = w.Write(nil)
3237 if err != ErrHijacked {
3238 t.Errorf("Write error = %v; want ErrHijacked", err)
3239 }
3240 }), func(ts *httptest.Server) {
3241 ts.Config.ErrorLog = log.New(terrorWriter{t}, "Unexpected write: ", 0)
3242 }).ts
3243
3244 c := ts.Client()
3245 res, err := c.Get(ts.URL)
3246 if err != nil {
3247 t.Fatal(err)
3248 }
3249 res.Body.Close()
3250 <-done
3251 }
3252
3253 func TestServerNoDate(t *testing.T) {
3254 runSynctest(t, func(t *testing.T, mode testMode) {
3255 testServerNoHeader(t, mode, "Date")
3256 })
3257 }
3258
3259 func TestServerContentType(t *testing.T) {
3260 runSynctest(t, func(t *testing.T, mode testMode) {
3261 testServerNoHeader(t, mode, "Content-Type")
3262 })
3263 }
3264
3265 func testServerNoHeader(t *testing.T, mode testMode, header string) {
3266 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3267 w.Header()[header] = nil
3268 io.WriteString(w, "<html>foo</html>")
3269 }))
3270 res, err := cst.c.Get(cst.ts.URL)
3271 if err != nil {
3272 t.Fatal(err)
3273 }
3274 res.Body.Close()
3275 if got, ok := res.Header[header]; ok {
3276 t.Fatalf("Expected no %s header; got %q", header, got)
3277 }
3278 }
3279
3280 func TestStripPrefix(t *testing.T) { runNoSynctest(t, testStripPrefix) }
3281 func testStripPrefix(t *testing.T, mode testMode) {
3282 cases := []struct {
3283 reqPath string
3284 path string
3285 rawPath string
3286 }{
3287 {"/foo/bar/qux", "/qux", ""},
3288 {"/foo/bar%2Fqux", "/qux", "%2Fqux"},
3289 {"/foo%2Fbar/qux", "", ""},
3290 {"/bar", "", ""},
3291 }
3292 for _, tc := range cases {
3293 synctest.Subtest(t, tc.reqPath, func(t *testing.T) {
3294 h := HandlerFunc(func(w ResponseWriter, r *Request) {
3295 w.Header().Set("X-Path", r.URL.Path)
3296 w.Header().Set("X-RawPath", r.URL.RawPath)
3297 })
3298 ts := newClientServerTest(t, mode, StripPrefix("/foo/bar", h)).ts
3299
3300 res, err := ts.Client().Get(ts.URL + tc.reqPath)
3301 if err != nil {
3302 t.Fatal(err)
3303 }
3304 res.Body.Close()
3305 if tc.path == "" {
3306 if res.StatusCode != StatusNotFound {
3307 t.Errorf("got %q, want 404 Not Found", res.Status)
3308 }
3309 return
3310 }
3311 if res.StatusCode != StatusOK {
3312 t.Fatalf("got %q, want 200 OK", res.Status)
3313 }
3314 if g, w := res.Header.Get("X-Path"), tc.path; g != w {
3315 t.Errorf("got Path %q, want %q", g, w)
3316 }
3317 if g, w := res.Header.Get("X-RawPath"), tc.rawPath; g != w {
3318 t.Errorf("got RawPath %q, want %q", g, w)
3319 }
3320 })
3321 }
3322 }
3323
3324
3325 func TestStripPrefixNotModifyRequest(t *testing.T) {
3326 h := StripPrefix("/foo", NotFoundHandler())
3327 req := httptest.NewRequest("GET", "/foo/bar", nil)
3328 h.ServeHTTP(httptest.NewRecorder(), req)
3329 if req.URL.Path != "/foo/bar" {
3330 t.Errorf("StripPrefix should not modify the provided Request, but it did")
3331 }
3332 }
3333
3334 func TestRequestLimit(t *testing.T) { runSynctest(t, testRequestLimit) }
3335 func testRequestLimit(t *testing.T, mode testMode) {
3336 bytesPerHeader := len("header12345: val12345\r\n")
3337 numHeaders := ((DefaultMaxHeaderBytes + 4096) / bytesPerHeader) + 1
3338
3339 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3340 t.Fatalf("didn't expect to get request in Handler")
3341 }), func(s *Server) {
3342 s.MaxHeaderValueCount = numHeaders
3343 }, optQuietLog)
3344 req, _ := NewRequest("GET", cst.ts.URL, nil)
3345 for i := range numHeaders {
3346 req.Header.Set(fmt.Sprintf("header%05d", i), fmt.Sprintf("val%05d", i))
3347 }
3348 res, err := cst.c.Do(req)
3349 if res != nil {
3350 defer res.Body.Close()
3351 }
3352 if mode == http2Mode {
3353
3354
3355
3356
3357 if err == nil && res.StatusCode != 431 {
3358 t.Fatalf("expected 431 response status; got: %d %s", res.StatusCode, res.Status)
3359 }
3360 } else {
3361
3362
3363
3364
3365 if err != nil {
3366 t.Fatalf("Do: %v", err)
3367 }
3368 if res.StatusCode != 431 {
3369 t.Fatalf("expected 431 response status; got: %d %s", res.StatusCode, res.Status)
3370 }
3371 }
3372 }
3373
3374 func TestRequestHeaderValueCountLimit(t *testing.T) {
3375 runNoSynctest(t, testRequestHeaderValueCountLimit)
3376 }
3377 func testRequestHeaderValueCountLimit(t *testing.T, mode testMode) {
3378 tests := []struct {
3379 name string
3380 limit int
3381 setup func(req *Request)
3382 wantStatus int
3383 }{
3384 {
3385 name: "below limit",
3386 limit: 15,
3387 setup: func(req *Request) {
3388
3389
3390
3391 for i := range 5 {
3392 req.Header.Add(fmt.Sprintf("X-Header-%d", i), "val")
3393 }
3394 },
3395 wantStatus: 200,
3396 },
3397 {
3398 name: "above limit",
3399 limit: 15,
3400 setup: func(req *Request) {
3401 for i := range 16 {
3402 req.Header.Add(fmt.Sprintf("X-Header-%d", i), "val")
3403 }
3404 },
3405 wantStatus: 431,
3406 },
3407 {
3408 name: "comma separated values count as one",
3409 limit: 15,
3410 setup: func(req *Request) {
3411 vals := make([]string, 16)
3412 for i := range vals {
3413 vals[i] = "val"
3414 }
3415 req.Header.Add("X-Comma", strings.Join(vals, ", "))
3416 },
3417 wantStatus: 200,
3418 },
3419 {
3420 name: "multiple values count as multiple",
3421 limit: 15,
3422 setup: func(req *Request) {
3423 for range 16 {
3424 req.Header.Add("X-Repeated", "val")
3425 }
3426 },
3427 wantStatus: 431,
3428 },
3429 {
3430
3431
3432
3433
3434
3435 name: "comma separated trailer values count as multiple",
3436 limit: 15,
3437 setup: func(req *Request) {
3438 req.Body = NoBody
3439 req.TransferEncoding = []string{"chunked"}
3440 req.Trailer = make(Header)
3441 for i := range 16 {
3442 req.Trailer[fmt.Sprintf("X-Trailer-%d", i)] = nil
3443 }
3444 },
3445 wantStatus: 431,
3446 },
3447 }
3448 for _, tt := range tests {
3449 synctest.Subtest(t, tt.name, func(t *testing.T) {
3450 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3451 w.WriteHeader(StatusOK)
3452 }), func(s *Server) {
3453 s.MaxHeaderValueCount = tt.limit
3454 }, optQuietLog)
3455
3456 req, _ := NewRequest("GET", cst.ts.URL, nil)
3457 tt.setup(req)
3458
3459 res, err := cst.c.Do(req)
3460 if err != nil {
3461 t.Fatal(err)
3462 }
3463 defer res.Body.Close()
3464 if res.StatusCode != tt.wantStatus {
3465 t.Errorf("got status %d, want %d", res.StatusCode, tt.wantStatus)
3466 }
3467 })
3468 }
3469 }
3470
3471 func TestRequestTrailerHeaderValueCountLimit(t *testing.T) {
3472 runNoSynctest(t, testRequestTrailerHeaderValueCountLimit)
3473 }
3474 func testRequestTrailerHeaderValueCountLimit(t *testing.T, mode testMode) {
3475 tests := []struct {
3476 name string
3477 limit int
3478 setup func(req *Request)
3479 wantErr bool
3480 }{
3481 {
3482 name: "below limit",
3483 limit: 15,
3484 setup: func(req *Request) {
3485 req.Trailer = make(Header)
3486 for i := range 14 {
3487 req.Trailer.Add(fmt.Sprintf("X-Trailer-%d", i), "val")
3488 }
3489 },
3490 },
3491 {
3492 name: "above limit",
3493 limit: 15,
3494 setup: func(req *Request) {
3495 req.Trailer = make(Header)
3496 for i := range 16 {
3497 req.Trailer.Add(fmt.Sprintf("X-Trailer-%d", i), "val")
3498 }
3499 },
3500 wantErr: true,
3501 },
3502 {
3503 name: "comma separated values count as one",
3504 limit: 15,
3505 setup: func(req *Request) {
3506 req.Trailer = make(Header)
3507 vals := make([]string, 16)
3508 for i := range vals {
3509 vals[i] = "val"
3510 }
3511 req.Trailer.Add("X-Comma-Trailer", strings.Join(vals, ", "))
3512 },
3513 },
3514 {
3515 name: "multiple values count as multiple",
3516 limit: 15,
3517 setup: func(req *Request) {
3518 req.Trailer = make(Header)
3519 for range 16 {
3520 req.Trailer.Add("X-Repeated-Trailer", "val")
3521 }
3522 },
3523 wantErr: true,
3524 },
3525 }
3526 for _, tt := range tests {
3527 synctest.Subtest(t, tt.name, func(t *testing.T) {
3528 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3529 _, err := io.Copy(io.Discard, r.Body)
3530 if (err != nil) != tt.wantErr {
3531 t.Errorf("Read = %v, want %v", err, tt.wantErr)
3532 }
3533 }), func(s *Server) {
3534 s.MaxHeaderValueCount = tt.limit
3535 }, optQuietLog)
3536
3537 req, _ := NewRequest("GET", cst.ts.URL, strings.NewReader("some body"))
3538 req.TransferEncoding = []string{"chunked"}
3539 tt.setup(req)
3540
3541
3542
3543 res, err := cst.c.Do(req)
3544 if err != nil && !tt.wantErr {
3545 t.Fatalf("unexpected Do error: %v", err)
3546 }
3547 if err == nil {
3548 res.Body.Close()
3549 }
3550 })
3551 }
3552 }
3553
3554 type neverEnding byte
3555
3556 func (b neverEnding) Read(p []byte) (n int, err error) {
3557 for i := range p {
3558 p[i] = byte(b)
3559 }
3560 return len(p), nil
3561 }
3562
3563 type bodyLimitReader struct {
3564 mu sync.Mutex
3565 count int
3566 limit int
3567 closed chan struct{}
3568 }
3569
3570 func (r *bodyLimitReader) Read(p []byte) (int, error) {
3571 r.mu.Lock()
3572 defer r.mu.Unlock()
3573 select {
3574 case <-r.closed:
3575 return 0, errors.New("closed")
3576 default:
3577 }
3578 if r.count > r.limit {
3579 return 0, errors.New("at limit")
3580 }
3581 r.count += len(p)
3582 for i := range p {
3583 p[i] = 'a'
3584 }
3585 return len(p), nil
3586 }
3587
3588 func (r *bodyLimitReader) Close() error {
3589 r.mu.Lock()
3590 defer r.mu.Unlock()
3591 close(r.closed)
3592 return nil
3593 }
3594
3595 func TestRequestBodyLimit(t *testing.T) { runSynctest(t, testRequestBodyLimit) }
3596 func testRequestBodyLimit(t *testing.T, mode testMode) {
3597 const limit = 1 << 20
3598 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3599 r.Body = MaxBytesReader(w, r.Body, limit)
3600 n, err := io.Copy(io.Discard, r.Body)
3601 if err == nil {
3602 t.Errorf("expected error from io.Copy")
3603 }
3604 if n != limit {
3605 t.Errorf("io.Copy = %d, want %d", n, limit)
3606 }
3607 mbErr, ok := err.(*MaxBytesError)
3608 if !ok {
3609 t.Errorf("expected MaxBytesError, got %T", err)
3610 }
3611 if mbErr.Limit != limit {
3612 t.Errorf("MaxBytesError.Limit = %d, want %d", mbErr.Limit, limit)
3613 }
3614 }))
3615
3616 body := &bodyLimitReader{
3617 closed: make(chan struct{}),
3618 limit: limit * 200,
3619 }
3620 req, _ := NewRequest("POST", cst.ts.URL, body)
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631 resp, err := cst.c.Do(req)
3632 if err == nil {
3633 resp.Body.Close()
3634 }
3635
3636
3637 <-body.closed
3638
3639 if body.count > limit*100 {
3640 t.Errorf("handler restricted the request body to %d bytes, but client managed to write %d",
3641 limit, body.count)
3642 }
3643 }
3644
3645
3646
3647 func TestClientWriteShutdown(t *testing.T) { runSynctest(t, testClientWriteShutdown, http3SkippedMode) }
3648 func testClientWriteShutdown(t *testing.T, mode testMode) {
3649 if runtime.GOOS == "plan9" {
3650 t.Skip("skipping test; see https://golang.org/issue/17906")
3651 }
3652 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}))
3653 _, conn := cst.dialNettest()
3654 err := conn.CloseWrite()
3655 if err != nil {
3656 t.Fatalf("CloseWrite: %v", err)
3657 }
3658
3659 bs, err := io.ReadAll(conn)
3660 if err != nil {
3661 t.Errorf("ReadAll: %v", err)
3662 }
3663 got := string(bs)
3664 if got != "" {
3665 t.Errorf("read %q from server; want nothing", got)
3666 }
3667 }
3668
3669
3670
3671 func TestServerBufferedChunking(t *testing.T) {
3672 conn := new(testConn)
3673 conn.readBuf.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"))
3674 conn.closec = make(chan bool, 1)
3675 ls := &oneConnListener{conn}
3676 go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
3677 rw.(Flusher).Flush()
3678 rw.Write([]byte{'x'})
3679 rw.Write([]byte{'y'})
3680 rw.Write([]byte{'z'})
3681 }))
3682 <-conn.closec
3683 if !bytes.HasSuffix(conn.writeBuf.Bytes(), []byte("\r\n\r\n3\r\nxyz\r\n0\r\n\r\n")) {
3684 t.Errorf("response didn't end with a single 3 byte 'xyz' chunk; got:\n%q",
3685 conn.writeBuf.Bytes())
3686 }
3687 }
3688
3689
3690
3691
3692
3693 func TestServerGracefulClose(t *testing.T) {
3694 synctest.Test(t, func(t *testing.T) {
3695 timeout := 50 * time.Millisecond
3696 SetRSTAvoidanceDelay(t, timeout)
3697
3698 st := newHTTP1ServerTest(t, HandlerFunc(func(w ResponseWriter, r *Request) {
3699 Error(w, "bye", StatusUnauthorized)
3700 }))
3701
3702 conn := st.dial()
3703 conn.writeMessage(joinCRLF(
3704 "POST / HTTP/1.1",
3705 "Host: foo.com",
3706 "Content-Length: 1000000",
3707 "",
3708 ))
3709 conn.wantResponse("HTTP/1.1 401 Unauthorized", nil)
3710 conn.wantBytes([]byte("bye\n"))
3711 conn.wantClosed()
3712
3713 synctest.Sleep(timeout - time.Nanosecond)
3714 if conn.conn.Peer().IsClosed() {
3715 t.Fatalf("peer closed connection before RSTAvoidanceDelay")
3716 }
3717
3718 synctest.Sleep(time.Nanosecond)
3719 if !conn.conn.Peer().IsClosed() {
3720 t.Fatalf("peer did not close connection after RSTAvoidanceDelay")
3721 }
3722 })
3723 }
3724
3725 func TestCaseSensitiveMethod(t *testing.T) { runSynctest(t, testCaseSensitiveMethod) }
3726 func testCaseSensitiveMethod(t *testing.T, mode testMode) {
3727 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3728 if r.Method != "get" {
3729 t.Errorf(`Got method %q; want "get"`, r.Method)
3730 }
3731 }))
3732 defer cst.close()
3733 req, _ := NewRequest("get", cst.ts.URL, nil)
3734 res, err := cst.c.Do(req)
3735 if err != nil {
3736 t.Error(err)
3737 return
3738 }
3739
3740 res.Body.Close()
3741 }
3742
3743
3744
3745
3746
3747 func TestContentLengthZero(t *testing.T) {
3748 runSynctest(t, testContentLengthZero, []testMode{http1Mode})
3749 }
3750 func testContentLengthZero(t *testing.T, mode testMode) {
3751 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {}))
3752
3753 for _, version := range []string{"HTTP/1.0", "HTTP/1.1"} {
3754 conn, _ := cst.dialNettest()
3755 _, err := fmt.Fprintf(conn, "GET / %v\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n", version)
3756 if err != nil {
3757 t.Fatalf("error writing: %v", err)
3758 }
3759 req, _ := NewRequest("GET", "/", nil)
3760 res, err := ReadResponse(bufio.NewReader(conn), req)
3761 if err != nil {
3762 t.Fatalf("error reading response: %v", err)
3763 }
3764 if te := res.TransferEncoding; len(te) > 0 {
3765 t.Errorf("For version %q, Transfer-Encoding = %q; want none", version, te)
3766 }
3767 if cl := res.ContentLength; cl != 0 {
3768 t.Errorf("For version %q, Content-Length = %v; want 0", version, cl)
3769 }
3770 conn.Close()
3771 }
3772 }
3773
3774 func TestCloseNotifier(t *testing.T) {
3775 runSynctest(t, testCloseNotifier, []testMode{http1Mode})
3776 }
3777 func testCloseNotifier(t *testing.T, mode testMode) {
3778 gotReq := make(chan bool, 1)
3779 sawClose := make(chan bool, 1)
3780 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
3781 gotReq <- true
3782 cc := rw.(CloseNotifier).CloseNotify()
3783 <-cc
3784 sawClose <- true
3785 }))
3786 conn, _ := cst.dialNettest()
3787 diec := make(chan bool)
3788 go func() {
3789 _, err := fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n")
3790 if err != nil {
3791 t.Error(err)
3792 return
3793 }
3794 <-diec
3795 conn.Close()
3796 }()
3797 For:
3798 for {
3799 select {
3800 case <-gotReq:
3801 diec <- true
3802 case <-sawClose:
3803 break For
3804 }
3805 }
3806 cst.ts.Close()
3807 }
3808
3809
3810
3811
3812
3813 func TestCloseNotifierPipelined(t *testing.T) {
3814 runSynctest(t, testCloseNotifierPipelined, []testMode{http1Mode})
3815 }
3816 func testCloseNotifierPipelined(t *testing.T, mode testMode) {
3817 gotReq := make(chan bool, 2)
3818 sawClose := make(chan bool, 2)
3819 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
3820 gotReq <- true
3821 cc := rw.(CloseNotifier).CloseNotify()
3822 select {
3823 case <-cc:
3824 t.Error("unexpected CloseNotify")
3825 case <-time.After(100 * time.Millisecond):
3826 }
3827 sawClose <- true
3828 }))
3829 conn, _ := cst.dialNettest()
3830 diec := make(chan bool, 1)
3831 defer close(diec)
3832 go func() {
3833 const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n"
3834 _, err := io.WriteString(conn, req+req)
3835 if err != nil {
3836 t.Error(err)
3837 return
3838 }
3839 <-diec
3840 conn.Close()
3841 }()
3842 reqs := 0
3843 closes := 0
3844 for {
3845 select {
3846 case <-gotReq:
3847 reqs++
3848 if reqs > 2 {
3849 t.Fatal("too many requests")
3850 }
3851 case <-sawClose:
3852 closes++
3853 if closes > 1 {
3854 return
3855 }
3856 }
3857 }
3858 }
3859
3860 func TestCloseNotifierChanLeak(t *testing.T) {
3861 req := reqBytes("GET / HTTP/1.0\nHost: golang.org")
3862 for i := 0; i < 20; i++ {
3863 var output bytes.Buffer
3864 conn := &rwTestConn{
3865 Reader: bytes.NewReader(req),
3866 Writer: &output,
3867 closec: make(chan bool, 1),
3868 }
3869 ln := &oneConnListener{conn: conn}
3870 handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
3871
3872
3873
3874 _ = rw.(CloseNotifier).CloseNotify()
3875 })
3876 go Serve(ln, handler)
3877 <-conn.closec
3878 }
3879 }
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890 func TestHijackAfterCloseNotifier(t *testing.T) {
3891 runSynctest(t, testHijackAfterCloseNotifier, []testMode{http1Mode})
3892 }
3893 func testHijackAfterCloseNotifier(t *testing.T, mode testMode) {
3894 script := make(chan string, 2)
3895 script <- "closenotify"
3896 script <- "hijack"
3897 close(script)
3898 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3899 plan := <-script
3900 switch plan {
3901 default:
3902 panic("bogus plan; too many requests")
3903 case "closenotify":
3904 w.(CloseNotifier).CloseNotify()
3905 w.Header().Set("X-Addr", r.RemoteAddr)
3906 case "hijack":
3907 c, _, err := w.(Hijacker).Hijack()
3908 if err != nil {
3909 t.Errorf("Hijack in Handler: %v", err)
3910 return
3911 }
3912 if _, ok := c.(*nettest.Conn); !ok {
3913
3914
3915 t.Errorf("type of hijacked conn is %T; want *net.TCPConn", c)
3916 }
3917 fmt.Fprintf(c, "HTTP/1.0 200 OK\r\nX-Addr: %v\r\nContent-Length: 0\r\n\r\n", r.RemoteAddr)
3918 c.Close()
3919 return
3920 }
3921 })).ts
3922 res1, err := ts.Client().Get(ts.URL)
3923 if err != nil {
3924 log.Fatal(err)
3925 }
3926 res2, err := ts.Client().Get(ts.URL)
3927 if err != nil {
3928 log.Fatal(err)
3929 }
3930 addr1 := res1.Header.Get("X-Addr")
3931 addr2 := res2.Header.Get("X-Addr")
3932 if addr1 == "" || addr1 != addr2 {
3933 t.Errorf("addr1, addr2 = %q, %q; want same", addr1, addr2)
3934 }
3935 }
3936
3937 func TestHijackBeforeRequestBodyRead(t *testing.T) {
3938 runSynctest(t, testHijackBeforeRequestBodyRead, []testMode{http1Mode})
3939 }
3940 func testHijackBeforeRequestBodyRead(t *testing.T, mode testMode) {
3941 var requestBody = bytes.Repeat([]byte("a"), 1<<20)
3942 bodyOkay := make(chan bool, 1)
3943 gotCloseNotify := make(chan bool, 1)
3944 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3945 defer close(bodyOkay)
3946
3947 reqBody := r.Body
3948 r.Body = nil
3949
3950 gone := w.(CloseNotifier).CloseNotify()
3951 slurp, err := io.ReadAll(reqBody)
3952 if err != nil {
3953 t.Errorf("Body read: %v", err)
3954 return
3955 }
3956 if len(slurp) != len(requestBody) {
3957 t.Errorf("Backend read %d request body bytes; want %d", len(slurp), len(requestBody))
3958 return
3959 }
3960 if !bytes.Equal(slurp, requestBody) {
3961 t.Error("Backend read wrong request body.")
3962 return
3963 }
3964 bodyOkay <- true
3965 <-gone
3966 gotCloseNotify <- true
3967 }))
3968
3969 conn, _ := cst.dialNettest()
3970 defer conn.Close()
3971
3972 fmt.Fprintf(conn, "POST / HTTP/1.1\r\nHost: foo\r\nContent-Length: %d\r\n\r\n%s",
3973 len(requestBody), requestBody)
3974 if !<-bodyOkay {
3975
3976 return
3977 }
3978 conn.Close()
3979 <-gotCloseNotify
3980 }
3981
3982 func TestOptions(t *testing.T) { runSynctest(t, testOptions, []testMode{http1Mode}) }
3983 func testOptions(t *testing.T, mode testMode) {
3984 uric := make(chan string, 2)
3985 mux := NewServeMux()
3986 mux.HandleFunc("/", func(w ResponseWriter, r *Request) {
3987 uric <- r.RequestURI
3988 })
3989 cst := newClientServerTest(t, mode, mux)
3990
3991 conn, _ := cst.dialNettest()
3992 defer conn.Close()
3993
3994
3995 _, err := conn.Write([]byte("OPTIONS * HTTP/1.1\r\nHost: foo.com\r\n\r\n"))
3996 if err != nil {
3997 t.Fatal(err)
3998 }
3999 br := bufio.NewReader(conn)
4000 res, err := ReadResponse(br, &Request{Method: "OPTIONS"})
4001 if err != nil {
4002 t.Fatal(err)
4003 }
4004 if res.StatusCode != 200 {
4005 t.Errorf("Got non-200 response to OPTIONS *: %#v", res)
4006 }
4007
4008
4009 _, err = conn.Write([]byte("GET * HTTP/1.1\r\nHost: foo.com\r\n\r\n"))
4010 if err != nil {
4011 t.Fatal(err)
4012 }
4013 res, err = ReadResponse(br, &Request{Method: "GET"})
4014 if err != nil {
4015 t.Fatal(err)
4016 }
4017 if res.StatusCode != 400 {
4018 t.Errorf("Got non-400 response to GET *: %#v", res)
4019 }
4020
4021 res, err = cst.c.Get(cst.ts.URL + "/second")
4022 if err != nil {
4023 t.Fatal(err)
4024 }
4025 res.Body.Close()
4026 if got := <-uric; got != "/second" {
4027 t.Errorf("Handler saw request for %q; want /second", got)
4028 }
4029 }
4030
4031 func TestOptionsHandler(t *testing.T) { runSynctest(t, testOptionsHandler, []testMode{http1Mode}) }
4032 func testOptionsHandler(t *testing.T, mode testMode) {
4033 rc := make(chan *Request, 1)
4034
4035 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4036 rc <- r
4037 }), func(ts *httptest.Server) {
4038 ts.Config.DisableGeneralOptionsHandler = true
4039 })
4040
4041 conn, _ := cst.dialNettest()
4042 defer conn.Close()
4043
4044 _, err := conn.Write([]byte("OPTIONS * HTTP/1.1\r\nHost: foo.com\r\n\r\n"))
4045 if err != nil {
4046 t.Fatal(err)
4047 }
4048
4049 if got := <-rc; got.Method != "OPTIONS" || got.RequestURI != "*" {
4050 t.Errorf("Expected OPTIONS * request, got %v", got)
4051 }
4052 }
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063 func TestHeaderToWire(t *testing.T) {
4064 tests := []struct {
4065 name string
4066 handler func(ResponseWriter, *Request)
4067 check func(got, logs string) error
4068 }{
4069 {
4070 name: "write without Header",
4071 handler: func(rw ResponseWriter, r *Request) {
4072 rw.Write([]byte("hello world"))
4073 },
4074 check: func(got, logs string) error {
4075 if !strings.Contains(got, "Content-Length:") {
4076 return errors.New("no content-length")
4077 }
4078 if !strings.Contains(got, "Content-Type: text/plain") {
4079 return errors.New("no content-type")
4080 }
4081 return nil
4082 },
4083 },
4084 {
4085 name: "Header mutation before write",
4086 handler: func(rw ResponseWriter, r *Request) {
4087 h := rw.Header()
4088 h.Set("Content-Type", "some/type")
4089 rw.Write([]byte("hello world"))
4090 h.Set("Too-Late", "bogus")
4091 },
4092 check: func(got, logs string) error {
4093 if !strings.Contains(got, "Content-Length:") {
4094 return errors.New("no content-length")
4095 }
4096 if !strings.Contains(got, "Content-Type: some/type") {
4097 return errors.New("wrong content-type")
4098 }
4099 if strings.Contains(got, "Too-Late") {
4100 return errors.New("don't want too-late header")
4101 }
4102 return nil
4103 },
4104 },
4105 {
4106 name: "write then useless Header mutation",
4107 handler: func(rw ResponseWriter, r *Request) {
4108 rw.Write([]byte("hello world"))
4109 rw.Header().Set("Too-Late", "Write already wrote headers")
4110 },
4111 check: func(got, logs string) error {
4112 if strings.Contains(got, "Too-Late") {
4113 return errors.New("header appeared from after WriteHeader")
4114 }
4115 return nil
4116 },
4117 },
4118 {
4119 name: "flush then write",
4120 handler: func(rw ResponseWriter, r *Request) {
4121 rw.(Flusher).Flush()
4122 rw.Write([]byte("post-flush"))
4123 rw.Header().Set("Too-Late", "Write already wrote headers")
4124 },
4125 check: func(got, logs string) error {
4126 if !strings.Contains(got, "Transfer-Encoding: chunked") {
4127 return errors.New("not chunked")
4128 }
4129 if strings.Contains(got, "Too-Late") {
4130 return errors.New("header appeared from after WriteHeader")
4131 }
4132 return nil
4133 },
4134 },
4135 {
4136 name: "header then flush",
4137 handler: func(rw ResponseWriter, r *Request) {
4138 rw.Header().Set("Content-Type", "some/type")
4139 rw.(Flusher).Flush()
4140 rw.Write([]byte("post-flush"))
4141 rw.Header().Set("Too-Late", "Write already wrote headers")
4142 },
4143 check: func(got, logs string) error {
4144 if !strings.Contains(got, "Transfer-Encoding: chunked") {
4145 return errors.New("not chunked")
4146 }
4147 if strings.Contains(got, "Too-Late") {
4148 return errors.New("header appeared from after WriteHeader")
4149 }
4150 if !strings.Contains(got, "Content-Type: some/type") {
4151 return errors.New("wrong content-type")
4152 }
4153 return nil
4154 },
4155 },
4156 {
4157 name: "sniff-on-first-write content-type",
4158 handler: func(rw ResponseWriter, r *Request) {
4159 rw.Write([]byte("<html><head></head><body>some html</body></html>"))
4160 rw.Header().Set("Content-Type", "x/wrong")
4161 },
4162 check: func(got, logs string) error {
4163 if !strings.Contains(got, "Content-Type: text/html") {
4164 return errors.New("wrong content-type; want html")
4165 }
4166 return nil
4167 },
4168 },
4169 {
4170 name: "explicit content-type wins",
4171 handler: func(rw ResponseWriter, r *Request) {
4172 rw.Header().Set("Content-Type", "some/type")
4173 rw.Write([]byte("<html><head></head><body>some html</body></html>"))
4174 },
4175 check: func(got, logs string) error {
4176 if !strings.Contains(got, "Content-Type: some/type") {
4177 return errors.New("wrong content-type; want html")
4178 }
4179 return nil
4180 },
4181 },
4182 {
4183 name: "empty handler",
4184 handler: func(rw ResponseWriter, r *Request) {
4185 },
4186 check: func(got, logs string) error {
4187 if !strings.Contains(got, "Content-Length: 0") {
4188 return errors.New("want 0 content-length")
4189 }
4190 return nil
4191 },
4192 },
4193 {
4194 name: "only Header, no write",
4195 handler: func(rw ResponseWriter, r *Request) {
4196 rw.Header().Set("Some-Header", "some-value")
4197 },
4198 check: func(got, logs string) error {
4199 if !strings.Contains(got, "Some-Header") {
4200 return errors.New("didn't get header")
4201 }
4202 return nil
4203 },
4204 },
4205 {
4206 name: "WriteHeader call",
4207 handler: func(rw ResponseWriter, r *Request) {
4208 rw.WriteHeader(404)
4209 rw.Header().Set("Too-Late", "some-value")
4210 },
4211 check: func(got, logs string) error {
4212 if !strings.Contains(got, "404") {
4213 return errors.New("wrong status")
4214 }
4215 if strings.Contains(got, "Too-Late") {
4216 return errors.New("shouldn't have seen Too-Late")
4217 }
4218 return nil
4219 },
4220 },
4221 }
4222 for _, tc := range tests {
4223 ht := newHandlerTest(HandlerFunc(tc.handler))
4224 got := ht.rawResponse("GET / HTTP/1.1\nHost: golang.org")
4225 logs := ht.logbuf.String()
4226 if err := tc.check(got, logs); err != nil {
4227 t.Errorf("%s: %v\nGot response:\n%s\n\n%s", tc.name, err, got, logs)
4228 }
4229 }
4230 }
4231
4232 type errorListener struct {
4233 errs []error
4234 }
4235
4236 func (l *errorListener) Accept() (c net.Conn, err error) {
4237 if len(l.errs) == 0 {
4238 return nil, io.EOF
4239 }
4240 err = l.errs[0]
4241 l.errs = l.errs[1:]
4242 return
4243 }
4244
4245 func (l *errorListener) Close() error {
4246 return nil
4247 }
4248
4249 func (l *errorListener) Addr() net.Addr {
4250 return dummyAddr("test-address")
4251 }
4252
4253 func TestAcceptMaxFds(t *testing.T) {
4254 t.Parallel()
4255
4256 ln := &errorListener{[]error{
4257 &net.OpError{
4258 Op: "accept",
4259 Err: syscall.EMFILE,
4260 }}}
4261 server := &Server{
4262 Handler: HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})),
4263 ErrorLog: log.New(io.Discard, "", 0),
4264 }
4265 err := server.Serve(ln)
4266 if err != io.EOF {
4267 t.Errorf("got error %v, want EOF", err)
4268 }
4269 }
4270
4271 func TestWriteAfterHijack(t *testing.T) {
4272 req := reqBytes("GET / HTTP/1.1\nHost: golang.org")
4273 var buf strings.Builder
4274 wrotec := make(chan bool, 1)
4275 conn := &rwTestConn{
4276 Reader: bytes.NewReader(req),
4277 Writer: &buf,
4278 closec: make(chan bool, 1),
4279 }
4280 handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
4281 conn, bufrw, err := rw.(Hijacker).Hijack()
4282 if err != nil {
4283 t.Error(err)
4284 return
4285 }
4286 go func() {
4287 bufrw.Write([]byte("[hijack-to-bufw]"))
4288 bufrw.Flush()
4289 conn.Write([]byte("[hijack-to-conn]"))
4290 conn.Close()
4291 wrotec <- true
4292 }()
4293 })
4294 ln := &oneConnListener{conn: conn}
4295 go Serve(ln, handler)
4296 <-conn.closec
4297 <-wrotec
4298 if g, w := buf.String(), "[hijack-to-bufw][hijack-to-conn]"; g != w {
4299 t.Errorf("wrote %q; want %q", g, w)
4300 }
4301 }
4302
4303 func TestDoubleHijack(t *testing.T) {
4304 req := reqBytes("GET / HTTP/1.1\nHost: golang.org")
4305 var buf bytes.Buffer
4306 conn := &rwTestConn{
4307 Reader: bytes.NewReader(req),
4308 Writer: &buf,
4309 closec: make(chan bool, 1),
4310 }
4311 handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
4312 conn, _, err := rw.(Hijacker).Hijack()
4313 if err != nil {
4314 t.Error(err)
4315 return
4316 }
4317 _, _, err = rw.(Hijacker).Hijack()
4318 if err == nil {
4319 t.Errorf("got err = nil; want err != nil")
4320 }
4321 conn.Close()
4322 })
4323 ln := &oneConnListener{conn: conn}
4324 go Serve(ln, handler)
4325 <-conn.closec
4326 }
4327
4328
4329
4330
4331
4332
4333
4334 func TestHTTP10ConnectionHeader(t *testing.T) {
4335 runSynctest(t, testHTTP10ConnectionHeader, []testMode{http1Mode})
4336 }
4337 func testHTTP10ConnectionHeader(t *testing.T, mode testMode) {
4338 mux := NewServeMux()
4339 mux.Handle("/", HandlerFunc(func(ResponseWriter, *Request) {}))
4340 cst := newClientServerTest(t, mode, mux)
4341
4342
4343 tests := []struct {
4344 req string
4345 expect []string
4346 }{
4347 {
4348 req: "GET / HTTP/1.0\r\n\r\n",
4349 expect: nil,
4350 },
4351 {
4352 req: "OPTIONS * HTTP/1.0\r\n\r\n",
4353 expect: nil,
4354 },
4355 {
4356 req: "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n",
4357 expect: []string{"keep-alive"},
4358 },
4359 }
4360
4361 for _, tt := range tests {
4362 conn, _ := cst.dialNettest()
4363
4364 _, err := fmt.Fprint(conn, tt.req)
4365 if err != nil {
4366 t.Fatal("conn write err:", err)
4367 }
4368
4369 resp, err := ReadResponse(bufio.NewReader(conn), &Request{Method: "GET"})
4370 if err != nil {
4371 t.Fatal("ReadResponse err:", err)
4372 }
4373 conn.Close()
4374 resp.Body.Close()
4375
4376 got := resp.Header["Connection"]
4377 if !slices.Equal(got, tt.expect) {
4378 t.Errorf("wrong Connection headers for request %q. Got %q expect %q", tt.req, got, tt.expect)
4379 }
4380 }
4381 }
4382
4383
4384 func TestServerReaderFromOrder(t *testing.T) { runSynctest(t, testServerReaderFromOrder) }
4385 func testServerReaderFromOrder(t *testing.T, mode testMode) {
4386 pr, pw := io.Pipe()
4387 const size = 3 << 20
4388 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
4389 rw.Header().Set("Content-Type", "text/plain")
4390 done := make(chan bool)
4391 go func() {
4392 io.Copy(rw, pr)
4393 close(done)
4394 }()
4395 time.Sleep(25 * time.Millisecond)
4396 n, err := io.Copy(io.Discard, req.Body)
4397 if err != nil {
4398 t.Errorf("handler Copy: %v", err)
4399 return
4400 }
4401 if n != size {
4402 t.Errorf("handler Copy = %d; want %d", n, size)
4403 }
4404 pw.Write([]byte("hi"))
4405 pw.Close()
4406 <-done
4407 }))
4408
4409 req, err := NewRequest("POST", cst.ts.URL, io.LimitReader(neverEnding('a'), size))
4410 if err != nil {
4411 t.Fatal(err)
4412 }
4413 res, err := cst.c.Do(req)
4414 if err != nil {
4415 t.Fatal(err)
4416 }
4417 all, err := io.ReadAll(res.Body)
4418 if err != nil {
4419 t.Fatal(err)
4420 }
4421 res.Body.Close()
4422 if string(all) != "hi" {
4423 t.Errorf("Body = %q; want hi", all)
4424 }
4425 }
4426
4427
4428 func TestCodesPreventingContentTypeAndBody(t *testing.T) {
4429 for _, code := range []int{StatusNotModified, StatusNoContent} {
4430 ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
4431 if r.URL.Path == "/header" {
4432 w.Header().Set("Content-Length", "123")
4433 }
4434 w.WriteHeader(code)
4435 if r.URL.Path == "/more" {
4436 w.Write([]byte("stuff"))
4437 }
4438 }))
4439 for _, req := range []string{
4440 "GET / HTTP/1.0",
4441 "GET /header HTTP/1.0",
4442 "GET /more HTTP/1.0",
4443 "GET / HTTP/1.1\nHost: foo",
4444 "GET /header HTTP/1.1\nHost: foo",
4445 "GET /more HTTP/1.1\nHost: foo",
4446 } {
4447 got := ht.rawResponse(req)
4448 wantStatus := fmt.Sprintf("%d %s", code, StatusText(code))
4449 if !strings.Contains(got, wantStatus) {
4450 t.Errorf("Code %d: Wanted %q Modified for %q: %s", code, wantStatus, req, got)
4451 } else if strings.Contains(got, "Content-Length") {
4452 t.Errorf("Code %d: Got a Content-Length from %q: %s", code, req, got)
4453 } else if strings.Contains(got, "stuff") {
4454 t.Errorf("Code %d: Response contains a body from %q: %s", code, req, got)
4455 }
4456 }
4457 }
4458 }
4459
4460 func TestContentTypeOkayOn204(t *testing.T) {
4461 ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
4462 w.Header().Set("Content-Length", "123")
4463 w.Header().Set("Content-Type", "foo/bar")
4464 w.WriteHeader(204)
4465 }))
4466 got := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
4467 if !strings.Contains(got, "Content-Type: foo/bar") {
4468 t.Errorf("Response = %q; want Content-Type: foo/bar", got)
4469 }
4470 if strings.Contains(got, "Content-Length: 123") {
4471 t.Errorf("Response = %q; don't want a Content-Length", got)
4472 }
4473 }
4474
4475
4476
4477
4478
4479
4480
4481 func TestTransportAndServerSharedBodyRace(t *testing.T) {
4482 runSynctest(t, testTransportAndServerSharedBodyRace)
4483 }
4484 func testTransportAndServerSharedBodyRace(t *testing.T, mode testMode) {
4485 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
4486
4487
4488
4489 go req.Body.Close()
4490 }))
4491 res, err := cst.c.Post(cst.ts.URL, "text/plain", strings.NewReader("hello"))
4492 if err != nil {
4493 t.Fatalf("original request: %v", err)
4494 }
4495 res.Body.Close()
4496 }
4497
4498
4499
4500
4501 func TestRequestBodyCloseDoesntBlock(t *testing.T) {
4502 runSynctest(t, testRequestBodyCloseDoesntBlock, []testMode{http1Mode})
4503 }
4504 func testRequestBodyCloseDoesntBlock(t *testing.T, mode testMode) {
4505 readErrCh := make(chan error, 1)
4506 errCh := make(chan error, 2)
4507
4508 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
4509 go func(body io.Reader) {
4510 _, err := body.Read(make([]byte, 100))
4511 readErrCh <- err
4512 }(req.Body)
4513 time.Sleep(500 * time.Millisecond)
4514 }))
4515
4516 closeConn := make(chan bool)
4517 defer close(closeConn)
4518 go func() {
4519 conn, _ := cst.dialNettest()
4520 defer conn.Close()
4521 _, err := conn.Write([]byte("POST / HTTP/1.1\r\nConnection: close\r\nHost: foo\r\nContent-Length: 100000\r\n\r\n"))
4522 if err != nil {
4523 errCh <- err
4524 return
4525 }
4526
4527
4528 <-closeConn
4529 }()
4530 select {
4531 case err := <-readErrCh:
4532 if err == nil {
4533 t.Error("Read was nil. Expected error.")
4534 }
4535 case err := <-errCh:
4536 t.Error(err)
4537 }
4538 }
4539
4540
4541 func TestResponseWriterWriteString(t *testing.T) {
4542 okc := make(chan bool, 1)
4543 ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
4544 _, ok := w.(io.StringWriter)
4545 okc <- ok
4546 }))
4547 ht.rawResponse("GET / HTTP/1.0")
4548 select {
4549 case ok := <-okc:
4550 if !ok {
4551 t.Error("ResponseWriter did not implement io.StringWriter")
4552 }
4553 default:
4554 t.Error("handler was never called")
4555 }
4556 }
4557
4558 func TestServerConnState(t *testing.T) { runSynctest(t, testServerConnState, []testMode{http1Mode}) }
4559 func testServerConnState(t *testing.T, mode testMode) {
4560 handler := map[string]func(w ResponseWriter, r *Request){
4561 "/": func(w ResponseWriter, r *Request) {
4562 fmt.Fprintf(w, "Hello.")
4563 },
4564 "/close": func(w ResponseWriter, r *Request) {
4565 w.Header().Set("Connection", "close")
4566 fmt.Fprintf(w, "Hello.")
4567 },
4568 "/hijack": func(w ResponseWriter, r *Request) {
4569 c, _, _ := w.(Hijacker).Hijack()
4570 c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
4571 c.Close()
4572 },
4573 "/hijack-panic": func(w ResponseWriter, r *Request) {
4574 c, _, _ := w.(Hijacker).Hijack()
4575 c.Write([]byte("HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello."))
4576 c.Close()
4577 panic("intentional panic")
4578 },
4579 }
4580
4581
4582 type stateLog struct {
4583 active net.Conn
4584 got []ConnState
4585 want []ConnState
4586 complete chan<- struct{}
4587 }
4588 activeLog := make(chan *stateLog, 1)
4589
4590
4591
4592
4593 wantLog := func(doRequests func(), want ...ConnState) {
4594 t.Helper()
4595 complete := make(chan struct{})
4596 activeLog <- &stateLog{want: want, complete: complete}
4597
4598 doRequests()
4599
4600 <-complete
4601 sl := <-activeLog
4602 if !slices.Equal(sl.got, sl.want) {
4603 t.Errorf("Request(s) produced unexpected state sequence.\nGot: %v\nWant: %v", sl.got, sl.want)
4604 }
4605
4606
4607
4608 }
4609
4610 cst := newClientServerTest(t, mode, nil, func(ts *httptest.Server) {
4611 ts.Config.ErrorLog = log.New(io.Discard, "", 0)
4612 ts.Config.ConnState = func(c net.Conn, state ConnState) {
4613 if c == nil {
4614 t.Errorf("nil conn seen in state %s", state)
4615 return
4616 }
4617 sl := <-activeLog
4618 if sl.active == nil && state == StateNew {
4619 sl.active = c
4620 } else if sl.active != c {
4621 t.Errorf("unexpected conn in state %s", state)
4622 activeLog <- sl
4623 return
4624 }
4625 sl.got = append(sl.got, state)
4626 if sl.complete != nil && (len(sl.got) >= len(sl.want) || !slices.Equal(sl.got, sl.want[:len(sl.got)])) {
4627 close(sl.complete)
4628 sl.complete = nil
4629 }
4630 activeLog <- sl
4631 }
4632 })
4633 ts := cst.ts
4634 ts.Config.Handler = HandlerFunc(func(w ResponseWriter, r *Request) {
4635 handler[r.URL.Path](w, r)
4636 })
4637 defer func() {
4638 activeLog <- &stateLog{}
4639 ts.Close()
4640 }()
4641
4642 c := ts.Client()
4643
4644 mustGet := func(url string, headers ...string) {
4645 t.Helper()
4646 req, err := NewRequest("GET", url, nil)
4647 if err != nil {
4648 t.Fatal(err)
4649 }
4650 for len(headers) > 0 {
4651 req.Header.Add(headers[0], headers[1])
4652 headers = headers[2:]
4653 }
4654 res, err := c.Do(req)
4655 if err != nil {
4656 t.Errorf("Error fetching %s: %v", url, err)
4657 return
4658 }
4659 _, err = io.ReadAll(res.Body)
4660 defer res.Body.Close()
4661 if err != nil {
4662 t.Errorf("Error reading %s: %v", url, err)
4663 }
4664 }
4665
4666 wantLog(func() {
4667 mustGet(ts.URL + "/")
4668 mustGet(ts.URL + "/close")
4669 }, StateNew, StateActive, StateIdle, StateActive, StateClosed)
4670
4671 wantLog(func() {
4672 mustGet(ts.URL + "/")
4673 mustGet(ts.URL+"/", "Connection", "close")
4674 }, StateNew, StateActive, StateIdle, StateActive, StateClosed)
4675
4676 wantLog(func() {
4677 mustGet(ts.URL + "/hijack")
4678 }, StateNew, StateActive, StateHijacked)
4679
4680 wantLog(func() {
4681 mustGet(ts.URL + "/hijack-panic")
4682 }, StateNew, StateActive, StateHijacked)
4683
4684 wantLog(func() {
4685 c, _ := cst.dialNettest()
4686 c.Close()
4687 }, StateNew, StateClosed)
4688
4689 wantLog(func() {
4690 c, _ := cst.dialNettest()
4691 if _, err := io.WriteString(c, "BOGUS REQUEST\r\n\r\n"); err != nil {
4692 t.Fatal(err)
4693 }
4694 c.Read(make([]byte, 1))
4695 c.Close()
4696 }, StateNew, StateActive, StateClosed)
4697
4698 wantLog(func() {
4699 c, _ := cst.dialNettest()
4700 if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
4701 t.Fatal(err)
4702 }
4703 res, err := ReadResponse(bufio.NewReader(c), nil)
4704 if err != nil {
4705 t.Fatal(err)
4706 }
4707 if _, err := io.Copy(io.Discard, res.Body); err != nil {
4708 t.Fatal(err)
4709 }
4710 c.Close()
4711 }, StateNew, StateActive, StateIdle, StateClosed)
4712 }
4713
4714 func TestServerKeepAlivesEnabledResultClose(t *testing.T) {
4715 runSynctest(t, testServerKeepAlivesEnabledResultClose, []testMode{http1Mode})
4716 }
4717 func testServerKeepAlivesEnabledResultClose(t *testing.T, mode testMode) {
4718 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4719 }), func(ts *httptest.Server) {
4720 ts.Config.SetKeepAlivesEnabled(false)
4721 }).ts
4722 res, err := ts.Client().Get(ts.URL)
4723 if err != nil {
4724 t.Fatal(err)
4725 }
4726 defer res.Body.Close()
4727 if !res.Close {
4728 t.Errorf("Body.Close == false; want true")
4729 }
4730 }
4731
4732
4733 func TestServerEmptyBodyRace(t *testing.T) { runSynctest(t, testServerEmptyBodyRace) }
4734 func testServerEmptyBodyRace(t *testing.T, mode testMode) {
4735 var n int32
4736 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
4737 atomic.AddInt32(&n, 1)
4738 }), optQuietLog)
4739 var wg sync.WaitGroup
4740 const reqs = 20
4741 for i := 0; i < reqs; i++ {
4742 wg.Add(1)
4743 go func() {
4744 defer wg.Done()
4745 res, err := cst.c.Get(cst.ts.URL)
4746 if err != nil {
4747
4748
4749 time.Sleep(10 * time.Millisecond)
4750 res, err = cst.c.Get(cst.ts.URL)
4751 if err != nil {
4752 t.Error(err)
4753 return
4754 }
4755 }
4756 defer res.Body.Close()
4757 _, err = io.Copy(io.Discard, res.Body)
4758 if err != nil {
4759 t.Error(err)
4760 return
4761 }
4762 }()
4763 }
4764 wg.Wait()
4765 if got := atomic.LoadInt32(&n); got != reqs {
4766 t.Errorf("handler ran %d times; want %d", got, reqs)
4767 }
4768 }
4769
4770 func TestServerConnStateNew(t *testing.T) {
4771 sawNew := false
4772 srv := &Server{
4773 ConnState: func(c net.Conn, state ConnState) {
4774 if state == StateNew {
4775 sawNew = true
4776 }
4777 },
4778 Handler: HandlerFunc(func(w ResponseWriter, r *Request) {}),
4779 }
4780 srv.Serve(&oneConnListener{
4781 conn: &rwTestConn{
4782 Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"),
4783 Writer: io.Discard,
4784 },
4785 })
4786 if !sawNew {
4787 t.Error("StateNew not seen")
4788 }
4789 }
4790
4791 type closeWriteTestConn struct {
4792 rwTestConn
4793 didCloseWrite bool
4794 }
4795
4796 func (c *closeWriteTestConn) CloseWrite() error {
4797 c.didCloseWrite = true
4798 return nil
4799 }
4800
4801 func TestCloseWrite(t *testing.T) {
4802 SetRSTAvoidanceDelay(t, 1*time.Millisecond)
4803
4804 var srv Server
4805 var testConn closeWriteTestConn
4806 c := ExportServerNewConn(&srv, &testConn)
4807 ExportCloseWriteAndWait(c)
4808 if !testConn.didCloseWrite {
4809 t.Error("didn't see CloseWrite call")
4810 }
4811 }
4812
4813
4814
4815
4816
4817
4818
4819
4820 func TestServerFlushAndHijack(t *testing.T) {
4821 runSynctest(t, testServerFlushAndHijack, []testMode{http1Mode})
4822 }
4823 func testServerFlushAndHijack(t *testing.T, mode testMode) {
4824 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4825 io.WriteString(w, "Hello, ")
4826 w.(Flusher).Flush()
4827 conn, buf, _ := w.(Hijacker).Hijack()
4828 buf.WriteString("6\r\nworld!\r\n0\r\n\r\n")
4829 if err := buf.Flush(); err != nil {
4830 t.Error(err)
4831 }
4832 if err := conn.Close(); err != nil {
4833 t.Error(err)
4834 }
4835 })).ts
4836 res, err := ts.Client().Get(ts.URL)
4837 if err != nil {
4838 t.Fatal(err)
4839 }
4840 defer res.Body.Close()
4841 all, err := io.ReadAll(res.Body)
4842 if err != nil {
4843 t.Fatal(err)
4844 }
4845 if want := "Hello, world!"; string(all) != want {
4846 t.Errorf("Got %q; want %q", all, want)
4847 }
4848 }
4849
4850
4851
4852
4853
4854
4855
4856 func TestServerKeepAliveAfterWriteError(t *testing.T) {
4857 runSynctest(t, testServerKeepAliveAfterWriteError, []testMode{http1Mode})
4858 }
4859 func testServerKeepAliveAfterWriteError(t *testing.T, mode testMode) {
4860 const numReq = 3
4861 addrc := make(chan string, numReq)
4862 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4863 addrc <- r.RemoteAddr
4864 time.Sleep(500 * time.Millisecond)
4865 w.(Flusher).Flush()
4866 }), func(ts *httptest.Server) {
4867 ts.Config.WriteTimeout = 250 * time.Millisecond
4868 }).ts
4869
4870 errc := make(chan error, numReq)
4871 go func() {
4872 defer close(errc)
4873 for i := 0; i < numReq; i++ {
4874 res, err := ts.Client().Get(ts.URL)
4875 if res != nil {
4876 res.Body.Close()
4877 }
4878 errc <- err
4879 }
4880 }()
4881
4882 addrSeen := map[string]bool{}
4883 numOkay := 0
4884 for {
4885 select {
4886 case v := <-addrc:
4887 addrSeen[v] = true
4888 case err, ok := <-errc:
4889 if !ok {
4890 if len(addrSeen) != numReq {
4891 t.Errorf("saw %d unique client addresses; want %d", len(addrSeen), numReq)
4892 }
4893 if numOkay != 0 {
4894 t.Errorf("got %d successful client requests; want 0", numOkay)
4895 }
4896 return
4897 }
4898 if err == nil {
4899 numOkay++
4900 }
4901 }
4902 }
4903 }
4904
4905
4906
4907 func TestNoContentLengthIfTransferEncoding(t *testing.T) {
4908 runSynctest(t, testNoContentLengthIfTransferEncoding, []testMode{http1Mode})
4909 }
4910 func testNoContentLengthIfTransferEncoding(t *testing.T, mode testMode) {
4911 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4912 w.Header().Set("Transfer-Encoding", "foo")
4913 io.WriteString(w, "<html>")
4914 }))
4915 c, _ := cst.dialNettest()
4916 defer c.Close()
4917 if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
4918 t.Fatal(err)
4919 }
4920 bs := bufio.NewScanner(c)
4921 var got strings.Builder
4922 for bs.Scan() {
4923 if strings.TrimSpace(bs.Text()) == "" {
4924 break
4925 }
4926 got.WriteString(bs.Text())
4927 got.WriteByte('\n')
4928 }
4929 if err := bs.Err(); err != nil {
4930 t.Fatal(err)
4931 }
4932 if strings.Contains(got.String(), "Content-Length") {
4933 t.Errorf("Unexpected Content-Length in response headers: %s", got.String())
4934 }
4935 if strings.Contains(got.String(), "Content-Type") {
4936 t.Errorf("Unexpected Content-Type in response headers: %s", got.String())
4937 }
4938 }
4939
4940
4941
4942 func TestTolerateCRLFBeforeRequestLine(t *testing.T) {
4943 req := []byte("POST / HTTP/1.1\r\nHost: golang.org\r\nContent-Length: 3\r\n\r\nABC" +
4944 "\r\n\r\n" +
4945 "GET / HTTP/1.1\r\nHost: golang.org\r\n\r\n")
4946 var buf bytes.Buffer
4947 conn := &rwTestConn{
4948 Reader: bytes.NewReader(req),
4949 Writer: &buf,
4950 closec: make(chan bool, 1),
4951 }
4952 ln := &oneConnListener{conn: conn}
4953 numReq := 0
4954 go Serve(ln, HandlerFunc(func(rw ResponseWriter, r *Request) {
4955 numReq++
4956 }))
4957 <-conn.closec
4958 if numReq != 2 {
4959 t.Errorf("num requests = %d; want 2", numReq)
4960 t.Logf("Res: %s", buf.Bytes())
4961 }
4962 }
4963
4964 func TestIssue13893_Expect100(t *testing.T) {
4965
4966 req := reqBytes(`PUT /readbody HTTP/1.1
4967 User-Agent: PycURL/7.22.0
4968 Host: 127.0.0.1:9000
4969 Accept: */*
4970 Expect: 100-continue
4971 Content-Length: 10
4972
4973 HelloWorld
4974
4975 `)
4976 var buf bytes.Buffer
4977 conn := &rwTestConn{
4978 Reader: bytes.NewReader(req),
4979 Writer: &buf,
4980 closec: make(chan bool, 1),
4981 }
4982 ln := &oneConnListener{conn: conn}
4983 go Serve(ln, HandlerFunc(func(w ResponseWriter, r *Request) {
4984 if _, ok := r.Header["Expect"]; !ok {
4985 t.Error("Expect header should not be filtered out")
4986 }
4987 }))
4988 <-conn.closec
4989 }
4990
4991 func TestIssue11549_Expect100(t *testing.T) {
4992 req := reqBytes(`PUT /readbody HTTP/1.1
4993 User-Agent: PycURL/7.22.0
4994 Host: 127.0.0.1:9000
4995 Accept: */*
4996 Expect: 100-continue
4997 Content-Length: 10
4998
4999 HelloWorldPUT /noreadbody HTTP/1.1
5000 User-Agent: PycURL/7.22.0
5001 Host: 127.0.0.1:9000
5002 Accept: */*
5003 Expect: 100-continue
5004 Content-Length: 10
5005
5006 GET /should-be-ignored HTTP/1.1
5007 Host: foo
5008
5009 `)
5010 var buf strings.Builder
5011 conn := &rwTestConn{
5012 Reader: bytes.NewReader(req),
5013 Writer: &buf,
5014 closec: make(chan bool, 1),
5015 }
5016 ln := &oneConnListener{conn: conn}
5017 numReq := 0
5018 go Serve(ln, HandlerFunc(func(w ResponseWriter, r *Request) {
5019 numReq++
5020 if r.URL.Path == "/readbody" {
5021 io.ReadAll(r.Body)
5022 }
5023 io.WriteString(w, "Hello world!")
5024 }))
5025 <-conn.closec
5026 if numReq != 2 {
5027 t.Errorf("num requests = %d; want 2", numReq)
5028 }
5029 if !strings.Contains(buf.String(), "Connection: close\r\n") {
5030 t.Errorf("expected 'Connection: close' in response; got: %s", buf.String())
5031 }
5032 }
5033
5034
5035
5036 func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) {
5037 t.Parallel()
5038 conn := newTestConn()
5039 conn.readBuf.WriteString(
5040 "POST / HTTP/1.1\r\n" +
5041 "Host: test\r\n" +
5042 "Content-Length: 9999999999\r\n" +
5043 "\r\n" + strings.Repeat("a", 1<<20))
5044
5045 ls := &oneConnListener{conn}
5046 var inHandlerLen int
5047 go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
5048 inHandlerLen = conn.readBuf.Len()
5049 rw.WriteHeader(404)
5050 }))
5051 <-conn.closec
5052 afterHandlerLen := conn.readBuf.Len()
5053
5054 if afterHandlerLen != inHandlerLen {
5055 t.Errorf("unexpected implicit read. Read buffer went from %d -> %d", inHandlerLen, afterHandlerLen)
5056 }
5057 }
5058
5059 func TestHandlerSetsBodyNil(t *testing.T) { runSynctest(t, testHandlerSetsBodyNil) }
5060 func testHandlerSetsBodyNil(t *testing.T, mode testMode) {
5061 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5062 r.Body = nil
5063 fmt.Fprintf(w, "%v", r.RemoteAddr)
5064 }))
5065 get := func() string {
5066 res, err := cst.c.Get(cst.ts.URL)
5067 if err != nil {
5068 t.Fatal(err)
5069 }
5070 defer res.Body.Close()
5071 slurp, err := io.ReadAll(res.Body)
5072 if err != nil {
5073 t.Fatal(err)
5074 }
5075 return string(slurp)
5076 }
5077 a, b := get(), get()
5078 if a != b {
5079 t.Errorf("Failed to reuse connections between requests: %v vs %v", a, b)
5080 }
5081 }
5082
5083
5084
5085 func TestServerValidatesHostHeader(t *testing.T) {
5086 tests := []struct {
5087 proto string
5088 host string
5089 want int
5090 }{
5091 {"HTTP/0.9", "", 505},
5092
5093 {"HTTP/1.1", "", 400},
5094 {"HTTP/1.1", "Host: \r\n", 200},
5095 {"HTTP/1.1", "Host: 1.2.3.4\r\n", 200},
5096 {"HTTP/1.1", "Host: foo.com\r\n", 200},
5097 {"HTTP/1.1", "Host: foo-bar_baz.com\r\n", 200},
5098 {"HTTP/1.1", "Host: foo.com:80\r\n", 200},
5099 {"HTTP/1.1", "Host: ::1\r\n", 200},
5100 {"HTTP/1.1", "Host: [::1]\r\n", 200},
5101 {"HTTP/1.1", "Host: [::1]:80\r\n", 200},
5102 {"HTTP/1.1", "Host: [::1%25en0]:80\r\n", 200},
5103 {"HTTP/1.1", "Host: 1.2.3.4\r\n", 200},
5104 {"HTTP/1.1", "Host: \x06\r\n", 400},
5105 {"HTTP/1.1", "Host: \xff\r\n", 400},
5106 {"HTTP/1.1", "Host: {\r\n", 400},
5107 {"HTTP/1.1", "Host: }\r\n", 400},
5108 {"HTTP/1.1", "Host: first\r\nHost: second\r\n", 400},
5109
5110
5111
5112 {"HTTP/1.0", "", 200},
5113 {"HTTP/1.0", "Host: first\r\nHost: second\r\n", 400},
5114 {"HTTP/1.0", "Host: \xff\r\n", 400},
5115
5116
5117 {"PRI * HTTP/2.0", "", 200},
5118
5119
5120 {"CONNECT golang.org:443 HTTP/1.1", "", 200},
5121
5122
5123 {"PRI / HTTP/2.0", "", 505},
5124 {"GET / HTTP/2.0", "", 505},
5125 {"GET / HTTP/3.0", "", 505},
5126 }
5127 for _, tt := range tests {
5128 conn := newTestConn()
5129 methodTarget := "GET / "
5130 if !strings.HasPrefix(tt.proto, "HTTP/") {
5131 methodTarget = ""
5132 }
5133 io.WriteString(&conn.readBuf, methodTarget+tt.proto+"\r\n"+tt.host+"\r\n")
5134
5135 ln := &oneConnListener{conn}
5136 srv := Server{
5137 ErrorLog: quietLog,
5138 Handler: HandlerFunc(func(ResponseWriter, *Request) {}),
5139 }
5140 go srv.Serve(ln)
5141 <-conn.closec
5142 res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
5143 if err != nil {
5144 t.Errorf("For %s %q, ReadResponse: %v", tt.proto, tt.host, res)
5145 continue
5146 }
5147 if res.StatusCode != tt.want {
5148 t.Errorf("For %s %q, Status = %d; want %d", tt.proto, tt.host, res.StatusCode, tt.want)
5149 }
5150 }
5151 }
5152
5153 func TestServerHandlersCanHandleH2PRI(t *testing.T) {
5154 runSynctest(t, testServerHandlersCanHandleH2PRI, []testMode{http1Mode})
5155 }
5156 func testServerHandlersCanHandleH2PRI(t *testing.T, mode testMode) {
5157 const upgradeResponse = "upgrade here"
5158 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5159 conn, br, err := w.(Hijacker).Hijack()
5160 if err != nil {
5161 t.Error(err)
5162 return
5163 }
5164 defer conn.Close()
5165 if r.Method != "PRI" || r.RequestURI != "*" {
5166 t.Errorf("Got method/target %q %q; want PRI *", r.Method, r.RequestURI)
5167 return
5168 }
5169 if !r.Close {
5170 t.Errorf("Request.Close = true; want false")
5171 }
5172 const want = "SM\r\n\r\n"
5173 buf := make([]byte, len(want))
5174 n, err := io.ReadFull(br, buf)
5175 if err != nil || string(buf[:n]) != want {
5176 t.Errorf("Read = %v, %v (%q), want %q", n, err, buf[:n], want)
5177 return
5178 }
5179 io.WriteString(conn, upgradeResponse)
5180 }))
5181
5182 c, _ := cst.dialNettest()
5183 defer c.Close()
5184 io.WriteString(c, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
5185 slurp, err := io.ReadAll(c)
5186 if err != nil {
5187 t.Fatal(err)
5188 }
5189 if string(slurp) != upgradeResponse {
5190 t.Errorf("Handler response = %q; want %q", slurp, upgradeResponse)
5191 }
5192 }
5193
5194
5195
5196 func TestServerValidatesHeaders(t *testing.T) {
5197 t.Parallel()
5198 tests := []struct {
5199 header string
5200 want int
5201 }{
5202 {"", 200},
5203 {"Foo: bar\r\n", 200},
5204 {"X-Foo: bar\r\n", 200},
5205 {"Foo: a space\r\n", 200},
5206
5207 {"A space: foo\r\n", 400},
5208 {"foo\xffbar: foo\r\n", 400},
5209 {"foo\x00bar: foo\r\n", 400},
5210 {"Foo: " + strings.Repeat("x", 1<<21) + "\r\n", 431},
5211
5212
5213 {"Foo : bar\r\n", 400},
5214 {"Foo\t: bar\r\n", 400},
5215
5216
5217
5218 {": empty key\r\n", 400},
5219
5220
5221
5222
5223 {"Content-Length: notdigits\r\n", 400},
5224 {"Content-Length: notdigits\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n", 400},
5225
5226 {"foo: foo foo\r\n", 200},
5227 {"foo: foo\tfoo\r\n", 200},
5228 {"foo: foo\x00foo\r\n", 400},
5229 {"foo: foo\x7ffoo\r\n", 400},
5230 {"foo: foo\xfffoo\r\n", 200},
5231 }
5232 for _, tt := range tests {
5233 conn := newTestConn()
5234 io.WriteString(&conn.readBuf, "GET / HTTP/1.1\r\nHost: foo\r\n"+tt.header+"\r\n")
5235
5236 ln := &oneConnListener{conn}
5237 srv := Server{
5238 ErrorLog: quietLog,
5239 Handler: HandlerFunc(func(ResponseWriter, *Request) {}),
5240 }
5241 go srv.Serve(ln)
5242 <-conn.closec
5243 res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
5244 if err != nil {
5245 t.Errorf("For %q, ReadResponse: %v", tt.header, res)
5246 continue
5247 }
5248 if res.StatusCode != tt.want {
5249 t.Errorf("For %q, Status = %d; want %d", tt.header, res.StatusCode, tt.want)
5250 }
5251 }
5252 }
5253
5254 func TestServerRequestContextCancel_ServeHTTPDone(t *testing.T) {
5255 runSynctest(t, testServerRequestContextCancel_ServeHTTPDone)
5256 }
5257 func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, mode testMode) {
5258 ctxc := make(chan context.Context, 1)
5259 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5260 ctx := r.Context()
5261 select {
5262 case <-ctx.Done():
5263 t.Error("should not be Done in ServeHTTP")
5264 default:
5265 }
5266 ctxc <- ctx
5267 }))
5268 res, err := cst.c.Get(cst.ts.URL)
5269 if err != nil {
5270 t.Fatal(err)
5271 }
5272 res.Body.Close()
5273 ctx := <-ctxc
5274 select {
5275 case <-ctx.Done():
5276 default:
5277 t.Error("context should be done after ServeHTTP completes")
5278 }
5279 }
5280
5281
5282
5283
5284 func TestServerRequestContextCancel_ConnClose(t *testing.T) {
5285 runSynctest(t, testServerRequestContextCancel_ConnClose)
5286 }
5287 func testServerRequestContextCancel_ConnClose(t *testing.T, mode testMode) {
5288 inHandler := make(chan struct{})
5289 handlerDone := make(chan struct{})
5290 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5291 close(inHandler)
5292 <-r.Context().Done()
5293 close(handlerDone)
5294 }))
5295 cc, err := cst.tr.NewClientConn(t.Context(), mode.Scheme(), "example.tld:80")
5296 if err != nil {
5297 t.Fatal(err)
5298 }
5299 defer cc.Close()
5300
5301 req, err := NewRequest("GET", cst.ts.URL, nil)
5302 if err != nil {
5303 t.Fatal(err)
5304 }
5305 var wg sync.WaitGroup
5306 wg.Go(func() {
5307 cc.RoundTrip(req)
5308 })
5309 defer wg.Wait()
5310
5311 <-inHandler
5312 cc.Close()
5313 <-handlerDone
5314 }
5315
5316 func TestServerContext_ServerContextKey(t *testing.T) {
5317 runSynctest(t, testServerContext_ServerContextKey)
5318 }
5319 func testServerContext_ServerContextKey(t *testing.T, mode testMode) {
5320 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5321 ctx := r.Context()
5322 got := ctx.Value(ServerContextKey)
5323 if _, ok := got.(*Server); !ok {
5324 t.Errorf("context value = %T; want *http.Server", got)
5325 }
5326 }))
5327 res, err := cst.c.Get(cst.ts.URL)
5328 if err != nil {
5329 t.Fatal(err)
5330 }
5331 res.Body.Close()
5332 }
5333
5334 func TestServerContext_LocalAddrContextKey(t *testing.T) {
5335 runNoSynctest(t, testServerContext_LocalAddrContextKey)
5336 }
5337 func testServerContext_LocalAddrContextKey(t *testing.T, mode testMode) {
5338 ch := make(chan any, 1)
5339 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5340 ch <- r.Context().Value(LocalAddrContextKey)
5341 }), optRealNet)
5342 if _, err := cst.c.Head(cst.ts.URL); err != nil {
5343 t.Fatal(err)
5344 }
5345
5346 host := cst.ts.Listener.Addr().String()
5347 got := <-ch
5348 if addr, ok := got.(net.Addr); !ok {
5349 t.Errorf("local addr value = %T; want net.Addr", got)
5350 } else if fmt.Sprint(addr) != host {
5351 t.Errorf("local addr = %v; want %v", addr, host)
5352 }
5353 }
5354
5355
5356 func TestHandlerSetTransferEncodingChunked(t *testing.T) {
5357 t.Parallel()
5358 ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
5359 w.Header().Set("Transfer-Encoding", "chunked")
5360 w.Write([]byte("hello"))
5361 }))
5362 resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
5363 const hdr = "Transfer-Encoding: chunked"
5364 if n := strings.Count(resp, hdr); n != 1 {
5365 t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp)
5366 }
5367 }
5368
5369
5370 func TestHandlerSetTransferEncodingGzip(t *testing.T) {
5371 t.Parallel()
5372 ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
5373 w.Header().Set("Transfer-Encoding", "gzip")
5374 gz := gzip.NewWriter(w)
5375 gz.Write([]byte("hello"))
5376 gz.Close()
5377 }))
5378 resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
5379 for _, v := range []string{"gzip", "chunked"} {
5380 hdr := "Transfer-Encoding: " + v
5381 if n := strings.Count(resp, hdr); n != 1 {
5382 t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp)
5383 }
5384 }
5385 }
5386
5387 func BenchmarkClientServer(b *testing.B) {
5388 runNoSynctest(b, benchmarkClientServer, []testMode{http1Mode, https1Mode, http2Mode})
5389 }
5390 func benchmarkClientServer(b *testing.B, mode testMode) {
5391 b.ReportAllocs()
5392 b.StopTimer()
5393 ts := newClientServerTest(b, mode, HandlerFunc(func(rw ResponseWriter, r *Request) {
5394 fmt.Fprintf(rw, "Hello world.\n")
5395 })).ts
5396 b.StartTimer()
5397
5398 c := ts.Client()
5399 for i := 0; i < b.N; i++ {
5400 res, err := c.Get(ts.URL)
5401 if err != nil {
5402 b.Fatal("Get:", err)
5403 }
5404 all, err := io.ReadAll(res.Body)
5405 res.Body.Close()
5406 if err != nil {
5407 b.Fatal("ReadAll:", err)
5408 }
5409 body := string(all)
5410 if body != "Hello world.\n" {
5411 b.Fatal("Got body:", body)
5412 }
5413 }
5414
5415 b.StopTimer()
5416 }
5417
5418 func BenchmarkClientServerParallel(b *testing.B) {
5419 for _, parallelism := range []int{4, 64} {
5420 b.Run(fmt.Sprint(parallelism), func(b *testing.B) {
5421 runNoSynctest(b, func(b *testing.B, mode testMode) {
5422 benchmarkClientServerParallel(b, parallelism, mode)
5423 }, []testMode{http1Mode, https1Mode, http2Mode})
5424 })
5425 }
5426 }
5427
5428 func benchmarkClientServerParallel(b *testing.B, parallelism int, mode testMode) {
5429 b.ReportAllocs()
5430 ts := newClientServerTest(b, mode, HandlerFunc(func(rw ResponseWriter, r *Request) {
5431 fmt.Fprintf(rw, "Hello world.\n")
5432 })).ts
5433 b.ResetTimer()
5434 b.SetParallelism(parallelism)
5435 b.RunParallel(func(pb *testing.PB) {
5436 c := ts.Client()
5437 for pb.Next() {
5438 res, err := c.Get(ts.URL)
5439 if err != nil {
5440 b.Logf("Get: %v", err)
5441 continue
5442 }
5443 all, err := io.ReadAll(res.Body)
5444 res.Body.Close()
5445 if err != nil {
5446 b.Logf("ReadAll: %v", err)
5447 continue
5448 }
5449 body := string(all)
5450 if body != "Hello world.\n" {
5451 panic("Got body: " + body)
5452 }
5453 }
5454 })
5455 }
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466 func BenchmarkServer(b *testing.B) {
5467 b.ReportAllocs()
5468
5469 if url := os.Getenv("GO_TEST_BENCH_SERVER_URL"); url != "" {
5470 n, err := strconv.Atoi(os.Getenv("GO_TEST_BENCH_CLIENT_N"))
5471 if err != nil {
5472 panic(err)
5473 }
5474 for i := 0; i < n; i++ {
5475 res, err := Get(url)
5476 if err != nil {
5477 log.Panicf("Get: %v", err)
5478 }
5479 all, err := io.ReadAll(res.Body)
5480 res.Body.Close()
5481 if err != nil {
5482 log.Panicf("ReadAll: %v", err)
5483 }
5484 body := string(all)
5485 if body != "Hello world.\n" {
5486 log.Panicf("Got body: %q", body)
5487 }
5488 }
5489 os.Exit(0)
5490 return
5491 }
5492
5493 var res = []byte("Hello world.\n")
5494 b.StopTimer()
5495 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
5496 rw.Header().Set("Content-Type", "text/html; charset=utf-8")
5497 rw.Write(res)
5498 }))
5499 defer ts.Close()
5500 b.StartTimer()
5501
5502 cmd := testenv.Command(b, os.Args[0], "-test.run=^$", "-test.bench=^BenchmarkServer$")
5503 cmd.Env = append([]string{
5504 fmt.Sprintf("GO_TEST_BENCH_CLIENT_N=%d", b.N),
5505 fmt.Sprintf("GO_TEST_BENCH_SERVER_URL=%s", ts.URL),
5506 }, os.Environ()...)
5507 out, err := cmd.CombinedOutput()
5508 if err != nil {
5509 b.Errorf("Test failure: %v, with output: %s", err, out)
5510 }
5511 }
5512
5513
5514 func getNoBody(urlStr string) (*Response, error) {
5515 res, err := Get(urlStr)
5516 if err != nil {
5517 return nil, err
5518 }
5519 res.Body.Close()
5520 return res, nil
5521 }
5522
5523
5524
5525 func BenchmarkClient(b *testing.B) {
5526 var data = []byte("Hello world.\n")
5527
5528 url := startClientBenchmarkServer(b, HandlerFunc(func(w ResponseWriter, _ *Request) {
5529 w.Header().Set("Content-Type", "text/html; charset=utf-8")
5530 w.Write(data)
5531 }))
5532
5533
5534 b.StartTimer()
5535 for i := 0; i < b.N; i++ {
5536 res, err := Get(url)
5537 if err != nil {
5538 b.Fatalf("Get: %v", err)
5539 }
5540 body, err := io.ReadAll(res.Body)
5541 res.Body.Close()
5542 if err != nil {
5543 b.Fatalf("ReadAll: %v", err)
5544 }
5545 if !bytes.Equal(body, data) {
5546 b.Fatalf("Got body: %q", body)
5547 }
5548 }
5549 b.StopTimer()
5550 }
5551
5552 func startClientBenchmarkServer(b *testing.B, handler Handler) string {
5553 b.ReportAllocs()
5554 b.StopTimer()
5555
5556 if server := os.Getenv("GO_TEST_BENCH_SERVER"); server != "" {
5557
5558 port := os.Getenv("GO_TEST_BENCH_SERVER_PORT")
5559 if port == "" {
5560 port = "0"
5561 }
5562 ln, err := net.Listen("tcp", "localhost:"+port)
5563 if err != nil {
5564 log.Fatal(err)
5565 }
5566 fmt.Println(ln.Addr().String())
5567
5568 HandleFunc("/", func(w ResponseWriter, r *Request) {
5569 r.ParseForm()
5570 if r.Form.Get("stop") != "" {
5571 os.Exit(0)
5572 }
5573 handler.ServeHTTP(w, r)
5574 })
5575 var srv Server
5576 log.Fatal(srv.Serve(ln))
5577 }
5578
5579
5580 ctx, cancel := context.WithCancel(context.Background())
5581 cmd := testenv.CommandContext(b, ctx, os.Args[0], "-test.run=^$", "-test.bench=^"+b.Name()+"$")
5582 cmd.Env = append(cmd.Environ(), "GO_TEST_BENCH_SERVER=yes")
5583 cmd.Stderr = os.Stderr
5584 stdout, err := cmd.StdoutPipe()
5585 if err != nil {
5586 b.Fatal(err)
5587 }
5588 if err := cmd.Start(); err != nil {
5589 b.Fatalf("subprocess failed to start: %v", err)
5590 }
5591
5592 done := make(chan error, 1)
5593 go func() {
5594 done <- cmd.Wait()
5595 close(done)
5596 }()
5597
5598
5599
5600 bs := bufio.NewScanner(stdout)
5601 if !bs.Scan() {
5602 b.Fatalf("failed to read listening URL from child: %v", bs.Err())
5603 }
5604 url := "http://" + strings.TrimSpace(bs.Text()) + "/"
5605 if _, err := getNoBody(url); err != nil {
5606 b.Fatalf("initial probe of child process failed: %v", err)
5607 }
5608
5609
5610 b.Cleanup(func() {
5611 getNoBody(url + "?stop=yes")
5612 if err := <-done; err != nil {
5613 b.Fatalf("subprocess failed: %v", err)
5614 }
5615
5616 cancel()
5617 <-done
5618
5619 })
5620
5621 return url
5622 }
5623
5624 func BenchmarkClientGzip(b *testing.B) {
5625 const responseSize = 1024 * 1024
5626
5627 var buf bytes.Buffer
5628 gz := gzip.NewWriter(&buf)
5629 if _, err := io.CopyN(gz, crand.Reader, responseSize); err != nil {
5630 b.Fatal(err)
5631 }
5632 gz.Close()
5633
5634 data := buf.Bytes()
5635
5636 url := startClientBenchmarkServer(b, HandlerFunc(func(w ResponseWriter, _ *Request) {
5637 w.Header().Set("Content-Encoding", "gzip")
5638 w.Write(data)
5639 }))
5640
5641
5642 b.StartTimer()
5643 for i := 0; i < b.N; i++ {
5644 res, err := Get(url)
5645 if err != nil {
5646 b.Fatalf("Get: %v", err)
5647 }
5648 n, err := io.Copy(io.Discard, res.Body)
5649 res.Body.Close()
5650 if err != nil {
5651 b.Fatalf("ReadAll: %v", err)
5652 }
5653 if n != responseSize {
5654 b.Fatalf("ReadAll: expected %d bytes, got %d", responseSize, n)
5655 }
5656 }
5657 b.StopTimer()
5658 }
5659
5660 func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) {
5661 b.ReportAllocs()
5662 req := reqBytes(`GET / HTTP/1.0
5663 Host: golang.org
5664 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
5665 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
5666 Accept-Encoding: gzip,deflate,sdch
5667 Accept-Language: en-US,en;q=0.8
5668 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
5669 `)
5670 res := []byte("Hello world!\n")
5671
5672 conn := newTestConn()
5673 handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
5674 rw.Header().Set("Content-Type", "text/html; charset=utf-8")
5675 rw.Write(res)
5676 })
5677 ln := new(oneConnListener)
5678 for i := 0; i < b.N; i++ {
5679 conn.readBuf.Reset()
5680 conn.writeBuf.Reset()
5681 conn.readBuf.Write(req)
5682 ln.conn = conn
5683 Serve(ln, handler)
5684 <-conn.closec
5685 }
5686 }
5687
5688
5689 type repeatReader struct {
5690 content []byte
5691 count int
5692 off int
5693 }
5694
5695 func (r *repeatReader) Read(p []byte) (n int, err error) {
5696 if r.count <= 0 {
5697 return 0, io.EOF
5698 }
5699 n = copy(p, r.content[r.off:])
5700 r.off += n
5701 if r.off == len(r.content) {
5702 r.count--
5703 r.off = 0
5704 }
5705 return
5706 }
5707
5708 func BenchmarkServerFakeConnWithKeepAlive(b *testing.B) {
5709 b.ReportAllocs()
5710
5711 req := reqBytes(`GET / HTTP/1.1
5712 Host: golang.org
5713 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
5714 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
5715 Accept-Encoding: gzip,deflate,sdch
5716 Accept-Language: en-US,en;q=0.8
5717 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
5718 `)
5719 res := []byte("Hello world!\n")
5720
5721 conn := &rwTestConn{
5722 Reader: &repeatReader{content: req, count: b.N},
5723 Writer: io.Discard,
5724 closec: make(chan bool, 1),
5725 }
5726 handled := 0
5727 handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
5728 handled++
5729 rw.Header().Set("Content-Type", "text/html; charset=utf-8")
5730 rw.Write(res)
5731 })
5732 ln := &oneConnListener{conn: conn}
5733 go Serve(ln, handler)
5734 <-conn.closec
5735 if b.N != handled {
5736 b.Errorf("b.N=%d but handled %d", b.N, handled)
5737 }
5738 }
5739
5740
5741
5742 func BenchmarkServerFakeConnWithKeepAliveLite(b *testing.B) {
5743 b.ReportAllocs()
5744
5745 req := reqBytes(`GET / HTTP/1.1
5746 Host: golang.org
5747 `)
5748 res := []byte("Hello world!\n")
5749
5750 conn := &rwTestConn{
5751 Reader: &repeatReader{content: req, count: b.N},
5752 Writer: io.Discard,
5753 closec: make(chan bool, 1),
5754 }
5755 handled := 0
5756 handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
5757 handled++
5758 rw.Write(res)
5759 })
5760 ln := &oneConnListener{conn: conn}
5761 go Serve(ln, handler)
5762 <-conn.closec
5763 if b.N != handled {
5764 b.Errorf("b.N=%d but handled %d", b.N, handled)
5765 }
5766 }
5767
5768 const someResponse = "<html>some response</html>"
5769
5770
5771 var response = bytes.Repeat([]byte(someResponse), 2<<10/len(someResponse))
5772
5773
5774 func BenchmarkServerHandlerTypeLen(b *testing.B) {
5775 benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
5776 w.Header().Set("Content-Type", "text/html")
5777 w.Header().Set("Content-Length", strconv.Itoa(len(response)))
5778 w.Write(response)
5779 }))
5780 }
5781
5782
5783 func BenchmarkServerHandlerNoLen(b *testing.B) {
5784 benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
5785 w.Header().Set("Content-Type", "text/html")
5786 w.Write(response)
5787 }))
5788 }
5789
5790
5791 func BenchmarkServerHandlerNoType(b *testing.B) {
5792 benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
5793 w.Header().Set("Content-Length", strconv.Itoa(len(response)))
5794 w.Write(response)
5795 }))
5796 }
5797
5798
5799 func BenchmarkServerHandlerNoHeader(b *testing.B) {
5800 benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
5801 w.Write(response)
5802 }))
5803 }
5804
5805 func benchmarkHandler(b *testing.B, h Handler) {
5806 b.ReportAllocs()
5807 req := reqBytes(`GET / HTTP/1.1
5808 Host: golang.org
5809 `)
5810 conn := &rwTestConn{
5811 Reader: &repeatReader{content: req, count: b.N},
5812 Writer: io.Discard,
5813 closec: make(chan bool, 1),
5814 }
5815 handled := 0
5816 handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
5817 handled++
5818 h.ServeHTTP(rw, r)
5819 })
5820 ln := &oneConnListener{conn: conn}
5821 go Serve(ln, handler)
5822 <-conn.closec
5823 if b.N != handled {
5824 b.Errorf("b.N=%d but handled %d", b.N, handled)
5825 }
5826 }
5827
5828 func BenchmarkServerHijack(b *testing.B) {
5829 b.ReportAllocs()
5830 req := reqBytes(`GET / HTTP/1.1
5831 Host: golang.org
5832 `)
5833 h := HandlerFunc(func(w ResponseWriter, r *Request) {
5834 conn, _, err := w.(Hijacker).Hijack()
5835 if err != nil {
5836 panic(err)
5837 }
5838 conn.Close()
5839 })
5840 conn := &rwTestConn{
5841 Writer: io.Discard,
5842 closec: make(chan bool, 1),
5843 }
5844 ln := &oneConnListener{conn: conn}
5845 for i := 0; i < b.N; i++ {
5846 conn.Reader = bytes.NewReader(req)
5847 ln.conn = conn
5848 Serve(ln, h)
5849 <-conn.closec
5850 }
5851 }
5852
5853 func BenchmarkCloseNotifier(b *testing.B) {
5854 runNoSynctest(b, benchmarkCloseNotifier, []testMode{http1Mode})
5855 }
5856 func benchmarkCloseNotifier(b *testing.B, mode testMode) {
5857 b.ReportAllocs()
5858 b.StopTimer()
5859 sawClose := make(chan bool)
5860 ts := newClientServerTest(b, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
5861 <-rw.(CloseNotifier).CloseNotify()
5862 sawClose <- true
5863 }), optRealNet).ts
5864 b.StartTimer()
5865 for i := 0; i < b.N; i++ {
5866 conn, err := net.Dial("tcp", ts.Listener.Addr().String())
5867 if err != nil {
5868 b.Fatalf("error dialing: %v", err)
5869 }
5870 _, err = fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n")
5871 if err != nil {
5872 b.Fatal(err)
5873 }
5874 conn.Close()
5875 <-sawClose
5876 }
5877 b.StopTimer()
5878 }
5879
5880
5881 func TestConcurrentServerServe(t *testing.T) {
5882 t.Parallel()
5883 for i := 0; i < 100; i++ {
5884 ln1 := &oneConnListener{conn: nil}
5885 ln2 := &oneConnListener{conn: nil}
5886 srv := Server{}
5887 go func() { srv.Serve(ln1) }()
5888 go func() { srv.Serve(ln2) }()
5889 }
5890 }
5891
5892 func TestServerIdleTimeout(t *testing.T) {
5893 runSynctest(t, testServerIdleTimeout, []testMode{http1Mode})
5894 }
5895 func testServerIdleTimeout(t *testing.T, mode testMode) {
5896 readHeaderTimeout := 1 * time.Second
5897 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5898 io.Copy(io.Discard, r.Body)
5899 io.WriteString(w, r.RemoteAddr)
5900 }), func(ts *httptest.Server) {
5901 ts.Config.ReadHeaderTimeout = readHeaderTimeout
5902 ts.Config.IdleTimeout = 2 * readHeaderTimeout
5903 })
5904 defer cst.close()
5905 ts := cst.ts
5906 t.Logf("ReadHeaderTimeout = %v", ts.Config.ReadHeaderTimeout)
5907 t.Logf("IdleTimeout = %v", ts.Config.IdleTimeout)
5908 c := ts.Client()
5909
5910 get := func() (string, error) {
5911 res, err := c.Get(ts.URL)
5912 if err != nil {
5913 return "", err
5914 }
5915 defer res.Body.Close()
5916 slurp, err := io.ReadAll(res.Body)
5917 if err != nil {
5918
5919
5920
5921 t.Fatal(err)
5922 }
5923 return string(slurp), nil
5924 }
5925
5926 a1, err := get()
5927 if err != nil {
5928 t.Fatal(err)
5929 }
5930 a2, err := get()
5931 if err != nil {
5932 t.Fatal(err)
5933 }
5934 if a1 != a2 {
5935 t.Fatal("did requests on different connections")
5936 }
5937 synctest.Sleep(ts.Config.IdleTimeout)
5938 a3, err := get()
5939 if err != nil {
5940 t.Fatal(err)
5941 }
5942 if a2 == a3 {
5943 t.Fatal("request three unexpectedly on same connection")
5944 }
5945
5946
5947 _, conn := cst.dialNettest()
5948 conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo.com\r\n"))
5949 synctest.Sleep(ts.Config.ReadHeaderTimeout)
5950 if _, err := io.CopyN(io.Discard, conn, 1); err == nil {
5951 t.Fatal("copy byte succeeded; want err")
5952 }
5953 }
5954
5955 func get(t *testing.T, c *Client, url string) string {
5956 res, err := c.Get(url)
5957 if err != nil {
5958 t.Fatal(err)
5959 }
5960 defer res.Body.Close()
5961 slurp, err := io.ReadAll(res.Body)
5962 if err != nil {
5963 t.Fatal(err)
5964 }
5965 return string(slurp)
5966 }
5967
5968
5969
5970 func TestServerSetKeepAlivesEnabledClosesConns(t *testing.T) {
5971 runSynctest(t, testServerSetKeepAlivesEnabledClosesConns, []testMode{http1Mode})
5972 }
5973 func testServerSetKeepAlivesEnabledClosesConns(t *testing.T, mode testMode) {
5974 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5975 io.WriteString(w, r.RemoteAddr)
5976 })).ts
5977
5978 c := ts.Client()
5979 tr := c.Transport.(*Transport)
5980
5981 get := func() string { return get(t, c, ts.URL) }
5982
5983 a1, a2 := get(), get()
5984 if a1 == a2 {
5985 t.Logf("made two requests from a single conn %q (as expected)", a1)
5986 } else {
5987 t.Errorf("server reported requests from %q and %q; expected same connection", a1, a2)
5988 }
5989
5990
5991
5992
5993
5994 if conns := tr.IdleConnStrsForTesting(); len(conns) != 1 {
5995 t.Errorf("found %d idle conns (%q); want 1", len(conns), conns)
5996 }
5997
5998
5999 ts.Config.SetKeepAlivesEnabled(false)
6000
6001 waitCondition(t, 10*time.Millisecond, func(d time.Duration) bool {
6002 if conns := tr.IdleConnStrsForTesting(); len(conns) > 0 {
6003 if d > 0 {
6004 t.Logf("idle conns %v after SetKeepAlivesEnabled called = %q; waiting for empty", d, conns)
6005 }
6006 return false
6007 }
6008 return true
6009 })
6010
6011
6012
6013
6014 }
6015
6016 func TestServerShutdown(t *testing.T) { runNoSynctest(t, testServerShutdown, http3SkippedMode) }
6017 func testServerShutdown(t *testing.T, mode testMode) {
6018 var cst *clientServerTest
6019
6020 var once sync.Once
6021 statesRes := make(chan map[ConnState]int, 1)
6022 shutdownRes := make(chan error, 1)
6023 gotOnShutdown := make(chan struct{})
6024 handler := HandlerFunc(func(w ResponseWriter, r *Request) {
6025 first := false
6026 once.Do(func() {
6027 statesRes <- cst.ts.Config.ExportAllConnsByState()
6028 go func() {
6029 shutdownRes <- cst.ts.Config.Shutdown(context.Background())
6030 }()
6031 first = true
6032 })
6033
6034 if first {
6035
6036
6037
6038 <-gotOnShutdown
6039
6040
6041 for !t.Failed() {
6042 res, err := cst.c.Get(cst.ts.URL)
6043 if err != nil {
6044 break
6045 }
6046 out, _ := io.ReadAll(res.Body)
6047 res.Body.Close()
6048 if mode == http2Mode {
6049 t.Logf("%v: unexpected success (%q). Listener should be closed before OnShutdown is called.", cst.ts.URL, out)
6050 t.Logf("Retrying to work around https://go.dev/issue/59038.")
6051 continue
6052 }
6053 t.Errorf("%v: unexpected success (%q). Listener should be closed before OnShutdown is called.", cst.ts.URL, out)
6054 }
6055 }
6056
6057 io.WriteString(w, r.RemoteAddr)
6058 })
6059
6060 cst = newClientServerTest(t, mode, handler, optRealNet, func(srv *httptest.Server) {
6061 srv.Config.RegisterOnShutdown(func() { close(gotOnShutdown) })
6062 })
6063
6064 out := get(t, cst.c, cst.ts.URL)
6065 t.Logf("%v: %q", cst.ts.URL, out)
6066
6067 if err := <-shutdownRes; err != nil {
6068 t.Fatalf("Shutdown: %v", err)
6069 }
6070 <-gotOnShutdown
6071
6072 if states := <-statesRes; states[StateActive] != 1 {
6073 t.Errorf("connection in wrong state, %v", states)
6074 }
6075 }
6076
6077 func TestServerShutdownStateNew(t *testing.T) {
6078 synctest.Test(t, testServerShutdownStateNew)
6079 }
6080 func testServerShutdownStateNew(t *testing.T) {
6081 listener := nettest.NewListener()
6082 defer listener.Close()
6083
6084 srv := &Server{}
6085 go srv.Serve(listener)
6086
6087
6088 conn := listener.NewConn()
6089 defer conn.Close()
6090 var connClosedAt time.Time
6091 go func() {
6092 io.Copy(io.Discard, conn)
6093 connClosedAt = time.Now()
6094 }()
6095 synctest.Wait()
6096
6097 start := time.Now()
6098 srv.Shutdown(context.Background())
6099 synctest.Wait()
6100
6101 if connClosedAt.IsZero() {
6102 t.Errorf("connection not closed after shutdown")
6103 } else if !connClosedAt.Equal(time.Now()) {
6104 t.Errorf("connection closed %v before shutdown", time.Since(connClosedAt))
6105 }
6106
6107
6108
6109
6110 const expectTimeout = 5 * time.Second
6111
6112 d := time.Since(start)
6113 if d < expectTimeout {
6114 t.Errorf("shutdown after %v, want at least %v", d, expectTimeout)
6115 }
6116
6117
6118
6119
6120 if want := expectTimeout + (2 * time.Second); d > want {
6121 t.Errorf("shutdown after %v, want no more than %v", d, want)
6122 }
6123 if !conn.Peer().IsClosed() {
6124 t.Fatalf("connection was not closed by server after shutdown")
6125 }
6126 }
6127
6128
6129 func TestServerCloseDeadlock(t *testing.T) {
6130 var s Server
6131 s.Close()
6132 s.Close()
6133 }
6134
6135
6136
6137 func TestServerKeepAlivesEnabled(t *testing.T) {
6138 runSynctest(t, testServerKeepAlivesEnabled, http3SkippedMode)
6139 }
6140 func testServerKeepAlivesEnabled(t *testing.T, mode testMode) {
6141 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}))
6142 defer cst.close()
6143 srv := cst.ts.Config
6144 srv.SetKeepAlivesEnabled(false)
6145 for try := range 2 {
6146 synctest.Wait()
6147 if !srv.ExportAllConnsIdle() {
6148 t.Fatalf("test server still has active conns before request %v", try)
6149 }
6150 conns := 0
6151 var info httptrace.GotConnInfo
6152 ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
6153 GotConn: func(v httptrace.GotConnInfo) {
6154 conns++
6155 info = v
6156 },
6157 })
6158 req, err := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil)
6159 if err != nil {
6160 t.Fatal(err)
6161 }
6162 res, err := cst.c.Do(req)
6163 if err != nil {
6164 t.Fatal(err)
6165 }
6166 res.Body.Close()
6167 if conns != 1 {
6168 t.Fatalf("request %v: got %v conns, want 1", try, conns)
6169 }
6170 if info.Reused || info.WasIdle {
6171 t.Fatalf("request %v: Reused=%v (want false), WasIdle=%v (want false)", try, info.Reused, info.WasIdle)
6172 }
6173 }
6174 }
6175
6176
6177
6178
6179 func TestServerCancelsReadTimeoutWhenIdle(t *testing.T) {
6180 runSynctest(t, testServerCancelsReadTimeoutWhenIdle)
6181 }
6182 func testServerCancelsReadTimeoutWhenIdle(t *testing.T, mode testMode) {
6183 timeout := time.Second
6184 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6185 select {
6186 case <-time.After(2 * timeout):
6187 fmt.Fprint(w, "ok")
6188 case <-r.Context().Done():
6189 fmt.Fprint(w, r.Context().Err())
6190 }
6191 }), func(ts *httptest.Server) {
6192 ts.Config.ReadTimeout = timeout
6193 t.Logf("Server.Config.ReadTimeout = %v", timeout)
6194 })
6195 defer cst.close()
6196 ts := cst.ts
6197
6198 var retries atomic.Int32
6199 cst.c.Transport.(*Transport).Proxy = func(*Request) (*url.URL, error) {
6200 if retries.Add(1) != 1 {
6201 return nil, errors.New("too many retries")
6202 }
6203 return nil, nil
6204 }
6205
6206 c := ts.Client()
6207
6208 res, err := c.Get(ts.URL)
6209 if err != nil {
6210 t.Fatalf("Get: %v", err)
6211 }
6212 slurp, err := io.ReadAll(res.Body)
6213 res.Body.Close()
6214 if err != nil {
6215 t.Fatalf("Body ReadAll: %v", err)
6216 }
6217 if string(slurp) != "ok" {
6218 t.Fatalf("got: %q, want ok", slurp)
6219 }
6220 }
6221
6222
6223
6224
6225 func TestServerCancelsReadHeaderTimeoutWhenIdle(t *testing.T) {
6226 runSynctest(t, testServerCancelsReadHeaderTimeoutWhenIdle, []testMode{http1Mode})
6227 }
6228 func testServerCancelsReadHeaderTimeoutWhenIdle(t *testing.T, mode testMode) {
6229 timeout := time.Second
6230 cst := newClientServerTest(t, mode, serve(200), func(ts *httptest.Server) {
6231 ts.Config.ReadHeaderTimeout = timeout
6232 ts.Config.IdleTimeout = 0
6233 })
6234 defer cst.close()
6235
6236
6237
6238 conn, _ := cst.dialNettest()
6239 br := bufio.NewReader(conn)
6240 defer conn.Close()
6241
6242 if _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")); err != nil {
6243 t.Fatalf("writing first request failed: %v", err)
6244 }
6245
6246 if _, err := ReadResponse(br, nil); err != nil {
6247 t.Fatalf("first response (before timeout) failed: %v", err)
6248 }
6249
6250
6251
6252 synctest.Sleep(timeout * 3 / 2)
6253
6254 if _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")); err != nil {
6255 t.Fatalf("writing second request failed: %v", err)
6256 }
6257
6258 if _, err := ReadResponse(br, nil); err != nil {
6259 t.Fatalf("second response (after timeout) failed: %v", err)
6260 }
6261 }
6262
6263
6264
6265 func TestServerDuplicateBackgroundRead(t *testing.T) {
6266 runSynctest(t, testServerDuplicateBackgroundRead, []testMode{http1Mode})
6267 }
6268 func testServerDuplicateBackgroundRead(t *testing.T, mode testMode) {
6269 if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm" {
6270 testenv.SkipFlaky(t, 24826)
6271 }
6272
6273 goroutines := 5
6274 requests := 2000
6275 if testing.Short() {
6276 goroutines = 3
6277 requests = 100
6278 }
6279
6280 cst := newClientServerTest(t, mode, HandlerFunc(NotFound))
6281
6282 reqBytes := []byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")
6283
6284 var wg sync.WaitGroup
6285 for i := 0; i < goroutines; i++ {
6286 wg.Add(1)
6287 go func() {
6288 defer wg.Done()
6289 cn, _ := cst.dialNettest()
6290 defer cn.Close()
6291
6292 wg.Add(1)
6293 go func() {
6294 defer wg.Done()
6295 io.Copy(io.Discard, cn)
6296 }()
6297
6298 for j := 0; j < requests; j++ {
6299 if t.Failed() {
6300 return
6301 }
6302 _, err := cn.Write(reqBytes)
6303 if err != nil {
6304 t.Error(err)
6305 return
6306 }
6307 }
6308 }()
6309 }
6310 wg.Wait()
6311 }
6312
6313
6314
6315
6316
6317
6318 func TestServerHijackGetsBackgroundByte(t *testing.T) {
6319 runSynctest(t, testServerHijackGetsBackgroundByte, []testMode{http1Mode})
6320 }
6321 func testServerHijackGetsBackgroundByte(t *testing.T, mode testMode) {
6322 if runtime.GOOS == "plan9" {
6323 t.Skip("skipping test; see https://golang.org/issue/18657")
6324 }
6325 done := make(chan struct{})
6326 inHandler := make(chan bool, 1)
6327 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6328 defer close(done)
6329
6330
6331 inHandler <- true
6332
6333 conn, buf, err := w.(Hijacker).Hijack()
6334 if err != nil {
6335 t.Error(err)
6336 return
6337 }
6338 defer conn.Close()
6339
6340 peek, err := buf.Reader.Peek(3)
6341 if string(peek) != "foo" || err != nil {
6342 t.Errorf("Peek = %q, %v; want foo, nil", peek, err)
6343 }
6344
6345 select {
6346 case <-r.Context().Done():
6347 t.Error("context unexpectedly canceled")
6348 default:
6349 }
6350 }))
6351
6352 _, cn := cst.dialNettest()
6353 defer cn.Close()
6354 if _, err := cn.Write([]byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")); err != nil {
6355 t.Fatal(err)
6356 }
6357 <-inHandler
6358 if _, err := cn.Write([]byte("foo")); err != nil {
6359 t.Fatal(err)
6360 }
6361
6362 if err := cn.CloseWrite(); err != nil {
6363 t.Fatal(err)
6364 }
6365 <-done
6366 }
6367
6368
6369 func TestServerHijackGetsFullBody(t *testing.T) {
6370 runSynctest(t, testServerHijackGetsFullBody, []testMode{http1Mode})
6371 }
6372 func testServerHijackGetsFullBody(t *testing.T, mode testMode) {
6373 if runtime.GOOS == "plan9" {
6374 t.Skip("skipping test; see https://golang.org/issue/18657")
6375 }
6376 done := make(chan struct{})
6377 needle := strings.Repeat("x", 100*1024)
6378 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6379 defer close(done)
6380
6381 conn, buf, err := w.(Hijacker).Hijack()
6382 if err != nil {
6383 t.Error(err)
6384 return
6385 }
6386 defer conn.Close()
6387
6388 got := make([]byte, len(needle))
6389 n, err := io.ReadFull(buf.Reader, got)
6390 if n != len(needle) || string(got) != needle || err != nil {
6391 t.Errorf("Peek = %q, %v; want 'x'*4096, nil", got, err)
6392 }
6393 }))
6394
6395 _, cn := cst.dialNettest()
6396 defer cn.Close()
6397 buf := []byte("GET / HTTP/1.1\r\nHost: e.com\r\n\r\n")
6398 buf = append(buf, []byte(needle)...)
6399 if _, err := cn.Write(buf); err != nil {
6400 t.Fatal(err)
6401 }
6402
6403 if err := cn.CloseWrite(); err != nil {
6404 t.Fatal(err)
6405 }
6406 <-done
6407 }
6408
6409
6410
6411
6412 func TestServerHijackGetsBackgroundByte_big(t *testing.T) {
6413 runSynctest(t, testServerHijackGetsBackgroundByte_big, []testMode{http1Mode})
6414 }
6415 func testServerHijackGetsBackgroundByte_big(t *testing.T, mode testMode) {
6416 if runtime.GOOS == "plan9" {
6417 t.Skip("skipping test; see https://golang.org/issue/18657")
6418 }
6419 done := make(chan struct{})
6420 const size = 8 << 10
6421 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6422 defer close(done)
6423
6424 conn, buf, err := w.(Hijacker).Hijack()
6425 if err != nil {
6426 t.Error(err)
6427 return
6428 }
6429 defer conn.Close()
6430 slurp, err := io.ReadAll(buf.Reader)
6431 if err != nil {
6432 t.Errorf("Copy: %v", err)
6433 }
6434 allX := true
6435 for _, v := range slurp {
6436 if v != 'x' {
6437 allX = false
6438 }
6439 }
6440 if len(slurp) != size {
6441 t.Errorf("read %d; want %d", len(slurp), size)
6442 } else if !allX {
6443 t.Errorf("read %q; want %d 'x'", slurp, size)
6444 }
6445 }))
6446
6447 _, cn := cst.dialNettest()
6448 defer cn.Close()
6449 if _, err := fmt.Fprintf(cn, "GET / HTTP/1.1\r\nHost: e.com\r\n\r\n%s",
6450 strings.Repeat("x", size)); err != nil {
6451 t.Fatal(err)
6452 }
6453 if err := cn.CloseWrite(); err != nil {
6454 t.Fatal(err)
6455 }
6456
6457 <-done
6458 }
6459
6460
6461 func TestServerValidatesMethod(t *testing.T) {
6462 tests := []struct {
6463 method string
6464 want int
6465 }{
6466 {"GET", 200},
6467 {"GE(T", 400},
6468 }
6469 for _, tt := range tests {
6470 conn := newTestConn()
6471 io.WriteString(&conn.readBuf, tt.method+" / HTTP/1.1\r\nHost: foo.example\r\n\r\n")
6472
6473 ln := &oneConnListener{conn}
6474 go Serve(ln, serve(200))
6475 <-conn.closec
6476 res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
6477 if err != nil {
6478 t.Errorf("For %s, ReadResponse: %v", tt.method, res)
6479 continue
6480 }
6481 if res.StatusCode != tt.want {
6482 t.Errorf("For %s, Status = %d; want %d", tt.method, res.StatusCode, tt.want)
6483 }
6484 }
6485 }
6486
6487
6488 type eofListenerNotComparable []int
6489
6490 func (eofListenerNotComparable) Accept() (net.Conn, error) { return nil, io.EOF }
6491 func (eofListenerNotComparable) Addr() net.Addr { return nil }
6492 func (eofListenerNotComparable) Close() error { return nil }
6493
6494
6495 func TestServerListenNotComparableListener(t *testing.T) {
6496 var s Server
6497 s.Serve(make(eofListenerNotComparable, 1))
6498 }
6499
6500
6501 type countCloseListener struct {
6502 net.Listener
6503 closes int32
6504 }
6505
6506 func (p *countCloseListener) Close() error {
6507 var err error
6508 if n := atomic.AddInt32(&p.closes, 1); n == 1 && p.Listener != nil {
6509 err = p.Listener.Close()
6510 }
6511 return err
6512 }
6513
6514
6515 func TestServerCloseListenerOnce(t *testing.T) {
6516 t.Parallel()
6517
6518 ln := newLocalListener(t)
6519 defer ln.Close()
6520
6521 cl := &countCloseListener{Listener: ln}
6522 server := &Server{}
6523 sdone := make(chan bool, 1)
6524
6525 go func() {
6526 server.Serve(cl)
6527 sdone <- true
6528 }()
6529 time.Sleep(10 * time.Millisecond)
6530 server.Shutdown(context.Background())
6531 ln.Close()
6532 <-sdone
6533
6534 nclose := atomic.LoadInt32(&cl.closes)
6535 if nclose != 1 {
6536 t.Errorf("Close calls = %v; want 1", nclose)
6537 }
6538 }
6539
6540
6541 func TestServerShutdownThenServe(t *testing.T) {
6542 var srv Server
6543 cl := &countCloseListener{Listener: nil}
6544 srv.Shutdown(context.Background())
6545 got := srv.Serve(cl)
6546 if got != ErrServerClosed {
6547 t.Errorf("Serve err = %v; want ErrServerClosed", got)
6548 }
6549 nclose := atomic.LoadInt32(&cl.closes)
6550 if nclose != 1 {
6551 t.Errorf("Close calls = %v; want 1", nclose)
6552 }
6553 }
6554
6555
6556 func TestStripPortFromHost(t *testing.T) {
6557 mux := NewServeMux()
6558
6559 mux.HandleFunc("example.com/", func(w ResponseWriter, r *Request) {
6560 fmt.Fprintf(w, "OK")
6561 })
6562 mux.HandleFunc("example.com:9000/", func(w ResponseWriter, r *Request) {
6563 fmt.Fprintf(w, "uh-oh!")
6564 })
6565
6566 req := httptest.NewRequest("GET", "http://example.com:9000/", nil)
6567 rw := httptest.NewRecorder()
6568
6569 mux.ServeHTTP(rw, req)
6570
6571 response := rw.Body.String()
6572 if response != "OK" {
6573 t.Errorf("Response gotten was %q", response)
6574 }
6575 }
6576
6577 func TestServerContexts(t *testing.T) { runSynctest(t, testServerContexts, http3SkippedMode) }
6578 func testServerContexts(t *testing.T, mode testMode) {
6579 type baseKey struct{}
6580 type connKey struct{}
6581 ch := make(chan context.Context, 1)
6582 ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, r *Request) {
6583 ch <- r.Context()
6584 }), func(ts *httptest.Server) {
6585 ts.Config.BaseContext = func(ln net.Listener) context.Context {
6586 if strings.Contains(reflect.TypeOf(ln).String(), "onceClose") {
6587 t.Errorf("unexpected onceClose listener type %T", ln)
6588 }
6589 return context.WithValue(context.Background(), baseKey{}, "base")
6590 }
6591 ts.Config.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
6592 if got, want := ctx.Value(baseKey{}), "base"; got != want {
6593 t.Errorf("in ConnContext, base context key = %#v; want %q", got, want)
6594 }
6595 return context.WithValue(ctx, connKey{}, "conn")
6596 }
6597 }).ts
6598 res, err := ts.Client().Get(ts.URL)
6599 if err != nil {
6600 t.Fatal(err)
6601 }
6602 res.Body.Close()
6603 ctx := <-ch
6604 if got, want := ctx.Value(baseKey{}), "base"; got != want {
6605 t.Errorf("base context key = %#v; want %q", got, want)
6606 }
6607 if got, want := ctx.Value(connKey{}), "conn"; got != want {
6608 t.Errorf("conn context key = %#v; want %q", got, want)
6609 }
6610 }
6611
6612
6613 func TestConnContextNotModifyingAllContexts(t *testing.T) {
6614 runSynctest(t, testConnContextNotModifyingAllContexts)
6615 }
6616 func testConnContextNotModifyingAllContexts(t *testing.T, mode testMode) {
6617 type connKey struct{}
6618 ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, r *Request) {
6619 rw.Header().Set("Connection", "close")
6620 }), func(ts *httptest.Server) {
6621 ts.Config.ConnContext = func(ctx context.Context, c net.Conn) context.Context {
6622 if got := ctx.Value(connKey{}); got != nil {
6623 t.Errorf("in ConnContext, unexpected context key = %#v", got)
6624 }
6625 return context.WithValue(ctx, connKey{}, "conn")
6626 }
6627 }).ts
6628
6629 var res *Response
6630 var err error
6631
6632 res, err = ts.Client().Get(ts.URL)
6633 if err != nil {
6634 t.Fatal(err)
6635 }
6636 res.Body.Close()
6637
6638 res, err = ts.Client().Get(ts.URL)
6639 if err != nil {
6640 t.Fatal(err)
6641 }
6642 res.Body.Close()
6643 }
6644
6645
6646
6647 func TestUnsupportedTransferEncodingsReturn501(t *testing.T) {
6648 runSynctest(t, testUnsupportedTransferEncodingsReturn501, []testMode{http1Mode})
6649 }
6650 func testUnsupportedTransferEncodingsReturn501(t *testing.T, mode testMode) {
6651 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6652 w.Write([]byte("Hello, World!"))
6653 }))
6654
6655 unsupportedTEs := []string{
6656 "fugazi",
6657 "foo-bar",
6658 "unknown",
6659 `" chunked"`,
6660 }
6661
6662 for _, badTE := range unsupportedTEs {
6663 http1ReqBody := fmt.Sprintf(""+
6664 "POST / HTTP/1.1\r\nConnection: close\r\n"+
6665 "Host: localhost\r\nTransfer-Encoding: %s\r\n\r\n", badTE)
6666
6667 gotBody, err := fetchWireResponse(cst, []byte(http1ReqBody))
6668 if err != nil {
6669 t.Errorf("%q. unexpected error: %v", badTE, err)
6670 continue
6671 }
6672
6673 wantBody := fmt.Sprintf("" +
6674 "HTTP/1.1 501 Not Implemented\r\nContent-Type: text/plain; charset=utf-8\r\n" +
6675 "Connection: close\r\n\r\nUnsupported transfer encoding")
6676
6677 if string(gotBody) != wantBody {
6678 t.Errorf("%q. body\ngot\n%q\nwant\n%q", badTE, gotBody, wantBody)
6679 }
6680 }
6681 }
6682
6683
6684 func TestContentEncodingNoSniffing(t *testing.T) { runNoSynctest(t, testContentEncodingNoSniffing) }
6685 func testContentEncodingNoSniffing(t *testing.T, mode testMode) {
6686 type setting struct {
6687 name string
6688 body []byte
6689
6690
6691
6692
6693 contentEncoding any
6694 wantContentType string
6695 }
6696
6697 settings := []*setting{
6698 {
6699 name: "gzip content-encoding, gzipped",
6700 contentEncoding: "application/gzip",
6701 wantContentType: "",
6702 body: func() []byte {
6703 buf := new(bytes.Buffer)
6704 gzw := gzip.NewWriter(buf)
6705 gzw.Write([]byte("doctype html><p>Hello</p>"))
6706 gzw.Close()
6707 return buf.Bytes()
6708 }(),
6709 },
6710 {
6711 name: "zlib content-encoding, zlibbed",
6712 contentEncoding: "application/zlib",
6713 wantContentType: "",
6714 body: func() []byte {
6715 buf := new(bytes.Buffer)
6716 zw := zlib.NewWriter(buf)
6717 zw.Write([]byte("doctype html><p>Hello</p>"))
6718 zw.Close()
6719 return buf.Bytes()
6720 }(),
6721 },
6722 {
6723 name: "no content-encoding",
6724 wantContentType: "application/x-gzip",
6725 body: func() []byte {
6726 buf := new(bytes.Buffer)
6727 gzw := gzip.NewWriter(buf)
6728 gzw.Write([]byte("doctype html><p>Hello</p>"))
6729 gzw.Close()
6730 return buf.Bytes()
6731 }(),
6732 },
6733 {
6734 name: "phony content-encoding",
6735 contentEncoding: "foo/bar",
6736 body: []byte("doctype html><p>Hello</p>"),
6737 },
6738 {
6739 name: "empty but set content-encoding",
6740 contentEncoding: "",
6741 wantContentType: "audio/mpeg",
6742 body: []byte("ID3"),
6743 },
6744 }
6745
6746 for _, tt := range settings {
6747 synctest.Subtest(t, tt.name, func(t *testing.T) {
6748 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, r *Request) {
6749 if tt.contentEncoding != nil {
6750 rw.Header().Set("Content-Encoding", tt.contentEncoding.(string))
6751 }
6752 rw.Write(tt.body)
6753 }))
6754
6755 res, err := cst.c.Get(cst.ts.URL)
6756 if err != nil {
6757 t.Fatalf("Failed to fetch URL: %v", err)
6758 }
6759 defer res.Body.Close()
6760
6761 if g, w := res.Header.Get("Content-Encoding"), tt.contentEncoding; g != w {
6762 if w != nil {
6763 t.Errorf("Content-Encoding mismatch\n\tgot: %q\n\twant: %q", g, w)
6764 } else if g != "" {
6765 t.Errorf("Unexpected Content-Encoding %q", g)
6766 }
6767 }
6768
6769 if g, w := res.Header.Get("Content-Type"), tt.wantContentType; g != w {
6770 t.Errorf("Content-Type mismatch\n\tgot: %q\n\twant: %q", g, w)
6771 }
6772 })
6773 }
6774 }
6775
6776
6777
6778 func TestTimeoutHandlerSuperfluousLogs(t *testing.T) {
6779 runNoSynctest(t, testTimeoutHandlerSuperfluousLogs, []testMode{http1Mode})
6780 }
6781 func testTimeoutHandlerSuperfluousLogs(t *testing.T, mode testMode) {
6782 if testing.Short() {
6783 t.Skip("skipping in short mode")
6784 }
6785
6786 pc, curFile, _, _ := runtime.Caller(0)
6787 curFileBaseName := filepath.Base(curFile)
6788 testFuncName := runtime.FuncForPC(pc).Name()
6789
6790 timeoutMsg := "timed out here!"
6791
6792 tests := []struct {
6793 name string
6794 mustTimeout bool
6795 wantResp string
6796 }{
6797 {
6798 name: "return before timeout",
6799 wantResp: "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n",
6800 },
6801 {
6802 name: "return after timeout",
6803 mustTimeout: true,
6804 wantResp: fmt.Sprintf("HTTP/1.1 503 Service Unavailable\r\nContent-Length: %d\r\n\r\n%s",
6805 len(timeoutMsg), timeoutMsg),
6806 },
6807 }
6808
6809 for _, tt := range tests {
6810 synctest.Subtest(t, tt.name, func(t *testing.T) {
6811 exitHandler := make(chan bool, 1)
6812 defer close(exitHandler)
6813 lastLine := make(chan int, 1)
6814
6815 sh := HandlerFunc(func(w ResponseWriter, r *Request) {
6816 w.WriteHeader(404)
6817 w.WriteHeader(404)
6818 w.WriteHeader(404)
6819 w.WriteHeader(404)
6820 _, _, line, _ := runtime.Caller(0)
6821 lastLine <- line
6822 <-exitHandler
6823 })
6824
6825 if !tt.mustTimeout {
6826 exitHandler <- true
6827 }
6828
6829 logBuf := new(strings.Builder)
6830 srvLog := log.New(logBuf, "", 0)
6831
6832
6833 th := TimeoutHandler(sh, 20*time.Millisecond, timeoutMsg)
6834 cst := newClientServerTest(t, mode, th, optWithServerLog(srvLog))
6835 defer cst.close()
6836
6837 res, err := cst.c.Get(cst.ts.URL)
6838 if err != nil {
6839 t.Fatalf("Unexpected error: %v", err)
6840 }
6841
6842
6843
6844 res.Header.Del("Date")
6845 res.Header.Del("Content-Type")
6846
6847
6848 blob, _ := httputil.DumpResponse(res, true)
6849 if g, w := string(blob), tt.wantResp; g != w {
6850 t.Errorf("Response mismatch\nGot\n%q\n\nWant\n%q", g, w)
6851 }
6852
6853
6854
6855 logEntries := strings.Split(strings.TrimSpace(logBuf.String()), "\n")
6856 if g, w := len(logEntries), 3; g != w {
6857 blob, _ := json.MarshalIndent(logEntries, "", " ")
6858 t.Fatalf("Server logs count mismatch\ngot %d, want %d\n\nGot\n%s\n", g, w, blob)
6859 }
6860
6861 lastSpuriousLine := <-lastLine
6862 firstSpuriousLine := lastSpuriousLine - 3
6863
6864
6865 for i, logEntry := range logEntries {
6866 wantLine := firstSpuriousLine + i
6867 pat := fmt.Sprintf("^http: superfluous response.WriteHeader call from %s.func\\d+.\\d+ \\(%s:%d\\)$",
6868 testFuncName, curFileBaseName, wantLine)
6869 re := regexp.MustCompile(pat)
6870 if !re.MatchString(logEntry) {
6871 t.Errorf("Log entry mismatch\n\t%s\ndoes not match\n\t%s", logEntry, pat)
6872 }
6873 }
6874 })
6875 }
6876 }
6877
6878
6879
6880
6881 func fetchWireResponse(cst *clientServerTest, http1ReqBody []byte) ([]byte, error) {
6882 conn, _ := cst.dialNettest()
6883 defer conn.Close()
6884
6885 if _, err := conn.Write(http1ReqBody); err != nil {
6886 return nil, err
6887 }
6888 return io.ReadAll(conn)
6889 }
6890
6891 func BenchmarkResponseStatusLine(b *testing.B) {
6892 b.ReportAllocs()
6893 b.RunParallel(func(pb *testing.PB) {
6894 bw := bufio.NewWriter(io.Discard)
6895 var buf3 [3]byte
6896 for pb.Next() {
6897 Export_writeStatusLine(bw, true, 200, buf3[:])
6898 }
6899 })
6900 }
6901
6902 func TestDisableKeepAliveUpgrade(t *testing.T) {
6903 runSynctest(t, testDisableKeepAliveUpgrade, []testMode{http1Mode})
6904 }
6905 func testDisableKeepAliveUpgrade(t *testing.T, mode testMode) {
6906 s := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6907 w.Header().Set("Connection", "Upgrade")
6908 w.Header().Set("Upgrade", "someProto")
6909 w.WriteHeader(StatusSwitchingProtocols)
6910 c, buf, err := w.(Hijacker).Hijack()
6911 if err != nil {
6912 return
6913 }
6914 defer c.Close()
6915
6916
6917
6918 io.Copy(c, buf)
6919 }), func(ts *httptest.Server) {
6920 ts.Config.SetKeepAlivesEnabled(false)
6921 }).ts
6922
6923 cl := s.Client()
6924 cl.Transport.(*Transport).DisableKeepAlives = true
6925
6926 resp, err := cl.Get(s.URL)
6927 if err != nil {
6928 t.Fatalf("failed to perform request: %v", err)
6929 }
6930 defer resp.Body.Close()
6931
6932 if resp.StatusCode != StatusSwitchingProtocols {
6933 t.Fatalf("unexpected status code: %v", resp.StatusCode)
6934 }
6935
6936 rwc, ok := resp.Body.(io.ReadWriteCloser)
6937 if !ok {
6938 t.Fatalf("Response.Body is not an io.ReadWriteCloser: %T", resp.Body)
6939 }
6940
6941 _, err = rwc.Write([]byte("hello"))
6942 if err != nil {
6943 t.Fatalf("failed to write to body: %v", err)
6944 }
6945
6946 b := make([]byte, 5)
6947 _, err = io.ReadFull(rwc, b)
6948 if err != nil {
6949 t.Fatalf("failed to read from body: %v", err)
6950 }
6951
6952 if string(b) != "hello" {
6953 t.Fatalf("unexpected value read from body:\ngot: %q\nwant: %q", b, "hello")
6954 }
6955 }
6956
6957 type tlogWriter struct{ t *testing.T }
6958
6959 func (w tlogWriter) Write(p []byte) (int, error) {
6960 w.t.Log(string(p))
6961 return len(p), nil
6962 }
6963
6964 func TestWriteHeaderSwitchingProtocols(t *testing.T) {
6965 runSynctest(t, testWriteHeaderSwitchingProtocols, []testMode{http1Mode})
6966 }
6967 func testWriteHeaderSwitchingProtocols(t *testing.T, mode testMode) {
6968 const wantBody = "want"
6969 const wantUpgrade = "someProto"
6970 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6971 w.Header().Set("Connection", "Upgrade")
6972 w.Header().Set("Upgrade", wantUpgrade)
6973 w.WriteHeader(StatusSwitchingProtocols)
6974 NewResponseController(w).Flush()
6975
6976
6977 w.WriteHeader(200)
6978 if _, err := w.Write([]byte("x")); err == nil {
6979 t.Errorf("Write to body after 101 Switching Protocols unexpectedly succeeded")
6980 }
6981
6982 c, _, err := NewResponseController(w).Hijack()
6983 if err != nil {
6984 t.Errorf("Hijack: %v", err)
6985 return
6986 }
6987 defer c.Close()
6988 if _, err := c.Write([]byte(wantBody)); err != nil {
6989 t.Errorf("Write to hijacked body: %v", err)
6990 }
6991 }), func(ts *httptest.Server) {
6992
6993 ts.Config.ErrorLog = log.New(tlogWriter{t}, "log: ", 0)
6994 })
6995
6996 conn, _ := cst.dialNettest()
6997 _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"))
6998 if err != nil {
6999 t.Fatalf("conn.Write: %v", err)
7000 }
7001 defer conn.Close()
7002
7003 r := bufio.NewReader(conn)
7004 res, err := ReadResponse(r, &Request{Method: "GET"})
7005 if err != nil {
7006 t.Fatal("ReadResponse error:", err)
7007 }
7008 if res.StatusCode != StatusSwitchingProtocols {
7009 t.Errorf("Response StatusCode=%v, want 101", res.StatusCode)
7010 }
7011 if got := res.Header.Get("Upgrade"); got != wantUpgrade {
7012 t.Errorf("Response Upgrade header = %q, want %q", got, wantUpgrade)
7013 }
7014 body, err := io.ReadAll(r)
7015 if err != nil {
7016 t.Error(err)
7017 }
7018 if string(body) != wantBody {
7019 t.Errorf("Response body = %q, want %q", string(body), wantBody)
7020 }
7021 }
7022
7023 func TestMuxRedirectRelative(t *testing.T) {
7024 t.Parallel()
7025 req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET http://example.com HTTP/1.1\r\nHost: test\r\n\r\n")))
7026 if err != nil {
7027 t.Errorf("%s", err)
7028 }
7029 mux := NewServeMux()
7030 resp := httptest.NewRecorder()
7031 mux.ServeHTTP(resp, req)
7032 if got, want := resp.Header().Get("Location"), "/"; got != want {
7033 t.Errorf("Location header expected %q; got %q", want, got)
7034 }
7035 if got, want := resp.Code, StatusTemporaryRedirect; got != want {
7036 t.Errorf("Expected response code %d; got %d", want, got)
7037 }
7038 }
7039
7040
7041 func TestQuerySemicolon(t *testing.T) {
7042 tests := []struct {
7043 query string
7044 xNoSemicolons string
7045 xWithSemicolons string
7046 expectParseFormErr bool
7047 }{
7048 {"?a=1;x=bad&x=good", "good", "bad", true},
7049 {"?a=1;b=bad&x=good", "good", "good", true},
7050 {"?a=1%3Bx=bad&x=good%3B", "good;", "good;", false},
7051 {"?a=1;x=good;x=bad", "", "good", true},
7052 }
7053
7054 runNoSynctest(t, func(t *testing.T, mode testMode) {
7055 for _, tt := range tests {
7056 synctest.Subtest(t, tt.query+"/allow=false", func(t *testing.T) {
7057 allowSemicolons := false
7058 testQuerySemicolon(t, mode, tt.query, tt.xNoSemicolons, allowSemicolons, tt.expectParseFormErr)
7059 })
7060 synctest.Subtest(t, tt.query+"/allow=true", func(t *testing.T) {
7061 allowSemicolons, expectParseFormErr := true, false
7062 testQuerySemicolon(t, mode, tt.query, tt.xWithSemicolons, allowSemicolons, expectParseFormErr)
7063 })
7064 }
7065 })
7066 }
7067
7068 func testQuerySemicolon(t *testing.T, mode testMode, query string, wantX string, allowSemicolons, expectParseFormErr bool) {
7069 writeBackX := func(w ResponseWriter, r *Request) {
7070 x := r.URL.Query().Get("x")
7071 if expectParseFormErr {
7072 if err := r.ParseForm(); err == nil || !strings.Contains(err.Error(), "semicolon") {
7073 t.Errorf("expected error mentioning semicolons from ParseForm, got %v", err)
7074 }
7075 } else {
7076 if err := r.ParseForm(); err != nil {
7077 t.Errorf("expected no error from ParseForm, got %v", err)
7078 }
7079 }
7080 if got := r.FormValue("x"); x != got {
7081 t.Errorf("got %q from FormValue, want %q", got, x)
7082 }
7083 fmt.Fprintf(w, "%s", x)
7084 }
7085
7086 h := Handler(HandlerFunc(writeBackX))
7087 if allowSemicolons {
7088 h = AllowQuerySemicolons(h)
7089 }
7090
7091 logBuf := &strings.Builder{}
7092 ts := newClientServerTest(t, mode, h, func(ts *httptest.Server) {
7093 ts.Config.ErrorLog = log.New(logBuf, "", 0)
7094 }).ts
7095
7096 req, _ := NewRequest("GET", ts.URL+query, nil)
7097 res, err := ts.Client().Do(req)
7098 if err != nil {
7099 t.Fatal(err)
7100 }
7101 slurp, _ := io.ReadAll(res.Body)
7102 res.Body.Close()
7103 if got, want := res.StatusCode, 200; got != want {
7104 t.Errorf("Status = %d; want = %d", got, want)
7105 }
7106 if got, want := string(slurp), wantX; got != want {
7107 t.Errorf("Body = %q; want = %q", got, want)
7108 }
7109 }
7110
7111 func TestMaxBytesHandler(t *testing.T) {
7112 for _, maxSize := range []int64{100, 1_000, 1_000_000} {
7113 for _, requestSize := range []int64{100, 1_000, 1_000_000} {
7114 t.Run(fmt.Sprintf("max size %d request size %d", maxSize, requestSize),
7115 func(t *testing.T) {
7116 runSynctest(t, func(t *testing.T, mode testMode) {
7117 testMaxBytesHandler(t, mode, maxSize, requestSize)
7118 })
7119 })
7120 }
7121 }
7122 }
7123
7124 func testMaxBytesHandler(t *testing.T, mode testMode, maxSize, requestSize int64) {
7125 var (
7126 mu sync.Mutex
7127 handlerN int64
7128 handlerErr error
7129 )
7130 echo := HandlerFunc(func(w ResponseWriter, r *Request) {
7131 mu.Lock()
7132 defer mu.Unlock()
7133 var buf bytes.Buffer
7134 handlerN, handlerErr = io.Copy(&buf, r.Body)
7135 io.Copy(w, &buf)
7136 })
7137
7138 cst := newClientServerTest(t, mode, MaxBytesHandler(echo, maxSize))
7139 ts := cst.ts
7140 c := ts.Client()
7141
7142 body := strings.Repeat("a", int(requestSize))
7143 var wg sync.WaitGroup
7144 defer wg.Wait()
7145 getBody := func() (io.ReadCloser, error) {
7146 wg.Add(1)
7147 body := &wgReadCloser{
7148 Reader: strings.NewReader(body),
7149 wg: &wg,
7150 }
7151 return body, nil
7152 }
7153 reqBody, _ := getBody()
7154 req, err := NewRequest("POST", ts.URL, reqBody)
7155 if err != nil {
7156 reqBody.Close()
7157 t.Fatal(err)
7158 }
7159 req.ContentLength = int64(len(body))
7160 req.GetBody = getBody
7161 req.Header.Set("Content-Type", "text/plain")
7162
7163 var buf strings.Builder
7164 res, err := c.Do(req)
7165 if err != nil {
7166 t.Fatalf("unexpected connection error: %v", err)
7167 } else {
7168 _, err = io.Copy(&buf, res.Body)
7169 res.Body.Close()
7170 if err != nil {
7171 t.Fatalf("unexpected read error: %v", err)
7172 }
7173 }
7174
7175 mu.Lock()
7176 defer mu.Unlock()
7177 if handlerN > maxSize {
7178 t.Errorf("expected max request body %d; got %d", maxSize, handlerN)
7179 }
7180 if requestSize > maxSize && handlerErr == nil {
7181 t.Error("expected error on handler side; got nil")
7182 }
7183 if requestSize <= maxSize {
7184 if handlerErr != nil {
7185 t.Errorf("%d expected nil error on handler side; got %v", requestSize, handlerErr)
7186 }
7187 if handlerN != requestSize {
7188 t.Errorf("expected request of size %d; got %d", requestSize, handlerN)
7189 }
7190 }
7191 if buf.Len() != int(handlerN) {
7192 t.Errorf("expected echo of size %d; got %d", handlerN, buf.Len())
7193 }
7194 }
7195
7196 func TestEarlyHints(t *testing.T) {
7197 ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
7198 h := w.Header()
7199 h.Add("Link", "</style.css>; rel=preload; as=style")
7200 h.Add("Link", "</script.js>; rel=preload; as=script")
7201 w.WriteHeader(StatusEarlyHints)
7202
7203 h.Add("Link", "</foo.js>; rel=preload; as=script")
7204 w.WriteHeader(StatusEarlyHints)
7205
7206 w.Write([]byte("stuff"))
7207 }))
7208
7209 got := ht.rawResponse("GET / HTTP/1.1\nHost: golang.org")
7210 expected := "HTTP/1.1 103 Early Hints\r\nLink: </style.css>; rel=preload; as=style\r\nLink: </script.js>; rel=preload; as=script\r\n\r\nHTTP/1.1 103 Early Hints\r\nLink: </style.css>; rel=preload; as=style\r\nLink: </script.js>; rel=preload; as=script\r\nLink: </foo.js>; rel=preload; as=script\r\n\r\nHTTP/1.1 200 OK\r\nLink: </style.css>; rel=preload; as=style\r\nLink: </script.js>; rel=preload; as=script\r\nLink: </foo.js>; rel=preload; as=script\r\nDate: "
7211 if !strings.Contains(got, expected) {
7212 t.Errorf("unexpected response; got %q; should start by %q", got, expected)
7213 }
7214 }
7215 func TestProcessing(t *testing.T) {
7216 ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
7217 w.WriteHeader(StatusProcessing)
7218 w.Write([]byte("stuff"))
7219 }))
7220
7221 got := ht.rawResponse("GET / HTTP/1.1\nHost: golang.org")
7222 expected := "HTTP/1.1 102 Processing\r\n\r\nHTTP/1.1 200 OK\r\nDate: "
7223 if !strings.Contains(got, expected) {
7224 t.Errorf("unexpected response; got %q; should start by %q", got, expected)
7225 }
7226 }
7227
7228 func TestParseFormCleanup(t *testing.T) { runSynctest(t, testParseFormCleanup) }
7229 func testParseFormCleanup(t *testing.T, mode testMode) {
7230 const maxMemory = 1024
7231 const key = "file"
7232
7233 if runtime.GOOS == "windows" {
7234
7235 t.Skip("https://go.dev/issue/25965")
7236 }
7237
7238 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7239 r.ParseMultipartForm(maxMemory)
7240 f, _, err := r.FormFile(key)
7241 if err != nil {
7242 t.Errorf("r.FormFile(%q) = %v", key, err)
7243 return
7244 }
7245 of, ok := f.(*os.File)
7246 if !ok {
7247 t.Errorf("r.FormFile(%q) returned type %T, want *os.File", key, f)
7248 return
7249 }
7250 w.Write([]byte(of.Name()))
7251 }))
7252
7253 fBuf := new(bytes.Buffer)
7254 mw := multipart.NewWriter(fBuf)
7255 mf, err := mw.CreateFormFile(key, "myfile.txt")
7256 if err != nil {
7257 t.Fatal(err)
7258 }
7259 if _, err := mf.Write(bytes.Repeat([]byte("A"), maxMemory*2)); err != nil {
7260 t.Fatal(err)
7261 }
7262 if err := mw.Close(); err != nil {
7263 t.Fatal(err)
7264 }
7265 req, err := NewRequest("POST", cst.ts.URL, fBuf)
7266 if err != nil {
7267 t.Fatal(err)
7268 }
7269 req.Header.Set("Content-Type", mw.FormDataContentType())
7270 res, err := cst.c.Do(req)
7271 if err != nil {
7272 t.Fatal(err)
7273 }
7274 defer res.Body.Close()
7275 fname, err := io.ReadAll(res.Body)
7276 if err != nil {
7277 t.Fatal(err)
7278 }
7279 cst.close()
7280 if _, err := os.Stat(string(fname)); !errors.Is(err, os.ErrNotExist) {
7281 t.Errorf("file %q exists after HTTP handler returned", string(fname))
7282 }
7283 }
7284
7285 func TestHeadBody(t *testing.T) {
7286 const identityMode = false
7287 const chunkedMode = true
7288 runNoSynctest(t, func(t *testing.T, mode testMode) {
7289 synctest.Subtest(t, "identity", func(t *testing.T) { testHeadBody(t, mode, identityMode, "HEAD") })
7290 synctest.Subtest(t, "chunked", func(t *testing.T) { testHeadBody(t, mode, chunkedMode, "HEAD") })
7291 })
7292 }
7293
7294 func TestGetBody(t *testing.T) {
7295 const identityMode = false
7296 const chunkedMode = true
7297 runNoSynctest(t, func(t *testing.T, mode testMode) {
7298 synctest.Subtest(t, "identity", func(t *testing.T) { testHeadBody(t, mode, identityMode, "GET") })
7299 synctest.Subtest(t, "chunked", func(t *testing.T) { testHeadBody(t, mode, chunkedMode, "GET") })
7300 })
7301 }
7302
7303 func testHeadBody(t *testing.T, mode testMode, chunked bool, method string) {
7304 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7305 b, err := io.ReadAll(r.Body)
7306 if err != nil {
7307 t.Errorf("server reading body: %v", err)
7308 return
7309 }
7310 w.Header().Set("X-Request-Body", string(b))
7311 w.Header().Set("Content-Length", "0")
7312 }))
7313 defer cst.close()
7314 for _, reqBody := range []string{
7315 "",
7316 "",
7317 "request_body",
7318 "",
7319 } {
7320 var bodyReader io.Reader
7321 if reqBody != "" {
7322 bodyReader = strings.NewReader(reqBody)
7323 if chunked {
7324 bodyReader = bufio.NewReader(bodyReader)
7325 }
7326 }
7327 req, err := NewRequest(method, cst.ts.URL, bodyReader)
7328 if err != nil {
7329 t.Fatal(err)
7330 }
7331 res, err := cst.c.Do(req)
7332 if err != nil {
7333 t.Fatal(err)
7334 }
7335 res.Body.Close()
7336 if got, want := res.StatusCode, 200; got != want {
7337 t.Errorf("%v request with %d-byte body: StatusCode = %v, want %v", method, len(reqBody), got, want)
7338 }
7339 if got, want := res.Header.Get("X-Request-Body"), reqBody; got != want {
7340 t.Errorf("%v request with %d-byte body: handler read body %q, want %q", method, len(reqBody), got, want)
7341 }
7342 }
7343 }
7344
7345
7346
7347 func TestDisableContentLength(t *testing.T) { runSynctest(t, testDisableContentLength) }
7348 func testDisableContentLength(t *testing.T, mode testMode) {
7349 noCL := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7350 w.Header()["Content-Length"] = nil
7351 fmt.Fprintf(w, "OK")
7352 }))
7353
7354 res, err := noCL.c.Get(noCL.ts.URL)
7355 if err != nil {
7356 t.Fatal(err)
7357 }
7358 if got, haveCL := res.Header["Content-Length"]; haveCL {
7359 t.Errorf("Unexpected Content-Length: %q", got)
7360 }
7361 if err := res.Body.Close(); err != nil {
7362 t.Fatal(err)
7363 }
7364
7365 withCL := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7366 fmt.Fprintf(w, "OK")
7367 }))
7368
7369 res, err = withCL.c.Get(withCL.ts.URL)
7370 if err != nil {
7371 t.Fatal(err)
7372 }
7373
7374 if got := res.Header.Get("Content-Length"); got != "2" && mode != http3Mode {
7375 t.Errorf("Content-Length: %q; want 2", got)
7376 }
7377 if err := res.Body.Close(); err != nil {
7378 t.Fatal(err)
7379 }
7380 }
7381
7382 func TestErrorContentLength(t *testing.T) { runSynctest(t, testErrorContentLength) }
7383 func testErrorContentLength(t *testing.T, mode testMode) {
7384 const errorBody = "an error occurred"
7385 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7386 w.Header().Set("Content-Length", "1000")
7387 Error(w, errorBody, 400)
7388 }))
7389 res, err := cst.c.Get(cst.ts.URL)
7390 if err != nil {
7391 t.Fatalf("Get(%q) = %v", cst.ts.URL, err)
7392 }
7393 defer res.Body.Close()
7394 body, err := io.ReadAll(res.Body)
7395 if err != nil {
7396 t.Fatalf("io.ReadAll(res.Body) = %v", err)
7397 }
7398 if string(body) != errorBody+"\n" {
7399 t.Fatalf("read body: %q, want %q", string(body), errorBody)
7400 }
7401 }
7402
7403 func TestError(t *testing.T) {
7404 w := httptest.NewRecorder()
7405 w.Header().Set("Content-Length", "1")
7406 w.Header().Set("X-Content-Type-Options", "scratch and sniff")
7407 w.Header().Set("Other", "foo")
7408 Error(w, "oops", 432)
7409
7410 h := w.Header()
7411 for _, hdr := range []string{"Content-Length"} {
7412 if v, ok := h[hdr]; ok {
7413 t.Errorf("%s: %q, want not present", hdr, v)
7414 }
7415 }
7416 if v := h.Get("Content-Type"); v != "text/plain; charset=utf-8" {
7417 t.Errorf("Content-Type: %q, want %q", v, "text/plain; charset=utf-8")
7418 }
7419 if v := h.Get("X-Content-Type-Options"); v != "nosniff" {
7420 t.Errorf("X-Content-Type-Options: %q, want %q", v, "nosniff")
7421 }
7422 }
7423
7424 func TestServerReadAfterWriteHeader100Continue(t *testing.T) {
7425 runSynctest(t, testServerReadAfterWriteHeader100Continue)
7426 }
7427 func testServerReadAfterWriteHeader100Continue(t *testing.T, mode testMode) {
7428 t.Skip("https://go.dev/issue/67555")
7429 body := []byte("body")
7430 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7431 w.WriteHeader(200)
7432 NewResponseController(w).Flush()
7433 io.ReadAll(r.Body)
7434 w.Write(body)
7435 }), func(tr *Transport) {
7436 tr.ExpectContinueTimeout = 24 * time.Hour
7437 })
7438
7439 req, _ := NewRequest("GET", cst.ts.URL, strings.NewReader("body"))
7440 req.Header.Set("Expect", "100-continue")
7441 res, err := cst.c.Do(req)
7442 if err != nil {
7443 t.Fatalf("Get(%q) = %v", cst.ts.URL, err)
7444 }
7445 defer res.Body.Close()
7446 got, err := io.ReadAll(res.Body)
7447 if err != nil {
7448 t.Fatalf("io.ReadAll(res.Body) = %v", err)
7449 }
7450 if !bytes.Equal(got, body) {
7451 t.Fatalf("response body = %q, want %q", got, body)
7452 }
7453 }
7454
7455 func TestServerReadAfterHandlerDone100Continue(t *testing.T) {
7456 runSynctest(t, testServerReadAfterHandlerDone100Continue)
7457 }
7458 func testServerReadAfterHandlerDone100Continue(t *testing.T, mode testMode) {
7459 t.Skip("https://go.dev/issue/67555")
7460 readyc := make(chan struct{})
7461 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7462 go func() {
7463 <-readyc
7464 io.ReadAll(r.Body)
7465 <-readyc
7466 }()
7467 }), func(tr *Transport) {
7468 tr.ExpectContinueTimeout = 24 * time.Hour
7469 })
7470
7471 req, _ := NewRequest("GET", cst.ts.URL, strings.NewReader("body"))
7472 req.Header.Set("Expect", "100-continue")
7473 res, err := cst.c.Do(req)
7474 if err != nil {
7475 t.Fatalf("Get(%q) = %v", cst.ts.URL, err)
7476 }
7477 res.Body.Close()
7478 readyc <- struct{}{}
7479 readyc <- struct{}{}
7480 }
7481
7482 func TestServerReadAfterHandlerAbort100Continue(t *testing.T) {
7483 runSynctest(t, testServerReadAfterHandlerAbort100Continue)
7484 }
7485 func testServerReadAfterHandlerAbort100Continue(t *testing.T, mode testMode) {
7486 t.Skip("https://go.dev/issue/67555")
7487 readyc := make(chan struct{})
7488 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7489 go func() {
7490 <-readyc
7491 io.ReadAll(r.Body)
7492 <-readyc
7493 }()
7494 panic(ErrAbortHandler)
7495 }), func(tr *Transport) {
7496 tr.ExpectContinueTimeout = 24 * time.Hour
7497 })
7498
7499 req, _ := NewRequest("GET", cst.ts.URL, strings.NewReader("body"))
7500 req.Header.Set("Expect", "100-continue")
7501 res, err := cst.c.Do(req)
7502 if err == nil {
7503 res.Body.Close()
7504 }
7505 readyc <- struct{}{}
7506 readyc <- struct{}{}
7507 }
7508
7509
7510 func TestServerExpect100ContinueUnreadBody(t *testing.T) {
7511 runSynctest(t, testServerExpect100ContinueUnreadBody)
7512 }
7513 func testServerExpect100ContinueUnreadBody(t *testing.T, mode testMode) {
7514 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7515 w.WriteHeader(StatusOK)
7516
7517
7518 io.ReadAll(r.Body)
7519 }))
7520
7521 req, _ := NewRequest("POST", cst.ts.URL, strings.NewReader("some body"))
7522 req.Header.Set("Expect", "100-continue")
7523
7524
7525 cst.c.Timeout = 2 * time.Second
7526 cst.tr.ExpectContinueTimeout = 10 * time.Second
7527
7528 resp, err := cst.c.Do(req)
7529 if err != nil {
7530 t.Fatalf("Request failed: %v (likely due to hang)", err)
7531 }
7532 defer resp.Body.Close()
7533
7534 if resp.StatusCode != StatusOK {
7535 t.Errorf("expected 200 OK, got %v", resp.Status)
7536 }
7537 }
7538
7539 func TestServer1xxExpect100ContinueRace(t *testing.T) {
7540 runSynctest(t, func(t *testing.T, mode testMode) {
7541 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7542 var wg sync.WaitGroup
7543 defer wg.Wait()
7544
7545
7546 wg.Go(func() { w.WriteHeader(StatusProcessing) })
7547 wg.Go(func() { w.WriteHeader(StatusEarlyHints) })
7548 io.ReadAll(r.Body)
7549 }))
7550 req, _ := NewRequest("POST", cst.ts.URL, strings.NewReader("hello"))
7551 req.Header.Set("Expect", "100-continue")
7552 res, err := cst.c.Do(req)
7553 if err != nil {
7554 t.Fatal(err)
7555 }
7556 defer res.Body.Close()
7557 if res.StatusCode != StatusOK {
7558 t.Errorf("want 200 OK, got %v", res.Status)
7559 }
7560 })
7561 }
7562
7563 func TestInvalidChunkedBodies(t *testing.T) {
7564 for _, test := range []struct {
7565 name string
7566 b string
7567 }{{
7568 name: "bare LF in chunk size",
7569 b: "1\na\r\n0\r\n\r\n",
7570 }, {
7571 name: "bare LF at body end",
7572 b: "1\r\na\r\n0\r\n\n",
7573 }} {
7574 t.Run(test.name, func(t *testing.T) {
7575 reqc := make(chan error)
7576 cst := newClientServerTest(t, http1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7577 got, err := io.ReadAll(r.Body)
7578 if err == nil {
7579 t.Logf("read body: %q", got)
7580 }
7581 reqc <- err
7582 }))
7583
7584 _, conn := cst.dialNettest()
7585 if _, err := conn.Write([]byte(
7586 "POST / HTTP/1.1\r\n" +
7587 "Host: localhost\r\n" +
7588 "Transfer-Encoding: chunked\r\n" +
7589 "Connection: close\r\n" +
7590 "\r\n" +
7591 test.b)); err != nil {
7592 t.Fatal(err)
7593 }
7594 conn.CloseWrite()
7595
7596 if err := <-reqc; err == nil {
7597 t.Errorf("server handler: io.ReadAll(r.Body) succeeded, want error")
7598 }
7599 })
7600 }
7601 }
7602
7603
7604 func TestServerTLSNextProtos(t *testing.T) {
7605 runSynctest(t, testServerTLSNextProtos, []testMode{https1Mode, http2Mode})
7606 }
7607 func testServerTLSNextProtos(t *testing.T, mode testMode) {
7608 CondSkipHTTP2(t)
7609
7610 cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
7611 if err != nil {
7612 t.Fatal(err)
7613 }
7614 leafCert, err := x509.ParseCertificate(cert.Certificate[0])
7615 if err != nil {
7616 t.Fatal(err)
7617 }
7618 certpool := x509.NewCertPool()
7619 certpool.AddCert(leafCert)
7620
7621 protos := new(Protocols)
7622 switch mode {
7623 case https1Mode:
7624 protos.SetHTTP1(true)
7625 case http2Mode:
7626 protos.SetHTTP2(true)
7627 }
7628
7629 wantNextProtos := []string{"http/1.1", "h2", "other"}
7630 nextProtos := slices.Clone(wantNextProtos)
7631
7632
7633 srv := &Server{
7634 TLSConfig: &tls.Config{
7635 Certificates: []tls.Certificate{cert},
7636 NextProtos: nextProtos,
7637 },
7638 Handler: HandlerFunc(func(w ResponseWriter, req *Request) {}),
7639 Protocols: protos,
7640 }
7641 tr := &Transport{
7642 TLSClientConfig: &tls.Config{
7643 RootCAs: certpool,
7644 NextProtos: nextProtos,
7645 },
7646 Protocols: protos,
7647 }
7648
7649 listener := newLocalListener(t)
7650 srvc := make(chan error, 1)
7651 go func() {
7652 srvc <- srv.ServeTLS(listener, "", "")
7653 }()
7654 t.Cleanup(func() {
7655 srv.Close()
7656 <-srvc
7657 })
7658
7659 client := &Client{Transport: tr}
7660 resp, err := client.Get("https://" + listener.Addr().String())
7661 if err != nil {
7662 t.Fatal(err)
7663 }
7664 resp.Body.Close()
7665
7666 if !slices.Equal(nextProtos, wantNextProtos) {
7667 t.Fatalf("after running test: original NextProtos slice = %v, want %v", nextProtos, wantNextProtos)
7668 }
7669 }
7670
7671
7672
7673 func TestServerHTTP2Disabled(t *testing.T) {
7674 synctest.Test(t, func(t *testing.T) {
7675 li := nettest.NewListener()
7676 srv := &Server{}
7677 srv.Protocols = new(Protocols)
7678 srv.Protocols.SetHTTP1(true)
7679 go srv.ServeTLS(li, "", "")
7680 synctest.Wait()
7681 srv.Shutdown(t.Context())
7682 })
7683 }
7684
7685 func TestServerConnectionReuse(t *testing.T) {
7686 for _, test := range []struct {
7687 name string
7688 message []string
7689 handler HandlerFunc
7690 continueBodySize int
7691 want100Continue bool
7692 wantResponse int
7693 wantReused bool
7694 skip string
7695 }{{
7696 name: "small body",
7697 message: []string{
7698 "POST / HTTP/1.1",
7699 "Host: example.tld",
7700 "Content-Length: 1",
7701 "",
7702 "x",
7703 },
7704 wantResponse: 200,
7705 wantReused: true,
7706 }, {
7707 name: "large body",
7708 message: []string{
7709 "POST / HTTP/1.1",
7710 "Host: example.tld",
7711 "Content-Length: 300000",
7712 "",
7713
7714 },
7715 wantResponse: 200,
7716 wantReused: false,
7717 }, {
7718 name: "small body full duplex",
7719 message: []string{
7720 "POST / HTTP/1.1",
7721 "Host: example.tld",
7722 "Content-Length: 1",
7723 "",
7724 "x",
7725 },
7726 handler: func(w ResponseWriter, req *Request) {
7727
7728
7729 NewResponseController(w).EnableFullDuplex()
7730 },
7731 wantResponse: 200,
7732 wantReused: true,
7733 }, {
7734 name: "large body full duplex",
7735 message: []string{
7736 "POST / HTTP/1.1",
7737 "Host: example.tld",
7738 "Content-Length: 300000",
7739 "",
7740
7741 },
7742 handler: func(w ResponseWriter, req *Request) {
7743
7744
7745 NewResponseController(w).EnableFullDuplex()
7746 },
7747 wantResponse: 200,
7748 wantReused: false,
7749 }, {
7750
7751
7752
7753
7754
7755
7756 skip: "https://go.dev/issue/75933",
7757
7758 name: "100-continue unconsumed small body",
7759 message: []string{
7760 "POST / HTTP/1.1",
7761 "Host: example.tld",
7762 "Expect: 100-continue",
7763 "Content-Length: 1",
7764 "",
7765
7766 },
7767 want100Continue: false,
7768 wantResponse: 200,
7769 wantReused: true,
7770 }, {
7771 name: "100-continue unconsumed large body",
7772 message: []string{
7773 "POST / HTTP/1.1",
7774 "Host: example.tld",
7775 "Expect: 100-continue",
7776 "Content-Length: 300000",
7777 "",
7778
7779 },
7780 want100Continue: false,
7781 wantResponse: 200,
7782 wantReused: false,
7783 }, {
7784 name: "100-continue consumed small body",
7785 message: []string{
7786 "POST / HTTP/1.1",
7787 "Host: example.tld",
7788 "Expect: 100-continue",
7789 "Content-Length: 1",
7790 "",
7791 },
7792 handler: func(w ResponseWriter, req *Request) {
7793 io.Copy(io.Discard, req.Body)
7794 },
7795 want100Continue: true,
7796 continueBodySize: 1,
7797 wantResponse: 200,
7798 wantReused: true,
7799 }, {
7800 name: "small wrapped body",
7801 message: []string{
7802 "POST / HTTP/1.1",
7803 "Host: example.tld",
7804 "Content-Length: 1",
7805 "",
7806 "x",
7807 },
7808 handler: func(w ResponseWriter, req *Request) {
7809
7810
7811 NewResponseController(w).EnableFullDuplex()
7812
7813
7814 req.Body = struct{ io.ReadCloser }{req.Body}
7815 },
7816 wantResponse: 200,
7817 wantReused: true,
7818 }, {
7819 name: "large wrapped body",
7820 message: []string{
7821 "POST / HTTP/1.1",
7822 "Host: example.tld",
7823 "Content-Length: 300000",
7824 "",
7825 },
7826 handler: func(w ResponseWriter, req *Request) {
7827
7828
7829 NewResponseController(w).EnableFullDuplex()
7830
7831
7832 req.Body = struct{ io.ReadCloser }{req.Body}
7833 },
7834 wantResponse: 200,
7835 wantReused: false,
7836 }} {
7837 t.Run(test.name, func(t *testing.T) {
7838 if test.skip != "" {
7839 t.Skip(test.skip)
7840 }
7841 synctest.Test(t, func(t *testing.T) {
7842 st := newHTTP1ServerTest(t, test.handler)
7843 conn := st.dial()
7844 conn.writeMessage(test.message...)
7845 resp := conn.readResponse()
7846 if got, want := resp.StatusCode == 100, test.want100Continue; got != want {
7847 t.Fatalf("100-Continue response: %v, want %v", got, want)
7848 }
7849 if resp.StatusCode == 100 {
7850 conn.conn.Write(bytes.Repeat([]byte("x"), test.continueBodySize))
7851 resp = conn.readResponse()
7852 }
7853 if got, want := resp.StatusCode, test.wantResponse; got != want {
7854 t.Fatalf("got response %v, want %v", got, want)
7855 }
7856 if test.wantReused {
7857 conn.wantIdle()
7858 } else {
7859 conn.wantClosed()
7860 }
7861 })
7862 })
7863 }
7864 }
7865
7866 func TestServerRequestBodyLength(t *testing.T) {
7867 for _, test := range []struct {
7868 name string
7869 message string
7870 closeWrite bool
7871 wantContentLength int64
7872 wantBodyLength int64
7873 wantErrorStatus int
7874 wantClose bool
7875 }{{
7876
7877 name: "TE and CL",
7878 message: joinCRLF(
7879 "POST / HTTP/1.1",
7880 "Host: example.tld",
7881 "Transfer-Encoding: chunked",
7882 "Content-Length: 5",
7883 "",
7884 "5",
7885 "hello",
7886 "0",
7887 "",
7888 "",
7889 ),
7890 wantContentLength: -1,
7891 wantBodyLength: 5,
7892 wantClose: true,
7893 }, {
7894
7895 name: "HTTP/1.0 TE and CL with keep-alive",
7896 message: joinCRLF(
7897 "POST / HTTP/1.0",
7898 "Host: example.tld",
7899 "Connection: keep-alive",
7900 "Transfer-Encoding: chunked",
7901 "Content-Length: 5",
7902 "",
7903 "hello",
7904 ),
7905 wantContentLength: 5,
7906 wantBodyLength: 5,
7907 wantClose: true,
7908 }, {
7909
7910 name: "HTTP/1.0 TE only with keep-alive",
7911 message: joinCRLF(
7912 "POST / HTTP/1.0",
7913 "Host: example.tld",
7914 "Connection: keep-alive",
7915 "Transfer-Encoding: chunked",
7916 "",
7917 "",
7918 ),
7919 wantContentLength: 0,
7920 wantBodyLength: 0,
7921 wantClose: true,
7922 }, {
7923
7924 name: "TE only",
7925 message: joinCRLF(
7926 "POST / HTTP/1.1",
7927 "Host: example.tld",
7928 "Transfer-Encoding: chunked",
7929 "",
7930 "5",
7931 "hello",
7932 "0",
7933 "",
7934 "",
7935 ),
7936 wantContentLength: -1,
7937 wantBodyLength: 5,
7938 }, {
7939
7940 name: "TE not chunked",
7941 message: joinCRLF(
7942 "POST / HTTP/1.1",
7943 "Host: example.tld",
7944 "Transfer-Encoding: chunked, smooth",
7945 "",
7946 "5",
7947 "hello",
7948 "0",
7949 "",
7950 ),
7951
7952
7953 wantErrorStatus: 501,
7954 wantClose: true,
7955 }, {
7956
7957 name: "invalid CL",
7958 message: joinCRLF(
7959 "POST / HTTP/1.1",
7960 "Host: example.tld",
7961 "Content-Length: yes",
7962 "",
7963 "",
7964 ),
7965 wantErrorStatus: 400,
7966 wantClose: true,
7967 }, {
7968
7969 name: "identical CL comma",
7970 message: joinCRLF(
7971 "POST / HTTP/1.1",
7972 "Host: example.tld",
7973 "Content-Length: 5, 5",
7974 "",
7975 "hello",
7976 ),
7977
7978 wantErrorStatus: 400,
7979 wantClose: true,
7980 }, {
7981
7982 name: "identical CL duplicate",
7983 message: joinCRLF(
7984 "POST / HTTP/1.1",
7985 "Host: example.tld",
7986 "Content-Length: 5",
7987 "Content-Length: 5",
7988 "",
7989 "hello",
7990 ),
7991 wantContentLength: 5,
7992 wantBodyLength: 5,
7993 }, {
7994
7995 name: "CL only",
7996 message: joinCRLF(
7997 "POST / HTTP/1.1",
7998 "Host: example.tld",
7999 "Content-Length: 5",
8000 "",
8001 "hello",
8002 ),
8003 wantContentLength: 5,
8004 wantBodyLength: 5,
8005 }, {
8006 name: "unsupported TE",
8007 message: joinCRLF(
8008 "POST / HTTP/1.1",
8009 "Host: example.tld",
8010 "Transfer-Encoding: fugazi",
8011 "",
8012 "",
8013 ),
8014 wantErrorStatus: 501,
8015 wantClose: true,
8016 }, {
8017 name: "duplicate TE values",
8018 message: joinCRLF(
8019 "POST / HTTP/1.1",
8020 "Host: example.tld",
8021 "Transfer-Encoding: chunked, chunked",
8022 "",
8023 "",
8024 ),
8025 wantErrorStatus: 501,
8026 wantClose: true,
8027 }, {
8028 name: "duplicate TE headers",
8029 message: joinCRLF(
8030 "POST / HTTP/1.1",
8031 "Host: example.tld",
8032 "Transfer-Encoding: chunked",
8033 "Transfer-Encoding: chunked",
8034 "",
8035 "",
8036 ),
8037 wantErrorStatus: 501,
8038 wantClose: true,
8039 }, {
8040 name: "empty TE",
8041 message: joinCRLF(
8042 "POST / HTTP/1.1",
8043 "Host: example.tld",
8044 "Transfer-Encoding: ",
8045 "",
8046 "",
8047 ),
8048 wantErrorStatus: 501,
8049 wantClose: true,
8050 }, {
8051 name: "TE: chunked, identity",
8052 message: joinCRLF(
8053 "POST / HTTP/1.1",
8054 "Host: example.tld",
8055 "Transfer-Encoding: chunked, identity",
8056 "",
8057 "",
8058 ),
8059 wantErrorStatus: 501,
8060 wantClose: true,
8061 }, {
8062 name: "TE: chunked, TE: identity",
8063 message: joinCRLF(
8064 "POST / HTTP/1.1",
8065 "Host: example.tld",
8066 "Transfer-Encoding: chunked",
8067 "Transfer-Encoding: identity",
8068 "",
8069 "",
8070 ),
8071 wantErrorStatus: 501,
8072 wantClose: true,
8073 }, {
8074 name: "TE: invalid character",
8075 message: joinCRLF(
8076 "POST / HTTP/1.1",
8077 "Host: example.tld",
8078 "Transfer-Encoding: \x0bchunked",
8079 "",
8080 "",
8081 ),
8082 wantErrorStatus: 400,
8083 wantClose: true,
8084 }, {
8085 name: "empty CL",
8086 message: joinCRLF(
8087 "POST / HTTP/1.1",
8088 "Host: example.tld",
8089 "Content-Length: ",
8090 "",
8091 "",
8092 ),
8093 wantErrorStatus: 400,
8094 wantClose: true,
8095 }, {
8096 name: "duplicate CL differs",
8097 message: joinCRLF(
8098 "POST / HTTP/1.1",
8099 "Host: example.tld",
8100 "Content-Length: 4",
8101 "Content-Length: 5",
8102 "",
8103 "hello",
8104 ),
8105 wantErrorStatus: 400,
8106 wantClose: true,
8107 }, {
8108 name: "CL with plus",
8109 message: joinCRLF(
8110 "POST / HTTP/1.1",
8111 "Host: example.tld",
8112 "Content-Length: +3",
8113 "",
8114 "",
8115 ),
8116 wantErrorStatus: 400,
8117 wantClose: true,
8118 }, {
8119 name: "negative CL",
8120 message: joinCRLF(
8121 "POST / HTTP/1.1",
8122 "Host: example.tld",
8123 "Content-Length: -3",
8124 "",
8125 "",
8126 ),
8127 wantErrorStatus: 400,
8128 wantClose: true,
8129 }, {
8130 name: "maxInt64 CL",
8131 message: joinCRLF(
8132 "POST / HTTP/1.1",
8133 "Host: example.tld",
8134 "Content-Length: 9223372036854775807",
8135 "",
8136 "hello",
8137 ),
8138 closeWrite: true,
8139 wantContentLength: 9223372036854775807,
8140 wantBodyLength: 5,
8141 }, {
8142 name: "overflowing CL",
8143 message: joinCRLF(
8144 "POST / HTTP/1.1",
8145 "Host: example.tld",
8146 "Content-Length: 9223372036854775808",
8147 "",
8148 "",
8149 ),
8150 wantErrorStatus: 400,
8151 wantClose: true,
8152 }} {
8153 t.Run(test.name, func(t *testing.T) {
8154 synctest.Test(t, func(t *testing.T) {
8155 handler := newTestHandler(t)
8156 st := newHTTP1ServerTest(t, handler.ServeHTTP)
8157 defer handler.Close()
8158 conn := st.dial()
8159 conn.conn.Write([]byte(test.message))
8160 if test.closeWrite {
8161 conn.conn.CloseWrite()
8162 }
8163
8164 if test.wantErrorStatus == 0 {
8165 call := handler.nextCall()
8166 if got, want := call.req.ContentLength, test.wantContentLength; got != want {
8167 t.Errorf("handler Request.ContentLength = %v, want %v", got, want)
8168 }
8169
8170 var bodySize int64
8171 reading := true
8172 go func() {
8173 bodySize, _ = io.Copy(io.Discard, call.req.Body)
8174 reading = false
8175 }()
8176 synctest.Wait()
8177 if reading {
8178 t.Fatalf("handler still reading request body (should have finished)")
8179 }
8180 if got, want := bodySize, test.wantBodyLength; got != want {
8181 t.Errorf("read %v body bytes, want %v", got, want)
8182 }
8183 call.exit()
8184 }
8185
8186 wantStatus := 200
8187 if test.wantErrorStatus != 0 {
8188 wantStatus = test.wantErrorStatus
8189 }
8190 resp := conn.readResponse()
8191 if got, want := resp.StatusCode, wantStatus; got != want {
8192 t.Errorf("server responded with status code %v, want %v", got, want)
8193 }
8194
8195 if got, want := conn.conn.Peer().IsClosed(), test.wantClose; got != want {
8196 t.Errorf("server closed connection: %v, want %v", got, want)
8197 }
8198 })
8199 })
8200 }
8201 }
8202
8203
8204
8205
8206 func TestServerRequestBodyCloseAfterPartialRead(t *testing.T) {
8207 synctest.Test(t, func(t *testing.T) {
8208 closeErr := make(chan error, 1)
8209 st := newHTTP1ServerTest(t, func(w ResponseWriter, req *Request) {
8210
8211 if _, err := io.ReadFull(req.Body, make([]byte, 2)); err != nil {
8212 closeErr <- fmt.Errorf("reading request body: %v", err)
8213 return
8214 }
8215 closeErr <- req.Body.Close()
8216 })
8217 conn := st.dial()
8218 conn.writeMessage(
8219 "POST / HTTP/1.1",
8220 "Host: example.tld",
8221 "Content-Length: 4",
8222 "",
8223 "test",
8224 )
8225 if got, want := conn.readResponse().StatusCode, 200; got != want {
8226 t.Fatalf("got response %v, want %v", got, want)
8227 }
8228 if err := <-closeErr; err != nil {
8229 t.Errorf("Request.Body.Close() = %v, want nil", err)
8230 }
8231 })
8232 }
8233
8234
8235
8236
8237
8238
8239 func TestServerAbortsWriteOnConnReadError(t *testing.T) {
8240 synctest.Test(t, func(t *testing.T) {
8241 handler := newTestHandler(t)
8242 st := newHTTP1ServerTest(t, handler.ServeHTTP)
8243 defer handler.Close()
8244 conn := st.dial()
8245 conn.writeMessage(
8246 "GET / HTTP/1.1",
8247 "Host: example.tld",
8248 "",
8249 )
8250 call := handler.nextCall()
8251
8252
8253 conn.conn.SetReadBufferSize(0)
8254 var writeErr error
8255 writing := true
8256 go func() {
8257 call.do(func(w ResponseWriter, req *Request) {
8258 _, writeErr = w.Write(make([]byte, 1<<20))
8259 })
8260 writing = false
8261 }()
8262 synctest.Wait()
8263 if !writing {
8264 t.Fatalf("handler finished writing response (should have blocked)")
8265 }
8266
8267 conn.conn.Peer().SetReadError(errors.New("connection reset"))
8268 synctest.Wait()
8269 if writing {
8270 t.Fatalf("handler still blocked writing response after connection read error")
8271 }
8272 if writeErr == nil {
8273 t.Errorf("handler wrote response successfully, want error")
8274 }
8275 })
8276 }
8277
8278
8279
8280
8281
8282 type bespokeTimeoutError struct{}
8283
8284 func (bespokeTimeoutError) Error() string { return "i/o timeout" }
8285 func (bespokeTimeoutError) Timeout() bool { return true }
8286 func (bespokeTimeoutError) Temporary() bool { return true }
8287
8288
8289
8290
8291 type bespokeTimeoutConn struct {
8292 net.Conn
8293 }
8294
8295 func (c bespokeTimeoutConn) Read(p []byte) (int, error) {
8296 n, err := c.Conn.Read(p)
8297 if errors.Is(err, os.ErrDeadlineExceeded) {
8298 err = bespokeTimeoutError{}
8299 }
8300 return n, err
8301 }
8302
8303 type bespokeTimeoutListener struct {
8304 net.Listener
8305 }
8306
8307 func (l bespokeTimeoutListener) Accept() (net.Conn, error) {
8308 c, err := l.Listener.Accept()
8309 if err != nil {
8310 return nil, err
8311 }
8312 return bespokeTimeoutConn{c}, nil
8313 }
8314
8315
8316
8317
8318
8319
8320
8321
8322 func testServerIdleKeepAlive(t *testing.T, wrap func(net.Listener) net.Listener) {
8323 t.Helper()
8324 handler := newTestHandler(t)
8325 srv := &Server{Handler: handler}
8326 li := nettest.NewListener()
8327 srvDone := make(chan struct{})
8328 go func() {
8329 defer close(srvDone)
8330 srv.Serve(wrap(li))
8331 }()
8332 defer func() {
8333 srv.Close()
8334 <-srvDone
8335 }()
8336 defer handler.Close()
8337
8338 conn := li.NewConn()
8339 defer conn.Close()
8340 tc := &http1TestConn{t: t, conn: conn, bufr: bufio.NewReader(conn)}
8341 for i := range 2 {
8342 if i == 1 {
8343 synctest.Sleep(250 * time.Millisecond)
8344 }
8345 tc.writeMessage(
8346 "GET / HTTP/1.1",
8347 "Host: foo",
8348 "",
8349 )
8350 call := handler.nextCall()
8351 if err := call.req.Context().Err(); err != nil {
8352 t.Errorf("request %d: handler's Request.Context().Err() = %v; want nil", i, err)
8353 }
8354 call.exit()
8355 tc.wantResponse("HTTP/1.1 200 OK", nil)
8356 }
8357 }
8358
8359
8360
8361
8362
8363 func TestServerIdleKeepAliveRequestContext(t *testing.T) {
8364 synctest.Test(t, func(t *testing.T) {
8365 testServerIdleKeepAlive(t, func(li net.Listener) net.Listener { return li })
8366 })
8367 }
8368
8369
8370
8371
8372
8373 func TestServerIdleKeepAliveNonstandardTimeoutError(t *testing.T) {
8374 synctest.Test(t, func(t *testing.T) {
8375 testServerIdleKeepAlive(t, func(li net.Listener) net.Listener {
8376 return bespokeTimeoutListener{li}
8377 })
8378 })
8379 }
8380
8381 func TestServerCONNECTSuccess(t *testing.T) {
8382 synctest.Test(t, func(t *testing.T) {
8383 handler := newTestHandler(t)
8384 st := newHTTP1ServerTest(t, handler.ServeHTTP)
8385 defer handler.Close()
8386 conn := st.dial()
8387 conn.writeMessage(
8388 "CONNECT backend.example.tld:80 HTTP/1.1",
8389 "Host: example.tld",
8390 "",
8391 )
8392 call := handler.nextCall()
8393 const code = 200
8394 call.w.WriteHeader(code)
8395 body := []byte("body")
8396 call.w.Write(body)
8397 NewResponseController(call.w).Flush()
8398 call.exit()
8399
8400 resp := conn.readResponse()
8401 if resp.StatusCode != code {
8402 t.Errorf("response status = %v, want %v", resp.StatusCode, code)
8403 }
8404 if resp.ContentLength != -1 {
8405 t.Errorf("Content-Length: %v; want absent", resp.ContentLength)
8406 }
8407 if len(resp.TransferEncoding) > 0 {
8408 t.Errorf("Transfer-Encoding: %q; want absent", resp.TransferEncoding)
8409 }
8410 for _, h := range []string{"Content-Length", "Transfer-Encoding"} {
8411 if got, ok := resp.Header[h]; ok {
8412 t.Errorf("response header %q = %q; want absent", h, got)
8413 }
8414 }
8415 conn.wantBytes(body)
8416 conn.wantClosed()
8417 })
8418 }
8419
8420 func TestServerCONNECTFailure(t *testing.T) {
8421 synctest.Test(t, func(t *testing.T) {
8422 handler := newTestHandler(t)
8423 st := newHTTP1ServerTest(t, handler.ServeHTTP)
8424 defer handler.Close()
8425 conn := st.dial()
8426 conn.writeMessage(
8427 "CONNECT backend.example.tld:80 HTTP/1.1",
8428 "Host: example.tld",
8429 "",
8430 )
8431 call := handler.nextCall()
8432 const code = 409
8433 body := []byte("body")
8434 call.w.Header().Set("Content-Length", strconv.Itoa(len(body)))
8435 call.w.WriteHeader(code)
8436 call.w.Write(body)
8437 call.exit()
8438
8439 resp := conn.readResponse()
8440 if resp.StatusCode != code {
8441 t.Errorf("response status = %v, want %v", resp.StatusCode, code)
8442 }
8443 if !resp.Close {
8444 t.Errorf("Connection: close not set; want it to be")
8445 }
8446 conn.wantBytes(body)
8447 conn.wantClosed()
8448 })
8449 }
8450
View as plain text