1
2
3
4
5 package http2_test
6
7 import (
8 "bufio"
9 "bytes"
10 "compress/gzip"
11 "context"
12 crand "crypto/rand"
13 "crypto/tls"
14 "encoding/hex"
15 "errors"
16 "flag"
17 "fmt"
18 "io"
19 "log"
20 "math/rand"
21 "net"
22 "net/http"
23 "net/http/httptest"
24 "net/http/httptrace"
25 "net/textproto"
26 "net/url"
27 "os"
28 "reflect"
29 "sort"
30 "strconv"
31 "strings"
32 "sync"
33 "sync/atomic"
34 "testing"
35 "testing/synctest"
36 "time"
37
38 . "net/http/internal/http2"
39 "net/http/internal/httpcommon"
40
41 "golang.org/x/net/http2/hpack"
42 )
43
44 var (
45 extNet = flag.Bool("extnet", false, "do external network tests")
46 transportHost = flag.String("transporthost", "go.dev", "hostname to use for TestTransport")
47 )
48
49 var tlsConfigInsecure = &tls.Config{InsecureSkipVerify: true}
50
51 var canceledCtx context.Context
52
53 func init() {
54 ctx, cancel := context.WithCancel(context.Background())
55 cancel()
56 canceledCtx = ctx
57 }
58
59
60 func newTransport(t testing.TB, opts ...any) *http.Transport {
61 tr1 := &http.Transport{
62 TLSClientConfig: tlsConfigInsecure,
63 Protocols: protocols("h2"),
64 HTTP2: &http.HTTP2Config{},
65 }
66 for _, o := range opts {
67 switch o := o.(type) {
68 case func(*http.Transport):
69 o(tr1)
70 case func(*http.HTTP2Config):
71 o(tr1.HTTP2)
72 default:
73 t.Fatalf("unknown newTransport option %T", o)
74 }
75 }
76 t.Cleanup(tr1.CloseIdleConnections)
77 return tr1
78 }
79
80 func TestTransportExternal(t *testing.T) {
81 if !*extNet {
82 t.Skip("skipping external network test")
83 }
84 req, _ := http.NewRequest("GET", "https://"+*transportHost+"/", nil)
85 rt := newTransport(t)
86 res, err := rt.RoundTrip(req)
87 if err != nil {
88 t.Fatalf("%v", err)
89 }
90 res.Write(os.Stdout)
91 }
92
93 func TestIdleConnTimeout(t *testing.T) {
94 for _, test := range []struct {
95 name string
96 idleConnTimeout time.Duration
97 wait time.Duration
98 baseTransport *http.Transport
99 wantNewConn bool
100 }{{
101 name: "NoExpiry",
102 idleConnTimeout: 2 * time.Second,
103 wait: 1 * time.Second,
104 baseTransport: nil,
105 wantNewConn: false,
106 }, {
107 name: "H2TransportTimeoutExpires",
108 idleConnTimeout: 1 * time.Second,
109 wait: 2 * time.Second,
110 baseTransport: nil,
111 wantNewConn: true,
112 }, {
113 name: "H1TransportTimeoutExpires",
114 idleConnTimeout: 0 * time.Second,
115 wait: 1 * time.Second,
116 baseTransport: newTransport(t, func(tr1 *http.Transport) {
117 tr1.IdleConnTimeout = 2 * time.Second
118 }),
119 wantNewConn: false,
120 }} {
121 synctestSubtest(t, test.name, func(t *testing.T) {
122 tt := newTestTransport(t, func(tr *http.Transport) {
123 tr.IdleConnTimeout = test.idleConnTimeout
124 })
125 var tc *testClientConn
126 for i := range 3 {
127 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
128 rt := tt.roundTrip(req)
129
130
131
132
133 wantConn := i == 0 || test.wantNewConn
134 if has := tt.hasConn(); has != wantConn {
135 t.Fatalf("request %v: hasConn=%v, want %v", i, has, wantConn)
136 }
137 if wantConn {
138 tc = tt.getConn()
139
140
141 tc.wantFrameType(FrameSettings)
142 tc.wantFrameType(FrameWindowUpdate)
143 tc.writeSettings()
144 }
145 if tt.hasConn() {
146 t.Fatalf("request %v: Transport has more than one conn", i)
147 }
148
149
150 hf := readFrame[*HeadersFrame](t, tc)
151 tc.writeHeaders(HeadersFrameParam{
152 StreamID: hf.StreamID,
153 EndHeaders: true,
154 EndStream: true,
155 BlockFragment: tc.makeHeaderBlockFragment(
156 ":status", "200",
157 ),
158 })
159 rt.wantStatus(200)
160
161
162 if wantConn {
163 tc.wantFrameType(FrameSettings)
164 }
165
166 time.Sleep(test.wait)
167 if got, want := tc.isClosed(), test.wantNewConn; got != want {
168 t.Fatalf("after waiting %v, conn closed=%v; want %v", test.wait, got, want)
169 }
170 }
171 })
172 }
173 }
174
175 func TestTransportH2c(t *testing.T) {
176 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
177 fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil)
178 }, func(s *http.Server) {
179 s.Protocols = protocols("h2c")
180 })
181 req, err := http.NewRequest("GET", ts.URL+"/foobar", nil)
182 if err != nil {
183 t.Fatal(err)
184 }
185 var gotConnCnt int32
186 trace := &httptrace.ClientTrace{
187 GotConn: func(connInfo httptrace.GotConnInfo) {
188 if !connInfo.Reused {
189 atomic.AddInt32(&gotConnCnt, 1)
190 }
191 },
192 }
193 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
194 tr := newTransport(t)
195 tr.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
196 return net.Dial(network, addr)
197 }
198 tr.Protocols = protocols("h2c")
199 res, err := tr.RoundTrip(req)
200 if err != nil {
201 t.Fatal(err)
202 }
203 if res.ProtoMajor != 2 {
204 t.Fatal("proto not h2c")
205 }
206 body, err := io.ReadAll(res.Body)
207 if err != nil {
208 t.Fatal(err)
209 }
210 if got, want := string(body), "Hello, /foobar, http: true"; got != want {
211 t.Fatalf("response got %v, want %v", got, want)
212 }
213 if got, want := gotConnCnt, int32(1); got != want {
214 t.Errorf("Too many got connections: %d", gotConnCnt)
215 }
216 }
217
218 func TestTransport(t *testing.T) {
219 const body = "sup"
220 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
221 io.WriteString(w, body)
222 })
223
224 tr := ts.Client().Transport.(*http.Transport)
225 defer tr.CloseIdleConnections()
226
227 u, err := url.Parse(ts.URL)
228 if err != nil {
229 t.Fatal(err)
230 }
231 for i, m := range []string{"GET", ""} {
232 req := &http.Request{
233 Method: m,
234 URL: u,
235 Header: http.Header{},
236 }
237 res, err := tr.RoundTrip(req)
238 if err != nil {
239 t.Fatalf("%d: %s", i, err)
240 }
241
242 t.Logf("%d: Got res: %+v", i, res)
243 if g, w := res.StatusCode, 200; g != w {
244 t.Errorf("%d: StatusCode = %v; want %v", i, g, w)
245 }
246 if g, w := res.Status, "200 OK"; g != w {
247 t.Errorf("%d: Status = %q; want %q", i, g, w)
248 }
249 wantHeader := http.Header{
250 "Content-Length": []string{"3"},
251 "Content-Type": []string{"text/plain; charset=utf-8"},
252 "Date": []string{"XXX"},
253 }
254
255 if d := res.Header["Date"]; len(d) == 1 {
256 d[0] = "XXX"
257 }
258 if !reflect.DeepEqual(res.Header, wantHeader) {
259 t.Errorf("%d: res Header = %v; want %v", i, res.Header, wantHeader)
260 }
261 if res.Request != req {
262 t.Errorf("%d: Response.Request = %p; want %p", i, res.Request, req)
263 }
264 if res.TLS == nil {
265 t.Errorf("%d: Response.TLS = nil; want non-nil", i)
266 }
267 slurp, err := io.ReadAll(res.Body)
268 if err != nil {
269 t.Errorf("%d: Body read: %v", i, err)
270 } else if string(slurp) != body {
271 t.Errorf("%d: Body = %q; want %q", i, slurp, body)
272 }
273 res.Body.Close()
274 }
275 }
276
277 func TestTransportFailureErrorForHTTP1Response(t *testing.T) {
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 t.Skip("test is racy")
300
301 const expectedHTTP1PayloadHint = "frame header looked like an HTTP/1.1 header"
302
303 ts := httptest.NewServer(http.NewServeMux())
304 t.Cleanup(ts.Close)
305
306 for _, tc := range []struct {
307 name string
308 maxFrameSize uint32
309 expectedErrorIs error
310 }{
311 {
312 name: "with default max frame size",
313 maxFrameSize: 0,
314 },
315 {
316 name: "with enough frame size to start reading",
317 maxFrameSize: InvalidHTTP1LookingFrameHeader().Length + 1,
318 },
319 } {
320 t.Run(tc.name, func(t *testing.T) {
321 tr := newTransport(t)
322 tr.HTTP2.MaxReadFrameSize = int(tc.maxFrameSize)
323 tr.Protocols = protocols("h2c")
324
325 req, err := http.NewRequest("GET", ts.URL, nil)
326 if err != nil {
327 t.Fatal(err)
328 }
329
330 _, err = tr.RoundTrip(req)
331 if err == nil || !strings.Contains(err.Error(), expectedHTTP1PayloadHint) {
332 t.Errorf("expected error to contain %q, got %v", expectedHTTP1PayloadHint, err)
333 }
334 })
335 }
336 }
337
338 func testTransportReusesConns(t *testing.T, wantSame bool, modReq func(*http.Request)) {
339 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
340 io.WriteString(w, r.RemoteAddr)
341 }, func(ts *httptest.Server) {
342 ts.Config.ConnState = func(c net.Conn, st http.ConnState) {
343 t.Logf("conn %v is now state %v", c.RemoteAddr(), st)
344 }
345 })
346 tr := newTransport(t)
347 get := func() string {
348 req, err := http.NewRequest("GET", ts.URL, nil)
349 if err != nil {
350 t.Fatal(err)
351 }
352 modReq(req)
353 res, err := tr.RoundTrip(req)
354 if err != nil {
355 t.Fatal(err)
356 }
357 defer res.Body.Close()
358 slurp, err := io.ReadAll(res.Body)
359 if err != nil {
360 t.Fatalf("Body read: %v", err)
361 }
362 addr := strings.TrimSpace(string(slurp))
363 if addr == "" {
364 t.Fatalf("didn't get an addr in response")
365 }
366 return addr
367 }
368 first := get()
369 second := get()
370 if got := first == second; got != wantSame {
371 t.Errorf("first and second responses on same connection: %v; want %v", got, wantSame)
372 }
373 }
374
375 func TestTransportReusesConns(t *testing.T) {
376 for _, test := range []struct {
377 name string
378 modReq func(*http.Request)
379 wantSame bool
380 }{{
381 name: "ReuseConn",
382 modReq: func(*http.Request) {},
383 wantSame: true,
384 }, {
385 name: "RequestClose",
386 modReq: func(r *http.Request) { r.Close = true },
387 wantSame: false,
388 }, {
389 name: "ConnClose",
390 modReq: func(r *http.Request) { r.Header.Set("Connection", "close") },
391 wantSame: false,
392 }} {
393 t.Run(test.name, func(t *testing.T) {
394 testTransportReusesConns(t, test.wantSame, test.modReq)
395 })
396 }
397 }
398
399 func TestTransportGetGotConnHooks_HTTP2Transport(t *testing.T) {
400 testTransportGetGotConnHooks(t, false)
401 }
402 func TestTransportGetGotConnHooks_Client(t *testing.T) { testTransportGetGotConnHooks(t, true) }
403
404 func testTransportGetGotConnHooks(t *testing.T, useClient bool) {
405 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
406 io.WriteString(w, r.RemoteAddr)
407 })
408
409 tr := newTransport(t)
410 client := ts.Client()
411
412 var (
413 getConns int32
414 gotConns int32
415 )
416 for i := range 2 {
417 trace := &httptrace.ClientTrace{
418 GetConn: func(hostport string) {
419 atomic.AddInt32(&getConns, 1)
420 },
421 GotConn: func(connInfo httptrace.GotConnInfo) {
422 got := atomic.AddInt32(&gotConns, 1)
423 wantReused, wantWasIdle := false, false
424 if got > 1 {
425 wantReused, wantWasIdle = true, true
426 }
427 if connInfo.Reused != wantReused || connInfo.WasIdle != wantWasIdle {
428 t.Errorf("GotConn %v: Reused=%v (want %v), WasIdle=%v (want %v)", i, connInfo.Reused, wantReused, connInfo.WasIdle, wantWasIdle)
429 }
430 },
431 }
432 req, err := http.NewRequest("GET", ts.URL, nil)
433 if err != nil {
434 t.Fatal(err)
435 }
436 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
437
438 var res *http.Response
439 if useClient {
440 res, err = client.Do(req)
441 } else {
442 res, err = tr.RoundTrip(req)
443 }
444 if err != nil {
445 t.Fatal(err)
446 }
447 res.Body.Close()
448 if get := atomic.LoadInt32(&getConns); get != int32(i+1) {
449 t.Errorf("after request %v, %v calls to GetConns: want %v", i, get, i+1)
450 }
451 if got := atomic.LoadInt32(&gotConns); got != int32(i+1) {
452 t.Errorf("after request %v, %v calls to GotConns: want %v", i, got, i+1)
453 }
454 }
455 }
456
457 func TestTransportAbortClosesPipes(t *testing.T) {
458 shutdown := make(chan struct{})
459 ts := newTestServer(t,
460 func(w http.ResponseWriter, r *http.Request) {
461 w.(http.Flusher).Flush()
462 <-shutdown
463 },
464 )
465 defer close(shutdown)
466
467 errCh := make(chan error)
468 go func() {
469 defer close(errCh)
470 tr := newTransport(t)
471 req, err := http.NewRequest("GET", ts.URL, nil)
472 if err != nil {
473 errCh <- err
474 return
475 }
476 res, err := tr.RoundTrip(req)
477 if err != nil {
478 errCh <- err
479 return
480 }
481 defer res.Body.Close()
482 ts.CloseClientConnections()
483 _, err = io.ReadAll(res.Body)
484 if err == nil {
485 errCh <- errors.New("expected error from res.Body.Read")
486 return
487 }
488 }()
489
490 select {
491 case err := <-errCh:
492 if err != nil {
493 t.Fatal(err)
494 }
495
496 case <-time.After(3 * time.Second):
497 t.Fatal("timeout")
498 }
499 }
500
501
502
503 func TestTransportPath(t *testing.T) {
504 gotc := make(chan *url.URL, 1)
505 ts := newTestServer(t,
506 func(w http.ResponseWriter, r *http.Request) {
507 gotc <- r.URL
508 },
509 )
510
511 tr := newTransport(t)
512 const (
513 path = "/testpath"
514 query = "q=1"
515 )
516 surl := ts.URL + path + "?" + query
517 req, err := http.NewRequest("POST", surl, nil)
518 if err != nil {
519 t.Fatal(err)
520 }
521 c := &http.Client{Transport: tr}
522 res, err := c.Do(req)
523 if err != nil {
524 t.Fatal(err)
525 }
526 defer res.Body.Close()
527 got := <-gotc
528 if got.Path != path {
529 t.Errorf("Read Path = %q; want %q", got.Path, path)
530 }
531 if got.RawQuery != query {
532 t.Errorf("Read RawQuery = %q; want %q", got.RawQuery, query)
533 }
534 }
535
536 func randString(n int) string {
537 rnd := rand.New(rand.NewSource(int64(n)))
538 b := make([]byte, n)
539 for i := range b {
540 b[i] = byte(rnd.Intn(256))
541 }
542 return string(b)
543 }
544
545 func TestTransportBody(t *testing.T) {
546 bodyTests := []struct {
547 body string
548 noContentLen bool
549 }{
550 {body: "some message"},
551 {body: "some message", noContentLen: true},
552 {body: strings.Repeat("a", 1<<20), noContentLen: true},
553 {body: strings.Repeat("a", 1<<20)},
554 {body: randString(16<<10 - 1)},
555 {body: randString(16 << 10)},
556 {body: randString(16<<10 + 1)},
557 {body: randString(512<<10 - 1)},
558 {body: randString(512 << 10)},
559 {body: randString(512<<10 + 1)},
560 {body: randString(1<<20 - 1)},
561 {body: randString(1 << 20)},
562 {body: randString(1<<20 + 2)},
563 }
564
565 type reqInfo struct {
566 req *http.Request
567 slurp []byte
568 err error
569 }
570 gotc := make(chan reqInfo, 1)
571 ts := newTestServer(t,
572 func(w http.ResponseWriter, r *http.Request) {
573 slurp, err := io.ReadAll(r.Body)
574 if err != nil {
575 gotc <- reqInfo{err: err}
576 } else {
577 gotc <- reqInfo{req: r, slurp: slurp}
578 }
579 },
580 )
581
582 for i, tt := range bodyTests {
583 tr := newTransport(t)
584
585 var body io.Reader = strings.NewReader(tt.body)
586 if tt.noContentLen {
587 body = struct{ io.Reader }{body}
588 }
589 req, err := http.NewRequest("POST", ts.URL, body)
590 if err != nil {
591 t.Fatalf("#%d: %v", i, err)
592 }
593 c := &http.Client{Transport: tr}
594 res, err := c.Do(req)
595 if err != nil {
596 t.Fatalf("#%d: %v", i, err)
597 }
598 defer res.Body.Close()
599 ri := <-gotc
600 if ri.err != nil {
601 t.Errorf("#%d: read error: %v", i, ri.err)
602 continue
603 }
604 if got := string(ri.slurp); got != tt.body {
605 t.Errorf("#%d: Read body mismatch.\n got: %q (len %d)\nwant: %q (len %d)", i, shortString(got), len(got), shortString(tt.body), len(tt.body))
606 }
607 wantLen := int64(len(tt.body))
608 if tt.noContentLen && tt.body != "" {
609 wantLen = -1
610 }
611 if ri.req.ContentLength != wantLen {
612 t.Errorf("#%d. handler got ContentLength = %v; want %v", i, ri.req.ContentLength, wantLen)
613 }
614 }
615 }
616
617 func shortString(v string) string {
618 const maxLen = 100
619 if len(v) <= maxLen {
620 return v
621 }
622 return fmt.Sprintf("%v[...%d bytes omitted...]%v", v[:maxLen/2], len(v)-maxLen, v[len(v)-maxLen/2:])
623 }
624
625 type capitalizeReader struct {
626 r io.Reader
627 }
628
629 func (cr capitalizeReader) Read(p []byte) (n int, err error) {
630 n, err = cr.r.Read(p)
631 for i, b := range p[:n] {
632 if b >= 'a' && b <= 'z' {
633 p[i] = b - ('a' - 'A')
634 }
635 }
636 return
637 }
638
639 type flushWriter struct {
640 w io.Writer
641 }
642
643 func (fw flushWriter) Write(p []byte) (n int, err error) {
644 n, err = fw.w.Write(p)
645 if f, ok := fw.w.(http.Flusher); ok {
646 f.Flush()
647 }
648 return
649 }
650
651 func newLocalListener(t *testing.T) net.Listener {
652 ln, err := net.Listen("tcp4", "127.0.0.1:0")
653 if err == nil {
654 return ln
655 }
656 ln, err = net.Listen("tcp6", "[::1]:0")
657 if err != nil {
658 t.Fatal(err)
659 }
660 return ln
661 }
662
663 func TestTransportReqBodyAfterResponse_200(t *testing.T) {
664 synctest.Test(t, func(t *testing.T) {
665 testTransportReqBodyAfterResponse(t, 200)
666 })
667 }
668 func TestTransportReqBodyAfterResponse_403(t *testing.T) {
669 synctest.Test(t, func(t *testing.T) {
670 testTransportReqBodyAfterResponse(t, 403)
671 })
672 }
673
674 func testTransportReqBodyAfterResponse(t *testing.T, status int) {
675 const bodySize = 1 << 10
676
677 tc := newTestClientConn(t)
678 tc.greet()
679
680 body := tc.newRequestBody()
681 body.writeBytes(bodySize / 2)
682 req, _ := http.NewRequest("PUT", "https://dummy.tld/", body)
683 rt := tc.roundTrip(req)
684
685 tc.wantHeaders(wantHeader{
686 streamID: rt.streamID(),
687 endStream: false,
688 header: http.Header{
689 ":authority": []string{"dummy.tld"},
690 ":method": []string{"PUT"},
691 ":path": []string{"/"},
692 },
693 })
694
695
696 tc.writeWindowUpdate(0, bodySize)
697 tc.writeWindowUpdate(rt.streamID(), bodySize)
698
699 tc.wantData(wantData{
700 streamID: rt.streamID(),
701 endStream: false,
702 size: bodySize / 2,
703 })
704
705 tc.writeHeaders(HeadersFrameParam{
706 StreamID: rt.streamID(),
707 EndHeaders: true,
708 EndStream: true,
709 BlockFragment: tc.makeHeaderBlockFragment(
710 ":status", strconv.Itoa(status),
711 ),
712 })
713
714 res := rt.response()
715 if res.StatusCode != status {
716 t.Fatalf("status code = %v; want %v", res.StatusCode, status)
717 }
718
719 body.writeBytes(bodySize / 2)
720 body.closeWithError(io.EOF)
721
722 if status == 200 {
723
724 tc.wantData(wantData{
725 streamID: rt.streamID(),
726 endStream: true,
727 size: bodySize / 2,
728 multiple: true,
729 })
730 } else {
731
732 tc.wantFrameType(FrameRSTStream)
733 }
734
735 rt.wantBody(nil)
736 }
737
738
739 func TestTransportFullDuplex(t *testing.T) {
740 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
741 w.WriteHeader(200)
742 w.(http.Flusher).Flush()
743 io.Copy(flushWriter{w}, capitalizeReader{r.Body})
744 fmt.Fprintf(w, "bye.\n")
745 })
746
747 tr := newTransport(t)
748 c := &http.Client{Transport: tr}
749
750 pr, pw := io.Pipe()
751 req, err := http.NewRequest("PUT", ts.URL, io.NopCloser(pr))
752 if err != nil {
753 t.Fatal(err)
754 }
755 req.ContentLength = -1
756 res, err := c.Do(req)
757 if err != nil {
758 t.Fatal(err)
759 }
760 defer res.Body.Close()
761 if res.StatusCode != 200 {
762 t.Fatalf("StatusCode = %v; want %v", res.StatusCode, 200)
763 }
764 bs := bufio.NewScanner(res.Body)
765 want := func(v string) {
766 if !bs.Scan() {
767 t.Fatalf("wanted to read %q but Scan() = false, err = %v", v, bs.Err())
768 }
769 }
770 write := func(v string) {
771 _, err := io.WriteString(pw, v)
772 if err != nil {
773 t.Fatalf("pipe write: %v", err)
774 }
775 }
776 write("foo\n")
777 want("FOO")
778 write("bar\n")
779 want("BAR")
780 pw.Close()
781 want("bye.")
782 if err := bs.Err(); err != nil {
783 t.Fatal(err)
784 }
785 }
786
787 func TestTransportConnectRequest(t *testing.T) {
788 gotc := make(chan *http.Request, 1)
789 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
790 gotc <- r
791 })
792
793 u, err := url.Parse(ts.URL)
794 if err != nil {
795 t.Fatal(err)
796 }
797
798 tr := newTransport(t)
799 c := &http.Client{Transport: tr}
800
801 tests := []struct {
802 req *http.Request
803 want string
804 }{
805 {
806 req: &http.Request{
807 Method: "CONNECT",
808 Header: http.Header{},
809 URL: u,
810 },
811 want: u.Host,
812 },
813 {
814 req: &http.Request{
815 Method: "CONNECT",
816 Header: http.Header{},
817 URL: u,
818 Host: "example.com:123",
819 },
820 want: "example.com:123",
821 },
822 }
823
824 for i, tt := range tests {
825 res, err := c.Do(tt.req)
826 if err != nil {
827 t.Errorf("%d. RoundTrip = %v", i, err)
828 continue
829 }
830 res.Body.Close()
831 req := <-gotc
832 if req.Method != "CONNECT" {
833 t.Errorf("method = %q; want CONNECT", req.Method)
834 }
835 if req.Host != tt.want {
836 t.Errorf("Host = %q; want %q", req.Host, tt.want)
837 }
838 if req.URL.Host != tt.want {
839 t.Errorf("URL.Host = %q; want %q", req.URL.Host, tt.want)
840 }
841 }
842 }
843
844 type headerType int
845
846 const (
847 noHeader headerType = iota
848 oneHeader
849 splitHeader
850 )
851
852 const (
853 f0 = noHeader
854 f1 = oneHeader
855 f2 = splitHeader
856 d0 = false
857 d1 = true
858 )
859
860
861
862
863
864
865 func TestTransportResPattern_c0h1d0t0(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f0) }
866 func TestTransportResPattern_c0h1d0t1(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f1) }
867 func TestTransportResPattern_c0h1d0t2(t *testing.T) { testTransportResPattern(t, f0, f1, d0, f2) }
868 func TestTransportResPattern_c0h1d1t0(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f0) }
869 func TestTransportResPattern_c0h1d1t1(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f1) }
870 func TestTransportResPattern_c0h1d1t2(t *testing.T) { testTransportResPattern(t, f0, f1, d1, f2) }
871 func TestTransportResPattern_c0h2d0t0(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f0) }
872 func TestTransportResPattern_c0h2d0t1(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f1) }
873 func TestTransportResPattern_c0h2d0t2(t *testing.T) { testTransportResPattern(t, f0, f2, d0, f2) }
874 func TestTransportResPattern_c0h2d1t0(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f0) }
875 func TestTransportResPattern_c0h2d1t1(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f1) }
876 func TestTransportResPattern_c0h2d1t2(t *testing.T) { testTransportResPattern(t, f0, f2, d1, f2) }
877 func TestTransportResPattern_c1h1d0t0(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f0) }
878 func TestTransportResPattern_c1h1d0t1(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f1) }
879 func TestTransportResPattern_c1h1d0t2(t *testing.T) { testTransportResPattern(t, f1, f1, d0, f2) }
880 func TestTransportResPattern_c1h1d1t0(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f0) }
881 func TestTransportResPattern_c1h1d1t1(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f1) }
882 func TestTransportResPattern_c1h1d1t2(t *testing.T) { testTransportResPattern(t, f1, f1, d1, f2) }
883 func TestTransportResPattern_c1h2d0t0(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f0) }
884 func TestTransportResPattern_c1h2d0t1(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f1) }
885 func TestTransportResPattern_c1h2d0t2(t *testing.T) { testTransportResPattern(t, f1, f2, d0, f2) }
886 func TestTransportResPattern_c1h2d1t0(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f0) }
887 func TestTransportResPattern_c1h2d1t1(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f1) }
888 func TestTransportResPattern_c1h2d1t2(t *testing.T) { testTransportResPattern(t, f1, f2, d1, f2) }
889 func TestTransportResPattern_c2h1d0t0(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f0) }
890 func TestTransportResPattern_c2h1d0t1(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f1) }
891 func TestTransportResPattern_c2h1d0t2(t *testing.T) { testTransportResPattern(t, f2, f1, d0, f2) }
892 func TestTransportResPattern_c2h1d1t0(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f0) }
893 func TestTransportResPattern_c2h1d1t1(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f1) }
894 func TestTransportResPattern_c2h1d1t2(t *testing.T) { testTransportResPattern(t, f2, f1, d1, f2) }
895 func TestTransportResPattern_c2h2d0t0(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f0) }
896 func TestTransportResPattern_c2h2d0t1(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f1) }
897 func TestTransportResPattern_c2h2d0t2(t *testing.T) { testTransportResPattern(t, f2, f2, d0, f2) }
898 func TestTransportResPattern_c2h2d1t0(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f0) }
899 func TestTransportResPattern_c2h2d1t1(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f1) }
900 func TestTransportResPattern_c2h2d1t2(t *testing.T) { testTransportResPattern(t, f2, f2, d1, f2) }
901
902 func testTransportResPattern(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) {
903 synctest.Test(t, func(t *testing.T) {
904 testTransportResPatternBubble(t, expect100Continue, resHeader, withData, trailers)
905 })
906 }
907 func testTransportResPatternBubble(t *testing.T, expect100Continue, resHeader headerType, withData bool, trailers headerType) {
908 const reqBody = "some request body"
909 const resBody = "some response body"
910
911 if resHeader == noHeader {
912
913
914 panic("invalid combination")
915 }
916
917 tc := newTestClientConn(t)
918 tc.greet()
919
920 req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(reqBody))
921 if expect100Continue != noHeader {
922 req.Header.Set("Expect", "100-continue")
923 }
924 rt := tc.roundTrip(req)
925
926 tc.wantFrameType(FrameHeaders)
927
928
929 tc.writeHeadersMode(expect100Continue, HeadersFrameParam{
930 StreamID: rt.streamID(),
931 EndHeaders: true,
932 EndStream: false,
933 BlockFragment: tc.makeHeaderBlockFragment(
934 ":status", "100",
935 ),
936 })
937
938
939 tc.wantData(wantData{
940 streamID: rt.streamID(),
941 endStream: true,
942 size: len(reqBody),
943 })
944
945 hdr := []string{
946 ":status", "200",
947 "x-foo", "blah",
948 "x-bar", "more",
949 }
950 if trailers != noHeader {
951 hdr = append(hdr, "trailer", "some-trailer")
952 }
953 tc.writeHeadersMode(resHeader, HeadersFrameParam{
954 StreamID: rt.streamID(),
955 EndHeaders: true,
956 EndStream: withData == false && trailers == noHeader,
957 BlockFragment: tc.makeHeaderBlockFragment(hdr...),
958 })
959 if withData {
960 endStream := trailers == noHeader
961 tc.writeData(rt.streamID(), endStream, []byte(resBody))
962 }
963 tc.writeHeadersMode(trailers, HeadersFrameParam{
964 StreamID: rt.streamID(),
965 EndHeaders: true,
966 EndStream: true,
967 BlockFragment: tc.makeHeaderBlockFragment(
968 "some-trailer", "some-value",
969 ),
970 })
971
972 rt.wantStatus(200)
973 if !withData {
974 rt.wantBody(nil)
975 } else {
976 rt.wantBody([]byte(resBody))
977 }
978 if trailers == noHeader {
979 rt.wantTrailers(nil)
980 } else {
981 rt.wantTrailers(http.Header{
982 "Some-Trailer": {"some-value"},
983 })
984 }
985 }
986
987
988 func TestTransportUnknown1xx(t *testing.T) { synctest.Test(t, testTransportUnknown1xx) }
989 func testTransportUnknown1xx(t *testing.T) {
990 var buf bytes.Buffer
991 SetTestHookGot1xx(t, func(code int, header textproto.MIMEHeader) error {
992 fmt.Fprintf(&buf, "code=%d header=%v\n", code, header)
993 return nil
994 })
995
996 tc := newTestClientConn(t)
997 tc.greet()
998
999 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1000 rt := tc.roundTrip(req)
1001
1002 for i := 110; i <= 114; i++ {
1003 tc.writeHeaders(HeadersFrameParam{
1004 StreamID: rt.streamID(),
1005 EndHeaders: true,
1006 EndStream: false,
1007 BlockFragment: tc.makeHeaderBlockFragment(
1008 ":status", fmt.Sprint(i),
1009 "foo-bar", fmt.Sprint(i),
1010 ),
1011 })
1012 }
1013 tc.writeHeaders(HeadersFrameParam{
1014 StreamID: rt.streamID(),
1015 EndHeaders: true,
1016 EndStream: true,
1017 BlockFragment: tc.makeHeaderBlockFragment(
1018 ":status", "204",
1019 ),
1020 })
1021
1022 res := rt.response()
1023 if res.StatusCode != 204 {
1024 t.Fatalf("status code = %v; want 204", res.StatusCode)
1025 }
1026 want := `code=110 header=map[Foo-Bar:[110]]
1027 code=111 header=map[Foo-Bar:[111]]
1028 code=112 header=map[Foo-Bar:[112]]
1029 code=113 header=map[Foo-Bar:[113]]
1030 code=114 header=map[Foo-Bar:[114]]
1031 `
1032 if got := buf.String(); got != want {
1033 t.Errorf("Got trace:\n%s\nWant:\n%s", got, want)
1034 }
1035 }
1036
1037 func TestTransportReceiveUndeclaredTrailer(t *testing.T) {
1038 synctest.Test(t, testTransportReceiveUndeclaredTrailer)
1039 }
1040 func testTransportReceiveUndeclaredTrailer(t *testing.T) {
1041 tc := newTestClientConn(t)
1042 tc.greet()
1043
1044 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1045 rt := tc.roundTrip(req)
1046
1047 tc.writeHeaders(HeadersFrameParam{
1048 StreamID: rt.streamID(),
1049 EndHeaders: true,
1050 EndStream: false,
1051 BlockFragment: tc.makeHeaderBlockFragment(
1052 ":status", "200",
1053 ),
1054 })
1055 tc.writeHeaders(HeadersFrameParam{
1056 StreamID: rt.streamID(),
1057 EndHeaders: true,
1058 EndStream: true,
1059 BlockFragment: tc.makeHeaderBlockFragment(
1060 "some-trailer", "I'm an undeclared Trailer!",
1061 ),
1062 })
1063
1064 rt.wantStatus(200)
1065 rt.wantBody(nil)
1066 rt.wantTrailers(http.Header{
1067 "Some-Trailer": []string{"I'm an undeclared Trailer!"},
1068 })
1069 }
1070
1071 func TestTransportInvalidTrailer_Pseudo1(t *testing.T) {
1072 testTransportInvalidTrailer_Pseudo(t, oneHeader)
1073 }
1074 func TestTransportInvalidTrailer_Pseudo2(t *testing.T) {
1075 testTransportInvalidTrailer_Pseudo(t, splitHeader)
1076 }
1077 func testTransportInvalidTrailer_Pseudo(t *testing.T, trailers headerType) {
1078 testInvalidTrailer(t, trailers, PseudoHeaderError(":colon"),
1079 ":colon", "foo",
1080 "foo", "bar",
1081 )
1082 }
1083
1084 func TestTransportInvalidTrailer_Capital1(t *testing.T) {
1085 testTransportInvalidTrailer_Capital(t, oneHeader)
1086 }
1087 func TestTransportInvalidTrailer_Capital2(t *testing.T) {
1088 testTransportInvalidTrailer_Capital(t, splitHeader)
1089 }
1090 func testTransportInvalidTrailer_Capital(t *testing.T, trailers headerType) {
1091 testInvalidTrailer(t, trailers, HeaderFieldNameError("Capital"),
1092 "foo", "bar",
1093 "Capital", "bad",
1094 )
1095 }
1096 func TestTransportInvalidTrailer_EmptyFieldName(t *testing.T) {
1097 testInvalidTrailer(t, oneHeader, HeaderFieldNameError(""),
1098 "", "bad",
1099 )
1100 }
1101 func TestTransportInvalidTrailer_BinaryFieldValue(t *testing.T) {
1102 testInvalidTrailer(t, oneHeader, HeaderFieldValueError("x"),
1103 "x", "has\nnewline",
1104 )
1105 }
1106
1107 func testInvalidTrailer(t *testing.T, mode headerType, wantErr error, trailers ...string) {
1108 synctest.Test(t, func(t *testing.T) {
1109 testInvalidTrailerBubble(t, mode, wantErr, trailers...)
1110 })
1111 }
1112 func testInvalidTrailerBubble(t *testing.T, mode headerType, wantErr error, trailers ...string) {
1113 tc := newTestClientConn(t)
1114 tc.greet()
1115
1116 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1117 rt := tc.roundTrip(req)
1118
1119 tc.writeHeaders(HeadersFrameParam{
1120 StreamID: rt.streamID(),
1121 EndHeaders: true,
1122 EndStream: false,
1123 BlockFragment: tc.makeHeaderBlockFragment(
1124 ":status", "200",
1125 "trailer", "declared",
1126 ),
1127 })
1128 tc.writeHeadersMode(mode, HeadersFrameParam{
1129 StreamID: rt.streamID(),
1130 EndHeaders: true,
1131 EndStream: true,
1132 BlockFragment: tc.makeHeaderBlockFragment(trailers...),
1133 })
1134
1135 rt.wantStatus(200)
1136 body, err := rt.readBody()
1137 se, ok := err.(StreamError)
1138 if !ok || se.Cause != wantErr {
1139 t.Fatalf("res.Body ReadAll error = %q, %#v; want StreamError with cause %T, %#v", body, err, wantErr, wantErr)
1140 }
1141 if len(body) > 0 {
1142 t.Fatalf("body = %q; want nothing", body)
1143 }
1144 }
1145
1146
1147
1148
1149
1150 func headerListSize(h http.Header) (size uint32) {
1151 for k, vv := range h {
1152 for _, v := range vv {
1153 hf := hpack.HeaderField{Name: k, Value: v}
1154 size += hf.Size()
1155 }
1156 }
1157 return size
1158 }
1159
1160
1161
1162
1163
1164
1165
1166
1167 func padHeaders(t *testing.T, h http.Header, limit uint64, filler string) {
1168 if limit > 0xffffffff {
1169 t.Fatalf("padHeaders: refusing to pad to more than 2^32-1 bytes. limit = %v", limit)
1170 }
1171 hf := hpack.HeaderField{Name: "Pad-Headers", Value: ""}
1172 minPadding := uint64(hf.Size())
1173 size := uint64(headerListSize(h))
1174
1175 minlimit := size + minPadding
1176 if limit < minlimit {
1177 t.Fatalf("padHeaders: limit %v < %v", limit, minlimit)
1178 }
1179
1180
1181
1182 nameFmt := "Pad-Headers-%06d"
1183 hf = hpack.HeaderField{Name: fmt.Sprintf(nameFmt, 1), Value: filler}
1184 fieldSize := uint64(hf.Size())
1185
1186
1187
1188 limit = limit - minPadding
1189 for i := 0; size+fieldSize < limit; i++ {
1190 name := fmt.Sprintf(nameFmt, i)
1191 h.Add(name, filler)
1192 size += fieldSize
1193 }
1194
1195
1196 remain := limit - size
1197 lastValue := strings.Repeat("*", int(remain))
1198 h.Add("Pad-Headers", lastValue)
1199 }
1200
1201 func TestPadHeaders(t *testing.T) {
1202 check := func(h http.Header, limit uint32, fillerLen int) {
1203 if h == nil {
1204 h = make(http.Header)
1205 }
1206 filler := strings.Repeat("f", fillerLen)
1207 padHeaders(t, h, uint64(limit), filler)
1208 gotSize := headerListSize(h)
1209 if gotSize != limit {
1210 t.Errorf("Got size = %v; want %v", gotSize, limit)
1211 }
1212 }
1213
1214 hf := hpack.HeaderField{Name: "Pad-Headers", Value: ""}
1215 minLimit := hf.Size()
1216 for limit := minLimit; limit <= 128; limit++ {
1217 for fillerLen := 0; uint32(fillerLen) <= limit; fillerLen++ {
1218 check(nil, limit, fillerLen)
1219 }
1220 }
1221
1222
1223
1224
1225
1226
1227 tests := []struct {
1228 fillerLen int
1229 limit uint32
1230 }{
1231 {
1232 fillerLen: 64,
1233 limit: 1024,
1234 },
1235 {
1236 fillerLen: 1024,
1237 limit: 1286,
1238 },
1239 {
1240 fillerLen: 256,
1241 limit: 2048,
1242 },
1243 {
1244 fillerLen: 1024,
1245 limit: 10 * 1024,
1246 },
1247 {
1248 fillerLen: 1023,
1249 limit: 11 * 1024,
1250 },
1251 }
1252 h := make(http.Header)
1253 for _, tc := range tests {
1254 check(nil, tc.limit, tc.fillerLen)
1255 check(h, tc.limit, tc.fillerLen)
1256 }
1257 }
1258
1259 func TestTransportChecksRequestHeaderListSize(t *testing.T) {
1260 synctest.Test(t, testTransportChecksRequestHeaderListSize)
1261 }
1262 func testTransportChecksRequestHeaderListSize(t *testing.T) {
1263 const peerSize = 16 << 10
1264
1265 tc := newTestClientConn(t)
1266 tc.greet(Setting{SettingMaxHeaderListSize, peerSize})
1267
1268 checkRoundTrip := func(req *http.Request, wantErr error, desc string) {
1269 t.Helper()
1270 rt := tc.roundTrip(req)
1271 if wantErr != nil {
1272 if err := rt.err(); !errors.Is(err, wantErr) {
1273 t.Errorf("%v: RoundTrip err = %v; want %v", desc, err, wantErr)
1274 }
1275 return
1276 }
1277
1278 tc.wantFrameType(FrameHeaders)
1279 tc.writeHeaders(HeadersFrameParam{
1280 StreamID: rt.streamID(),
1281 EndHeaders: true,
1282 EndStream: true,
1283 BlockFragment: tc.makeHeaderBlockFragment(
1284 ":status", "200",
1285 ),
1286 })
1287
1288 rt.wantStatus(http.StatusOK)
1289 }
1290 headerListSizeForRequest := func(req *http.Request) (size uint64) {
1291 _, err := httpcommon.EncodeHeaders(context.Background(), httpcommon.EncodeHeadersParam{
1292 Request: httpcommon.Request{
1293 Header: req.Header,
1294 Trailer: req.Trailer,
1295 URL: req.URL,
1296 Host: req.Host,
1297 Method: req.Method,
1298 ActualContentLength: req.ContentLength,
1299 },
1300 AddGzipHeader: true,
1301 PeerMaxHeaderListSize: 0xffffffffffffffff,
1302 }, func(name, value string) {
1303 hf := hpack.HeaderField{Name: name, Value: value}
1304 size += uint64(hf.Size())
1305 })
1306 if err != nil {
1307 t.Fatal(err)
1308 }
1309 return size
1310 }
1311
1312
1313
1314 newRequest := func() *http.Request {
1315
1316 const bodytext = "hello"
1317 body := strings.NewReader(bodytext)
1318 req, err := http.NewRequest("POST", "https://example.tld/", body)
1319 if err != nil {
1320 t.Fatalf("newRequest: NewRequest: %v", err)
1321 }
1322 req.ContentLength = int64(len(bodytext))
1323 req.Header = http.Header{"User-Agent": nil}
1324 return req
1325 }
1326
1327
1328 req := newRequest()
1329 req.Trailer = make(http.Header)
1330 filler := strings.Repeat("*", 1024)
1331 padHeaders(t, req.Trailer, peerSize, filler)
1332
1333
1334 defaultBytes := headerListSizeForRequest(req)
1335 padHeaders(t, req.Header, peerSize-defaultBytes, filler)
1336 checkRoundTrip(req, nil, "Headers & Trailers under limit")
1337
1338
1339 req = newRequest()
1340 padHeaders(t, req.Header, peerSize, filler)
1341 checkRoundTrip(req, ErrRequestHeaderListSize, "Headers over limit")
1342
1343
1344 req = newRequest()
1345 req.Trailer = make(http.Header)
1346 padHeaders(t, req.Trailer, peerSize+1, filler)
1347 checkRoundTrip(req, ErrRequestHeaderListSize, "Trailers over limit")
1348
1349
1350 req = newRequest()
1351 filler = strings.Repeat("*", int(peerSize))
1352 req.Header.Set("Big", filler)
1353 checkRoundTrip(req, ErrRequestHeaderListSize, "Single large header")
1354
1355
1356 req = newRequest()
1357 req.Trailer = make(http.Header)
1358 req.Trailer.Set("Big", filler)
1359 checkRoundTrip(req, ErrRequestHeaderListSize, "Single large trailer")
1360 }
1361
1362 func TestTransportChecksResponseHeaderListSize(t *testing.T) {
1363 t.Run("headers", func(t *testing.T) {
1364 synctest.Test(t, testTransportChecksResponseHeaderListSize)
1365 })
1366 t.Run("trailers", func(t *testing.T) {
1367 synctest.Test(t, testTransportChecksResponseTrailerHeaderListSize)
1368 })
1369 }
1370
1371 func testTransportChecksResponseHeaderListSize(t *testing.T) {
1372 tc := newTestClientConn(t)
1373 tc.greet()
1374
1375 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1376 rt := tc.roundTrip(req)
1377
1378 tc.wantFrameType(FrameHeaders)
1379
1380 hdr := []string{":status", "200"}
1381 large := strings.Repeat("a", 1<<10)
1382 for range 5042 {
1383 hdr = append(hdr, large, large)
1384 }
1385 hbf := tc.makeHeaderBlockFragment(hdr...)
1386
1387
1388
1389 if size, want := len(hbf), 6329; size != want {
1390 t.Fatalf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want)
1391 }
1392 tc.writeHeaders(HeadersFrameParam{
1393 StreamID: rt.streamID(),
1394 EndHeaders: true,
1395 EndStream: true,
1396 BlockFragment: hbf,
1397 })
1398
1399 res, err := rt.result()
1400 if e, ok := err.(StreamError); ok {
1401 err = e.Cause
1402 }
1403 if err != ErrResponseHeaderListSize {
1404 size := int64(0)
1405 if res != nil {
1406 res.Body.Close()
1407 for k, vv := range res.Header {
1408 for _, v := range vv {
1409 size += int64(len(k)) + int64(len(v)) + 32
1410 }
1411 }
1412 }
1413 t.Fatalf("RoundTrip Error = %v (and %d bytes of response headers); want errResponseHeaderListSize", err, size)
1414 }
1415 }
1416
1417 func testTransportChecksResponseTrailerHeaderListSize(t *testing.T) {
1418 tc := newTestClientConn(t)
1419 tc.greet()
1420
1421 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1422 rt := tc.roundTrip(req)
1423
1424 tc.wantFrameType(FrameHeaders)
1425 tc.writeHeaders(HeadersFrameParam{
1426 StreamID: rt.streamID(),
1427 EndHeaders: true,
1428 EndStream: false,
1429 BlockFragment: tc.makeHeaderBlockFragment(
1430 ":status", "200",
1431 "trailer", "x-trailer",
1432 ),
1433 })
1434 rt.wantStatus(200)
1435
1436 var hdr []string
1437 large := strings.Repeat("a", 1<<10)
1438 for range 5042 {
1439 hdr = append(hdr, large, large)
1440 }
1441 hbf := tc.makeHeaderBlockFragment(hdr...)
1442
1443 if size, want := len(hbf), 6328; size != want {
1444 t.Fatalf("encoding over 10MB of duplicate keypairs took %d bytes; expected %d", size, want)
1445 }
1446 tc.writeHeaders(HeadersFrameParam{
1447 StreamID: rt.streamID(),
1448 EndHeaders: true,
1449 EndStream: true,
1450 BlockFragment: hbf,
1451 })
1452
1453 _, err := rt.readBody()
1454 if e, ok := err.(StreamError); ok {
1455 err = e.Cause
1456 }
1457 if err != ErrResponseHeaderListSize {
1458 t.Errorf("Read = %v, want %v", err, ErrResponseHeaderListSize)
1459 }
1460
1461
1462 tc.wantFrameType(FrameRSTStream)
1463 tc.wantIdle()
1464 }
1465
1466 func TestTransportCookieHeaderSplit(t *testing.T) { synctest.Test(t, testTransportCookieHeaderSplit) }
1467 func testTransportCookieHeaderSplit(t *testing.T) {
1468 tc := newTestClientConn(t)
1469 tc.greet()
1470
1471 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1472 req.Header.Add("Cookie", "a=b;c=d; e=f;")
1473 req.Header.Add("Cookie", "e=f;g=h; ")
1474 req.Header.Add("Cookie", "i=j")
1475 rt := tc.roundTrip(req)
1476
1477 tc.wantHeaders(wantHeader{
1478 streamID: rt.streamID(),
1479 endStream: true,
1480 header: http.Header{
1481 "cookie": []string{"a=b", "c=d", "e=f", "e=f", "g=h", "i=j"},
1482 },
1483 })
1484 tc.writeHeaders(HeadersFrameParam{
1485 StreamID: rt.streamID(),
1486 EndHeaders: true,
1487 EndStream: true,
1488 BlockFragment: tc.makeHeaderBlockFragment(
1489 ":status", "204",
1490 ),
1491 })
1492
1493 if err := rt.err(); err != nil {
1494 t.Fatalf("RoundTrip = %v, want success", err)
1495 }
1496 }
1497
1498
1499
1500
1501 func TestTransportBodyReadErrorType(t *testing.T) {
1502 doPanic := make(chan bool, 1)
1503 ts := newTestServer(t,
1504 func(w http.ResponseWriter, r *http.Request) {
1505 w.(http.Flusher).Flush()
1506 <-doPanic
1507 panic("boom")
1508 },
1509 optQuiet,
1510 )
1511
1512 tr := newTransport(t)
1513 c := &http.Client{Transport: tr}
1514
1515 res, err := c.Get(ts.URL)
1516 if err != nil {
1517 t.Fatal(err)
1518 }
1519 defer res.Body.Close()
1520 doPanic <- true
1521 buf := make([]byte, 100)
1522 n, err := res.Body.Read(buf)
1523 got, ok := err.(StreamError)
1524 want := StreamError{StreamID: 0x1, Code: 0x2}
1525 if !ok || got.StreamID != want.StreamID || got.Code != want.Code {
1526 t.Errorf("Read = %v, %#v; want error %#v", n, err, want)
1527 }
1528 }
1529
1530
1531
1532
1533 func TestTransportDoubleCloseOnWriteError(t *testing.T) {
1534 var (
1535 mu sync.Mutex
1536 conn net.Conn
1537 )
1538
1539 ts := newTestServer(t,
1540 func(w http.ResponseWriter, r *http.Request) {
1541 mu.Lock()
1542 defer mu.Unlock()
1543 if conn != nil {
1544 conn.Close()
1545 }
1546 },
1547 )
1548
1549 tr := newTransport(t)
1550 tr.DialTLS = func(network, addr string) (net.Conn, error) {
1551 tc, err := tls.Dial(network, addr, tlsConfigInsecure)
1552 if err != nil {
1553 return nil, err
1554 }
1555 mu.Lock()
1556 defer mu.Unlock()
1557 conn = tc
1558 return tc, nil
1559 }
1560 c := &http.Client{Transport: tr}
1561 c.Get(ts.URL)
1562 }
1563
1564
1565
1566
1567 func TestTransportDisableKeepAlives(t *testing.T) {
1568 ts := newTestServer(t,
1569 func(w http.ResponseWriter, r *http.Request) {
1570 io.WriteString(w, "hi")
1571 },
1572 )
1573
1574 connClosed := make(chan struct{})
1575 tr := newTransport(t)
1576 tr.Dial = func(network, addr string) (net.Conn, error) {
1577 tc, err := net.Dial(network, addr)
1578 if err != nil {
1579 return nil, err
1580 }
1581 return ¬eCloseConn{Conn: tc, closefn: func() { close(connClosed) }}, nil
1582 }
1583 tr.DisableKeepAlives = true
1584 c := &http.Client{Transport: tr}
1585 res, err := c.Get(ts.URL)
1586 if err != nil {
1587 t.Fatal(err)
1588 }
1589 if _, err := io.ReadAll(res.Body); err != nil {
1590 t.Fatal(err)
1591 }
1592 defer res.Body.Close()
1593
1594 select {
1595 case <-connClosed:
1596 case <-time.After(1 * time.Second):
1597 t.Errorf("timeout")
1598 }
1599
1600 }
1601
1602
1603
1604 func TestTransportDisableKeepAlives_Concurrency(t *testing.T) {
1605 const D = 25 * time.Millisecond
1606 ts := newTestServer(t,
1607 func(w http.ResponseWriter, r *http.Request) {
1608 time.Sleep(D)
1609 io.WriteString(w, "hi")
1610 },
1611 )
1612
1613 var dials int32
1614 var conns sync.WaitGroup
1615 tr := newTransport(t)
1616 tr.Dial = func(network, addr string) (net.Conn, error) {
1617 tc, err := net.Dial(network, addr)
1618 if err != nil {
1619 return nil, err
1620 }
1621 atomic.AddInt32(&dials, 1)
1622 conns.Add(1)
1623 return ¬eCloseConn{Conn: tc, closefn: func() { conns.Done() }}, nil
1624 }
1625 tr.DisableKeepAlives = true
1626 c := &http.Client{Transport: tr}
1627 var reqs sync.WaitGroup
1628 const N = 20
1629 for i := range N {
1630 reqs.Add(1)
1631 if i == N-1 {
1632
1633
1634
1635
1636
1637
1638 time.Sleep(D * 2)
1639 }
1640 go func() {
1641 defer reqs.Done()
1642 res, err := c.Get(ts.URL)
1643 if err != nil {
1644 t.Error(err)
1645 return
1646 }
1647 if _, err := io.ReadAll(res.Body); err != nil {
1648 t.Error(err)
1649 return
1650 }
1651 res.Body.Close()
1652 }()
1653 }
1654 reqs.Wait()
1655 conns.Wait()
1656 t.Logf("did %d dials, %d requests", atomic.LoadInt32(&dials), N)
1657 }
1658
1659 type noteCloseConn struct {
1660 net.Conn
1661 onceClose sync.Once
1662 closefn func()
1663 }
1664
1665 func (c *noteCloseConn) Close() error {
1666 c.onceClose.Do(c.closefn)
1667 return c.Conn.Close()
1668 }
1669
1670 func isTimeout(err error) bool {
1671 switch err := err.(type) {
1672 case nil:
1673 return false
1674 case *url.Error:
1675 return isTimeout(err.Err)
1676 case net.Error:
1677 return err.Timeout()
1678 }
1679 return false
1680 }
1681
1682
1683 func TestTransportResponseHeaderTimeout_NoBody(t *testing.T) {
1684 synctest.Test(t, func(t *testing.T) {
1685 testTransportResponseHeaderTimeout(t, false)
1686 })
1687 }
1688 func TestTransportResponseHeaderTimeout_Body(t *testing.T) {
1689 synctest.Test(t, func(t *testing.T) {
1690 testTransportResponseHeaderTimeout(t, true)
1691 })
1692 }
1693
1694 func testTransportResponseHeaderTimeout(t *testing.T, body bool) {
1695 const bodySize = 4 << 20
1696 tc := newTestClientConn(t, func(t1 *http.Transport) {
1697 t1.ResponseHeaderTimeout = 5 * time.Millisecond
1698 })
1699 tc.greet()
1700
1701 var req *http.Request
1702 var reqBody *testRequestBody
1703 if body {
1704 reqBody = tc.newRequestBody()
1705 reqBody.writeBytes(bodySize)
1706 reqBody.closeWithError(io.EOF)
1707 req, _ = http.NewRequest("POST", "https://dummy.tld/", reqBody)
1708 req.Header.Set("Content-Type", "text/foo")
1709 } else {
1710 req, _ = http.NewRequest("GET", "https://dummy.tld/", nil)
1711 }
1712
1713 rt := tc.roundTrip(req)
1714
1715 tc.wantFrameType(FrameHeaders)
1716
1717 tc.writeWindowUpdate(0, bodySize)
1718 tc.writeWindowUpdate(rt.streamID(), bodySize)
1719
1720 if body {
1721 tc.wantData(wantData{
1722 endStream: true,
1723 size: bodySize,
1724 multiple: true,
1725 })
1726 }
1727
1728 time.Sleep(4 * time.Millisecond)
1729 if rt.done() {
1730 t.Fatalf("RoundTrip is done after 4ms; want still waiting")
1731 }
1732 time.Sleep(1 * time.Millisecond)
1733
1734 if err := rt.err(); !isTimeout(err) {
1735 t.Fatalf("RoundTrip error: %v; want timeout error", err)
1736 }
1737 }
1738
1739
1740
1741
1742
1743 func TestTransportSettingsFlowControlUpdateBeyondLimit(t *testing.T) {
1744 synctest.Test(t, testTransportSettingsFlowControlUpdateBeyondLimit)
1745 }
1746 func testTransportSettingsFlowControlUpdateBeyondLimit(t *testing.T) {
1747 tc := newTestClientConn(t)
1748 tc.greet()
1749
1750 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1751 rt := tc.roundTrip(req)
1752 tc.wantFrameType(FrameHeaders)
1753
1754
1755 const windowIncrease = 1000
1756 tc.writeWindowUpdate(rt.streamID(), windowIncrease)
1757 tc.wantIdle()
1758
1759
1760 const maxWindowSize = (1 << 31) - 1
1761 const maxInitialWindowSize = maxWindowSize - windowIncrease
1762 tc.writeSettings(Setting{SettingInitialWindowSize, maxInitialWindowSize + 1})
1763 tc.wantGoAway(0, ErrCodeFlowControl)
1764 }
1765
1766
1767
1768 func TestTransportSettingsFlowControlUpdateWithinLimit(t *testing.T) {
1769 synctest.Test(t, testTransportSettingsFlowControlUpdateWithinLimit)
1770 }
1771 func testTransportSettingsFlowControlUpdateWithinLimit(t *testing.T) {
1772 tc := newTestClientConn(t)
1773 tc.greet()
1774
1775 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1776 rt := tc.roundTrip(req)
1777 tc.wantFrameType(FrameHeaders)
1778
1779
1780 const windowIncrease = 1000
1781 tc.writeWindowUpdate(rt.streamID(), windowIncrease)
1782 tc.wantIdle()
1783
1784
1785 const maxWindowSize = (1 << 31) - 1
1786 const maxInitialWindowSize = maxWindowSize - windowIncrease
1787 tc.writeSettings(Setting{SettingInitialWindowSize, maxInitialWindowSize})
1788 tc.wantSettingsAck()
1789 tc.wantIdle()
1790 }
1791
1792
1793 func TestTransportWindowUpdateBeyondLimit(t *testing.T) {
1794 synctest.Test(t, testTransportWindowUpdateBeyondLimit)
1795 }
1796 func testTransportWindowUpdateBeyondLimit(t *testing.T) {
1797 const windowIncrease uint32 = (1 << 31) - 1
1798 tc := newTestClientConn(t)
1799 tc.greet()
1800
1801 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
1802 rt := tc.roundTrip(req)
1803 tc.wantHeaders(wantHeader{
1804 streamID: rt.streamID(),
1805 endStream: true,
1806 })
1807
1808 tc.writeWindowUpdate(rt.streamID(), windowIncrease)
1809 tc.wantRSTStream(rt.streamID(), ErrCodeFlowControl)
1810
1811 tc.writeWindowUpdate(0, windowIncrease)
1812 tc.wantClosed()
1813 }
1814
1815 func TestTransportDisableCompression(t *testing.T) {
1816 const body = "sup"
1817 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
1818 want := http.Header{
1819 "User-Agent": []string{"Go-http-client/2.0"},
1820 }
1821 if !reflect.DeepEqual(r.Header, want) {
1822 t.Errorf("request headers = %v; want %v", r.Header, want)
1823 }
1824 })
1825
1826 tr := newTransport(t)
1827 tr.DisableCompression = true
1828
1829 req, err := http.NewRequest("GET", ts.URL, nil)
1830 if err != nil {
1831 t.Fatal(err)
1832 }
1833 res, err := tr.RoundTrip(req)
1834 if err != nil {
1835 t.Fatal(err)
1836 }
1837 defer res.Body.Close()
1838 }
1839
1840
1841 func TestTransportRejectsConnHeaders(t *testing.T) {
1842 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
1843 var got []string
1844 for k := range r.Header {
1845 got = append(got, k)
1846 }
1847 sort.Strings(got)
1848 w.Header().Set("Got-Header", strings.Join(got, ","))
1849 })
1850
1851 tr := newTransport(t)
1852
1853 tests := []struct {
1854 key string
1855 value []string
1856 want string
1857 }{
1858 {
1859 key: "Upgrade",
1860 value: []string{"anything"},
1861 want: "ERROR: http2: invalid Upgrade request header: [\"anything\"]",
1862 },
1863 {
1864 key: "Connection",
1865 value: []string{"foo"},
1866 want: "ERROR: http2: invalid Connection request header: [\"foo\"]",
1867 },
1868 {
1869 key: "Connection",
1870 value: []string{"close"},
1871 want: "Accept-Encoding,User-Agent",
1872 },
1873 {
1874 key: "Connection",
1875 value: []string{"CLoSe"},
1876 want: "Accept-Encoding,User-Agent",
1877 },
1878 {
1879 key: "Connection",
1880 value: []string{"close", "something-else"},
1881 want: "ERROR: http2: invalid Connection request header: [\"close\" \"something-else\"]",
1882 },
1883 {
1884 key: "Connection",
1885 value: []string{"keep-alive"},
1886 want: "Accept-Encoding,User-Agent",
1887 },
1888 {
1889 key: "Connection",
1890 value: []string{"Keep-ALIVE"},
1891 want: "Accept-Encoding,User-Agent",
1892 },
1893 {
1894 key: "Proxy-Connection",
1895 value: []string{"keep-alive"},
1896 want: "Accept-Encoding,User-Agent",
1897 },
1898 {
1899 key: "Transfer-Encoding",
1900 value: []string{""},
1901 want: "Accept-Encoding,User-Agent",
1902 },
1903 {
1904 key: "Transfer-Encoding",
1905 value: []string{"foo"},
1906 want: "ERROR: http2: invalid Transfer-Encoding request header: [\"foo\"]",
1907 },
1908 {
1909 key: "Transfer-Encoding",
1910 value: []string{"chunked"},
1911 want: "Accept-Encoding,User-Agent",
1912 },
1913 {
1914 key: "Transfer-Encoding",
1915 value: []string{"chunKed"},
1916 want: "ERROR: http2: invalid Transfer-Encoding request header: [\"chunKed\"]",
1917 },
1918 {
1919 key: "Transfer-Encoding",
1920 value: []string{"chunked", "other"},
1921 want: "ERROR: http2: invalid Transfer-Encoding request header: [\"chunked\" \"other\"]",
1922 },
1923 {
1924 key: "Content-Length",
1925 value: []string{"123"},
1926 want: "Accept-Encoding,User-Agent",
1927 },
1928 {
1929 key: "Keep-Alive",
1930 value: []string{"doop"},
1931 want: "Accept-Encoding,User-Agent",
1932 },
1933 }
1934
1935 for _, tt := range tests {
1936 req, _ := http.NewRequest("GET", ts.URL, nil)
1937 req.Header[tt.key] = tt.value
1938 res, err := tr.RoundTrip(req)
1939 var got string
1940 if err != nil {
1941 got = fmt.Sprintf("ERROR: %v", err)
1942 } else {
1943 got = res.Header.Get("Got-Header")
1944 res.Body.Close()
1945 }
1946 if got != tt.want {
1947 t.Errorf("For key %q, value %q, got = %q; want %q", tt.key, tt.value, got, tt.want)
1948 }
1949 }
1950 }
1951
1952
1953
1954 func TestTransportRejectsContentLengthWithSign(t *testing.T) {
1955 tests := []struct {
1956 name string
1957 cl []string
1958 wantCL string
1959 }{
1960 {
1961 name: "proper content-length",
1962 cl: []string{"3"},
1963 wantCL: "3",
1964 },
1965 {
1966 name: "ignore cl with plus sign",
1967 cl: []string{"+3"},
1968 wantCL: "",
1969 },
1970 {
1971 name: "ignore cl with minus sign",
1972 cl: []string{"-3"},
1973 wantCL: "",
1974 },
1975 {
1976 name: "max int64, for safe uint64->int64 conversion",
1977 cl: []string{"9223372036854775807"},
1978 wantCL: "9223372036854775807",
1979 },
1980 {
1981 name: "overflows int64, so ignored",
1982 cl: []string{"9223372036854775808"},
1983 wantCL: "",
1984 },
1985 }
1986
1987 for _, tt := range tests {
1988 t.Run(tt.name, func(t *testing.T) {
1989 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
1990 w.Header().Set("Content-Length", tt.cl[0])
1991 })
1992 tr := newTransport(t)
1993
1994 req, _ := http.NewRequest("HEAD", ts.URL, nil)
1995 res, err := tr.RoundTrip(req)
1996
1997 var got string
1998 if err != nil {
1999 got = fmt.Sprintf("ERROR: %v", err)
2000 } else {
2001 got = res.Header.Get("Content-Length")
2002 res.Body.Close()
2003 }
2004
2005 if got != tt.wantCL {
2006 t.Fatalf("Got: %q\nWant: %q", got, tt.wantCL)
2007 }
2008 })
2009 }
2010 }
2011
2012
2013
2014 func TestTransportFailsOnInvalidHeadersAndTrailers(t *testing.T) {
2015 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
2016 var got []string
2017 for k := range r.Header {
2018 got = append(got, k)
2019 }
2020 sort.Strings(got)
2021 w.Header().Set("Got-Header", strings.Join(got, ","))
2022 })
2023
2024 tests := [...]struct {
2025 h http.Header
2026 t http.Header
2027 wantErr string
2028 }{
2029 0: {
2030 h: http.Header{"with space": {"foo"}},
2031 wantErr: `net/http: invalid header field name "with space"`,
2032 },
2033 1: {
2034 h: http.Header{"name": {"Брэд"}},
2035 wantErr: "",
2036 },
2037 2: {
2038 h: http.Header{"имя": {"Brad"}},
2039 wantErr: `net/http: invalid header field name "имя"`,
2040 },
2041 3: {
2042 h: http.Header{"foo": {"foo\x01bar"}},
2043 wantErr: `net/http: invalid header field value for "foo"`,
2044 },
2045 4: {
2046 t: http.Header{"foo": {"foo\x01bar"}},
2047 wantErr: `net/http: invalid trailer field value for "foo"`,
2048 },
2049 5: {
2050 t: http.Header{"x-\r\nda": {"foo\x01bar"}},
2051 wantErr: `net/http: invalid trailer field name "x-\r\nda"`,
2052 },
2053 }
2054
2055 tr := newTransport(t)
2056
2057 for i, tt := range tests {
2058 req, _ := http.NewRequest("GET", ts.URL, nil)
2059 req.Header = tt.h
2060 if req.Header == nil {
2061 req.Header = http.Header{}
2062 }
2063 req.Trailer = tt.t
2064 res, err := tr.RoundTrip(req)
2065 var bad bool
2066 if tt.wantErr == "" {
2067 if err != nil {
2068 bad = true
2069 t.Errorf("case %d: error = %v; want no error", i, err)
2070 }
2071 } else {
2072 if !strings.Contains(fmt.Sprint(err), tt.wantErr) {
2073 bad = true
2074 t.Errorf("case %d: error = %v; want error %q", i, err, tt.wantErr)
2075 }
2076 }
2077 if err == nil {
2078 if bad {
2079 t.Logf("case %d: server got headers %q", i, res.Header.Get("Got-Header"))
2080 }
2081 res.Body.Close()
2082 }
2083 }
2084 }
2085
2086
2087
2088
2089 func TestTransportReadHeadResponse(t *testing.T) { synctest.Test(t, testTransportReadHeadResponse) }
2090 func testTransportReadHeadResponse(t *testing.T) {
2091 tc := newTestClientConn(t)
2092 tc.greet()
2093
2094 req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil)
2095 rt := tc.roundTrip(req)
2096
2097 tc.wantFrameType(FrameHeaders)
2098 tc.writeHeaders(HeadersFrameParam{
2099 StreamID: rt.streamID(),
2100 EndHeaders: true,
2101 EndStream: false,
2102 BlockFragment: tc.makeHeaderBlockFragment(
2103 ":status", "200",
2104 "content-length", "123",
2105 ),
2106 })
2107 tc.writeData(rt.streamID(), true, nil)
2108
2109 res := rt.response()
2110 if res.ContentLength != 123 {
2111 t.Fatalf("Content-Length = %d; want 123", res.ContentLength)
2112 }
2113 rt.wantBody(nil)
2114 }
2115
2116 func TestTransportReadHeadResponseWithBody(t *testing.T) {
2117 synctest.Test(t, testTransportReadHeadResponseWithBody)
2118 }
2119 func testTransportReadHeadResponseWithBody(t *testing.T) {
2120
2121
2122 log.SetOutput(io.Discard)
2123 defer log.SetOutput(os.Stderr)
2124
2125 response := "redirecting to /elsewhere"
2126 tc := newTestClientConn(t)
2127 tc.greet()
2128
2129 req, _ := http.NewRequest("HEAD", "https://dummy.tld/", nil)
2130 rt := tc.roundTrip(req)
2131
2132 tc.wantFrameType(FrameHeaders)
2133 tc.writeHeaders(HeadersFrameParam{
2134 StreamID: rt.streamID(),
2135 EndHeaders: true,
2136 EndStream: false,
2137 BlockFragment: tc.makeHeaderBlockFragment(
2138 ":status", "200",
2139 "content-length", strconv.Itoa(len(response)),
2140 ),
2141 })
2142 tc.writeData(rt.streamID(), true, []byte(response))
2143
2144 res := rt.response()
2145 if res.ContentLength != int64(len(response)) {
2146 t.Fatalf("Content-Length = %d; want %d", res.ContentLength, len(response))
2147 }
2148 rt.wantBody(nil)
2149 }
2150
2151 type neverEnding byte
2152
2153 func (b neverEnding) Read(p []byte) (int, error) {
2154 for i := range p {
2155 p[i] = byte(b)
2156 }
2157 return len(p), nil
2158 }
2159
2160
2161
2162 func TestTransportStreamEndsWhileBodyIsBeingWritten(t *testing.T) {
2163 synctest.Test(t, testTransportStreamEndsWhileBodyIsBeingWritten)
2164 }
2165 func testTransportStreamEndsWhileBodyIsBeingWritten(t *testing.T) {
2166 body := "this is the client request body"
2167 const windowSize = 10
2168
2169 tc := newTestClientConn(t)
2170 tc.greet(Setting{SettingInitialWindowSize, windowSize})
2171
2172
2173 req, _ := http.NewRequest("PUT", "https://dummy.tld/", strings.NewReader(body))
2174 rt := tc.roundTrip(req)
2175 tc.wantFrameType(FrameHeaders)
2176 tc.wantData(wantData{
2177 streamID: rt.streamID(),
2178 endStream: false,
2179 size: windowSize,
2180 })
2181
2182
2183 tc.writeHeaders(HeadersFrameParam{
2184 StreamID: rt.streamID(),
2185 EndHeaders: true,
2186 EndStream: true,
2187 BlockFragment: tc.makeHeaderBlockFragment(
2188 ":status", "413",
2189 ),
2190 })
2191 rt.wantStatus(413)
2192 }
2193
2194 func TestTransportFlowControl(t *testing.T) { synctest.Test(t, testTransportFlowControl) }
2195 func testTransportFlowControl(t *testing.T) {
2196 const maxBuffer = 64 << 10
2197 tc := newTestClientConn(t, func(tr *http.Transport) {
2198 tr.HTTP2 = &http.HTTP2Config{
2199 MaxReceiveBufferPerConnection: maxBuffer,
2200 MaxReceiveBufferPerStream: maxBuffer,
2201 MaxReadFrameSize: 16 << 20,
2202 }
2203 })
2204 tc.greet()
2205
2206 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2207 rt := tc.roundTrip(req)
2208 tc.wantFrameType(FrameHeaders)
2209
2210 tc.writeHeaders(HeadersFrameParam{
2211 StreamID: rt.streamID(),
2212 EndHeaders: true,
2213 EndStream: false,
2214 BlockFragment: tc.makeHeaderBlockFragment(
2215 ":status", "200",
2216 ),
2217 })
2218 rt.wantStatus(200)
2219
2220
2221
2222
2223 tc.writeData(rt.streamID(), false, make([]byte, maxBuffer))
2224 tc.wantIdle()
2225
2226
2227
2228 resp := rt.response()
2229 if _, err := io.ReadFull(resp.Body, make([]byte, maxBuffer)); err != nil {
2230 t.Fatalf("io.Body.Read: %v", err)
2231 }
2232 var connTokens, streamTokens uint32
2233 for {
2234 f := tc.readFrame()
2235 if f == nil {
2236 break
2237 }
2238 wu, ok := f.(*WindowUpdateFrame)
2239 if !ok {
2240 t.Fatalf("received unexpected frame %T (want WINDOW_UPDATE)", f)
2241 }
2242 switch wu.StreamID {
2243 case 0:
2244 connTokens += wu.Increment
2245 case wu.StreamID:
2246 streamTokens += wu.Increment
2247 default:
2248 t.Fatalf("received unexpected WINDOW_UPDATE for stream %v", wu.StreamID)
2249 }
2250 }
2251 if got, want := connTokens, uint32(maxBuffer); got != want {
2252 t.Errorf("transport provided %v bytes of connection WINDOW_UPDATE, want %v", got, want)
2253 }
2254 if got, want := streamTokens, uint32(maxBuffer); got != want {
2255 t.Errorf("transport provided %v bytes of stream WINDOW_UPDATE, want %v", got, want)
2256 }
2257 }
2258
2259
2260
2261
2262
2263
2264 func TestTransportUsesGoAwayDebugError_RoundTrip(t *testing.T) {
2265 synctest.Test(t, func(t *testing.T) {
2266 testTransportUsesGoAwayDebugError(t, false)
2267 })
2268 }
2269
2270 func TestTransportUsesGoAwayDebugError_Body(t *testing.T) {
2271 synctest.Test(t, func(t *testing.T) {
2272 testTransportUsesGoAwayDebugError(t, true)
2273 })
2274 }
2275
2276 func testTransportUsesGoAwayDebugError(t *testing.T, failMidBody bool) {
2277 tc := newTestClientConn(t)
2278 tc.greet()
2279
2280 const goAwayErrCode = ErrCodeHTTP11Required
2281 const goAwayDebugData = "some debug data"
2282
2283 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2284 rt := tc.roundTrip(req)
2285
2286 tc.wantFrameType(FrameHeaders)
2287
2288 if failMidBody {
2289 tc.writeHeaders(HeadersFrameParam{
2290 StreamID: rt.streamID(),
2291 EndHeaders: true,
2292 EndStream: false,
2293 BlockFragment: tc.makeHeaderBlockFragment(
2294 ":status", "200",
2295 "content-length", "123",
2296 ),
2297 })
2298 }
2299
2300
2301
2302 tc.writeGoAway(5, ErrCodeNo, []byte(goAwayDebugData))
2303 tc.writeGoAway(5, goAwayErrCode, nil)
2304 tc.closeWrite()
2305
2306 res, err := rt.result()
2307 whence := "RoundTrip"
2308 if failMidBody {
2309 whence = "Body.Read"
2310 if err != nil {
2311 t.Fatalf("RoundTrip error = %v, want success", err)
2312 }
2313 _, err = res.Body.Read(make([]byte, 1))
2314 }
2315
2316 want := GoAwayError{
2317 LastStreamID: 5,
2318 ErrCode: goAwayErrCode,
2319 DebugData: goAwayDebugData,
2320 }
2321 if !reflect.DeepEqual(err, want) {
2322 t.Errorf("%v error = %T: %#v, want %T (%#v)", whence, err, err, want, want)
2323 }
2324 }
2325
2326
2327
2328 func TestTransportGoAwayWithNoConns(t *testing.T) { synctest.Test(t, testTransportGoAwayWithNoConns) }
2329 func testTransportGoAwayWithNoConns(t *testing.T) {
2330 tt := newTestTransportWithUnusedConn(t)
2331 tc := tt.getConn()
2332 tc.greet()
2333 tc.writeGoAway(1, ErrCodeNo, nil)
2334 tc.wantClosed()
2335 }
2336
2337 func testTransportReturnsUnusedFlowControl(t *testing.T, oneDataFrame bool) {
2338 tc := newTestClientConn(t)
2339 tc.greet()
2340
2341 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2342 rt := tc.roundTrip(req)
2343
2344 tc.wantFrameType(FrameHeaders)
2345 tc.writeHeaders(HeadersFrameParam{
2346 StreamID: rt.streamID(),
2347 EndHeaders: true,
2348 EndStream: false,
2349 BlockFragment: tc.makeHeaderBlockFragment(
2350 ":status", "200",
2351 "content-length", "5000",
2352 ),
2353 })
2354 initialInflow := tc.inflowWindow(0)
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366 const streamNotEnded = false
2367 if oneDataFrame {
2368 tc.writeData(rt.streamID(), streamNotEnded, make([]byte, 5000))
2369 } else {
2370 tc.writeData(rt.streamID(), streamNotEnded, make([]byte, 1))
2371 }
2372
2373 res := rt.response()
2374 if n, err := res.Body.Read(make([]byte, 1)); err != nil || n != 1 {
2375 t.Fatalf("body read = %v, %v; want 1, nil", n, err)
2376 }
2377 res.Body.Close()
2378 synctest.Wait()
2379
2380 sentAdditionalData := false
2381 tc.wantUnorderedFrames(
2382 func(f *RSTStreamFrame) bool {
2383 if f.ErrCode != ErrCodeCancel {
2384 t.Fatalf("Expected a RSTStreamFrame with code cancel; got %v", SummarizeFrame(f))
2385 }
2386 if !oneDataFrame {
2387
2388 tc.writeData(rt.streamID(), streamNotEnded, make([]byte, 4999))
2389 sentAdditionalData = true
2390 }
2391 return true
2392 },
2393 func(f *WindowUpdateFrame) bool {
2394 if !oneDataFrame && !sentAdditionalData {
2395 t.Fatalf("Got WindowUpdateFrame, don't expect one yet")
2396 }
2397 if f.Increment != 5000 {
2398 t.Fatalf("Expected WindowUpdateFrames for 5000 bytes; got %v", SummarizeFrame(f))
2399 }
2400 return true
2401 },
2402 )
2403
2404 if got, want := tc.inflowWindow(0), initialInflow; got != want {
2405 t.Fatalf("connection flow tokens = %v, want %v", got, want)
2406 }
2407 }
2408
2409
2410 func TestTransportReturnsUnusedFlowControlSingleWrite(t *testing.T) {
2411 synctest.Test(t, func(t *testing.T) {
2412 testTransportReturnsUnusedFlowControl(t, true)
2413 })
2414 }
2415
2416
2417 func TestTransportReturnsUnusedFlowControlMultipleWrites(t *testing.T) {
2418 synctest.Test(t, func(t *testing.T) {
2419 testTransportReturnsUnusedFlowControl(t, false)
2420 })
2421 }
2422
2423
2424
2425 func TestTransportAdjustsFlowControl(t *testing.T) { synctest.Test(t, testTransportAdjustsFlowControl) }
2426 func testTransportAdjustsFlowControl(t *testing.T) {
2427 const bodySize = 1 << 20
2428
2429 tc := newTestClientConn(t)
2430 tc.wantFrameType(FrameSettings)
2431 tc.wantFrameType(FrameWindowUpdate)
2432
2433
2434 body := tc.newRequestBody()
2435 body.writeBytes(bodySize)
2436 body.closeWithError(io.EOF)
2437
2438 req, _ := http.NewRequest("POST", "https://dummy.tld/", body)
2439 rt := tc.roundTrip(req)
2440
2441 tc.wantFrameType(FrameHeaders)
2442
2443 gotBytes := int64(0)
2444 for {
2445 f := readFrame[*DataFrame](t, tc)
2446 gotBytes += int64(len(f.Data()))
2447
2448
2449 if gotBytes >= InitialWindowSize/2 {
2450 break
2451 }
2452 }
2453
2454 tc.writeSettings(Setting{ID: SettingInitialWindowSize, Val: bodySize})
2455 tc.writeWindowUpdate(0, bodySize)
2456 tc.writeSettingsAck()
2457
2458 tc.wantUnorderedFrames(
2459 func(f *SettingsFrame) bool { return true },
2460 func(f *DataFrame) bool {
2461 gotBytes += int64(len(f.Data()))
2462 return f.StreamEnded()
2463 },
2464 )
2465
2466 if gotBytes != bodySize {
2467 t.Fatalf("server received %v bytes of body, want %v", gotBytes, bodySize)
2468 }
2469
2470 tc.writeHeaders(HeadersFrameParam{
2471 StreamID: rt.streamID(),
2472 EndHeaders: true,
2473 EndStream: true,
2474 BlockFragment: tc.makeHeaderBlockFragment(
2475 ":status", "200",
2476 ),
2477 })
2478 rt.wantStatus(200)
2479 }
2480
2481
2482 func TestTransportReturnsDataPaddingFlowControl(t *testing.T) {
2483 synctest.Test(t, testTransportReturnsDataPaddingFlowControl)
2484 }
2485 func testTransportReturnsDataPaddingFlowControl(t *testing.T) {
2486 tc := newTestClientConn(t)
2487 tc.greet()
2488
2489 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2490 rt := tc.roundTrip(req)
2491
2492 tc.wantFrameType(FrameHeaders)
2493 tc.writeHeaders(HeadersFrameParam{
2494 StreamID: rt.streamID(),
2495 EndHeaders: true,
2496 EndStream: false,
2497 BlockFragment: tc.makeHeaderBlockFragment(
2498 ":status", "200",
2499 "content-length", "5000",
2500 ),
2501 })
2502
2503 initialConnWindow := tc.inflowWindow(0)
2504 initialStreamWindow := tc.inflowWindow(rt.streamID())
2505
2506 pad := make([]byte, 5)
2507 tc.writeDataPadded(rt.streamID(), false, make([]byte, 5000), pad)
2508
2509
2510 synctest.Wait()
2511 if got, want := tc.inflowWindow(0), initialConnWindow-5000; got != want {
2512 t.Errorf("conn inflow window = %v, want %v", got, want)
2513 }
2514 if got, want := tc.inflowWindow(rt.streamID()), initialStreamWindow-5000; got != want {
2515 t.Errorf("stream inflow window = %v, want %v", got, want)
2516 }
2517 }
2518
2519
2520
2521 func TestTransportReturnsErrorOnBadResponseHeaders(t *testing.T) {
2522 synctest.Test(t, testTransportReturnsErrorOnBadResponseHeaders)
2523 }
2524 func testTransportReturnsErrorOnBadResponseHeaders(t *testing.T) {
2525 tc := newTestClientConn(t)
2526 tc.greet()
2527
2528 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2529 rt := tc.roundTrip(req)
2530
2531 tc.wantFrameType(FrameHeaders)
2532 tc.writeHeaders(HeadersFrameParam{
2533 StreamID: rt.streamID(),
2534 EndHeaders: true,
2535 EndStream: false,
2536 BlockFragment: tc.makeHeaderBlockFragment(
2537 ":status", "200",
2538 " content-type", "bogus",
2539 ),
2540 })
2541
2542 err := rt.err()
2543 want := StreamError{1, ErrCodeProtocol, HeaderFieldNameError(" content-type")}
2544 if !reflect.DeepEqual(err, want) {
2545 t.Fatalf("RoundTrip error = %#v; want %#v", err, want)
2546 }
2547
2548 fr := readFrame[*RSTStreamFrame](t, tc)
2549 if fr.StreamID != 1 || fr.ErrCode != ErrCodeProtocol {
2550 t.Errorf("Frame = %v; want RST_STREAM for stream 1 with ErrCodeProtocol", SummarizeFrame(fr))
2551 }
2552 }
2553
2554
2555
2556 type byteAndEOFReader byte
2557
2558 func (b byteAndEOFReader) Read(p []byte) (n int, err error) {
2559 if len(p) == 0 {
2560 panic("unexpected useless call")
2561 }
2562 p[0] = byte(b)
2563 return 1, io.EOF
2564 }
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575 func TestTransportBodyDoubleEndStream(t *testing.T) {
2576 synctest.Test(t, testTransportBodyDoubleEndStream)
2577 }
2578 func testTransportBodyDoubleEndStream(t *testing.T) {
2579 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
2580
2581 })
2582
2583 tr := newTransport(t)
2584
2585 for i := range 2 {
2586 req, _ := http.NewRequest("POST", ts.URL, byteAndEOFReader('a'))
2587 req.ContentLength = 1
2588 res, err := tr.RoundTrip(req)
2589 if err != nil {
2590 t.Fatalf("failure on req %d: %v", i+1, err)
2591 }
2592 defer res.Body.Close()
2593 }
2594 }
2595
2596
2597 func TestTransportRequestPathPseudo(t *testing.T) {
2598 type result struct {
2599 path string
2600 err string
2601 }
2602 tests := []struct {
2603 req *http.Request
2604 want result
2605 }{
2606 0: {
2607 req: &http.Request{
2608 Method: "GET",
2609 URL: &url.URL{
2610 Host: "foo.com",
2611 Path: "/foo",
2612 },
2613 },
2614 want: result{path: "/foo"},
2615 },
2616
2617
2618
2619 1: {
2620 req: &http.Request{
2621 Method: "GET",
2622 URL: &url.URL{
2623 Host: "foo.com",
2624 Path: "//foo",
2625 },
2626 },
2627 want: result{path: "//foo"},
2628 },
2629
2630
2631 2: {
2632 req: &http.Request{
2633 Method: "GET",
2634 URL: &url.URL{
2635 Scheme: "https",
2636 Opaque: "//foo.com/path",
2637 Host: "foo.com",
2638 Path: "/ignored",
2639 },
2640 },
2641 want: result{path: "/path"},
2642 },
2643
2644
2645 3: {
2646 req: &http.Request{
2647 Method: "GET",
2648 Host: "bar.com",
2649 URL: &url.URL{
2650 Scheme: "https",
2651 Opaque: "//bar.com/path",
2652 Host: "foo.com",
2653 Path: "/ignored",
2654 },
2655 },
2656 want: result{path: "/path"},
2657 },
2658
2659
2660 4: {
2661 req: &http.Request{
2662 Method: "GET",
2663 URL: &url.URL{
2664 Opaque: "/path",
2665 Host: "foo.com",
2666 Path: "/ignored",
2667 },
2668 },
2669 want: result{path: "/path"},
2670 },
2671
2672
2673 5: {
2674 req: &http.Request{
2675 Method: "GET",
2676 URL: &url.URL{
2677 Scheme: "https",
2678 Opaque: "//unknown_host/path",
2679 Host: "foo.com",
2680 Path: "/ignored",
2681 },
2682 },
2683 want: result{err: `invalid request :path "https://unknown_host/path" from URL.Opaque = "//unknown_host/path"`},
2684 },
2685
2686
2687 6: {
2688 req: &http.Request{
2689 Method: "CONNECT",
2690 URL: &url.URL{
2691 Host: "foo.com",
2692 },
2693 },
2694 want: result{},
2695 },
2696 }
2697 for i, tt := range tests {
2698 hbuf := &bytes.Buffer{}
2699 henc := hpack.NewEncoder(hbuf)
2700 _, err := httpcommon.EncodeHeaders(context.Background(), httpcommon.EncodeHeadersParam{
2701 Request: httpcommon.Request{
2702 Header: tt.req.Header,
2703 Trailer: tt.req.Trailer,
2704 URL: tt.req.URL,
2705 Host: tt.req.Host,
2706 Method: tt.req.Method,
2707 ActualContentLength: tt.req.ContentLength,
2708 },
2709 AddGzipHeader: false,
2710 PeerMaxHeaderListSize: 0xffffffffffffffff,
2711 }, func(name, value string) {
2712 henc.WriteField(hpack.HeaderField{Name: name, Value: value})
2713 })
2714 hdrs := hbuf.Bytes()
2715 var got result
2716 hpackDec := hpack.NewDecoder(InitialHeaderTableSize, func(f hpack.HeaderField) {
2717 if f.Name == ":path" {
2718 got.path = f.Value
2719 }
2720 })
2721 if err != nil {
2722 got.err = err.Error()
2723 } else if len(hdrs) > 0 {
2724 if _, err := hpackDec.Write(hdrs); err != nil {
2725 t.Errorf("%d. bogus hpack: %v", i, err)
2726 continue
2727 }
2728 }
2729 if got != tt.want {
2730 t.Errorf("%d. got %+v; want %+v", i, got, tt.want)
2731 }
2732
2733 }
2734
2735 }
2736
2737
2738
2739 func TestRoundTripDoesntConsumeRequestBodyEarly(t *testing.T) {
2740 synctest.Test(t, testRoundTripDoesntConsumeRequestBodyEarly)
2741 }
2742 func testRoundTripDoesntConsumeRequestBodyEarly(t *testing.T) {
2743 tc := newTestClientConn(t)
2744 tc.greet()
2745 tc.closeWrite()
2746 synctest.Wait()
2747
2748 const body = "foo"
2749 req, _ := http.NewRequest("POST", "http://foo.com/", io.NopCloser(strings.NewReader(body)))
2750 rt := tc.roundTrip(req)
2751 if err := rt.err(); err != ErrClientConnNotEstablished {
2752 t.Fatalf("RoundTrip = %v; want errClientConnNotEstablished", err)
2753 }
2754
2755 slurp, err := io.ReadAll(req.Body)
2756 if err != nil {
2757 t.Errorf("ReadAll = %v", err)
2758 }
2759 if string(slurp) != body {
2760 t.Errorf("Body = %q; want %q", slurp, body)
2761 }
2762 }
2763
2764
2765
2766
2767
2768 func TestTransportCancelDataResponseRace(t *testing.T) {
2769 cancel := make(chan struct{})
2770 clientGotResponse := make(chan bool, 1)
2771
2772 const msg = "Hello."
2773 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
2774 if strings.Contains(r.URL.Path, "/hello") {
2775 time.Sleep(50 * time.Millisecond)
2776 io.WriteString(w, msg)
2777 return
2778 }
2779 for i := range 50 {
2780 io.WriteString(w, "Some data.")
2781 w.(http.Flusher).Flush()
2782 if i == 2 {
2783 <-clientGotResponse
2784 close(cancel)
2785 }
2786 time.Sleep(10 * time.Millisecond)
2787 }
2788 })
2789
2790 tr := newTransport(t)
2791
2792 c := &http.Client{Transport: tr}
2793 req, _ := http.NewRequest("GET", ts.URL, nil)
2794 req.Cancel = cancel
2795 res, err := c.Do(req)
2796 clientGotResponse <- true
2797 if err != nil {
2798 t.Fatal(err)
2799 }
2800 if _, err = io.Copy(io.Discard, res.Body); err == nil {
2801 t.Fatal("unexpected success")
2802 }
2803
2804 res, err = c.Get(ts.URL + "/hello")
2805 if err != nil {
2806 t.Fatal(err)
2807 }
2808 slurp, err := io.ReadAll(res.Body)
2809 if err != nil {
2810 t.Fatal(err)
2811 }
2812 if string(slurp) != msg {
2813 t.Errorf("Got = %q; want %q", slurp, msg)
2814 }
2815 }
2816
2817
2818
2819 func TestTransportNoRaceOnRequestObjectAfterRequestComplete(t *testing.T) {
2820 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
2821 w.WriteHeader(200)
2822 io.WriteString(w, "body")
2823 })
2824
2825 tr := newTransport(t)
2826
2827 req, _ := http.NewRequest("GET", ts.URL, nil)
2828 resp, err := tr.RoundTrip(req)
2829 if err != nil {
2830 t.Fatal(err)
2831 }
2832 if _, err = io.Copy(io.Discard, resp.Body); err != nil {
2833 t.Fatalf("error reading response body: %v", err)
2834 }
2835 if err := resp.Body.Close(); err != nil {
2836 t.Fatalf("error closing response body: %v", err)
2837 }
2838
2839
2840 req.Header = http.Header{}
2841 }
2842
2843 func TestTransportCloseAfterLostPing(t *testing.T) { synctest.Test(t, testTransportCloseAfterLostPing) }
2844 func testTransportCloseAfterLostPing(t *testing.T) {
2845 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
2846 h2.PingTimeout = 1 * time.Second
2847 h2.SendPingTimeout = 1 * time.Second
2848 })
2849 tc.greet()
2850
2851 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2852 rt := tc.roundTrip(req)
2853 tc.wantFrameType(FrameHeaders)
2854
2855 time.Sleep(1 * time.Second)
2856 tc.wantFrameType(FramePing)
2857
2858 time.Sleep(1 * time.Second)
2859 err := rt.err()
2860 if err == nil || !strings.Contains(err.Error(), "client connection lost") {
2861 t.Fatalf("expected to get error about \"connection lost\", got %v", err)
2862 }
2863 }
2864
2865 func TestTransportPingWriteBlocks(t *testing.T) {
2866 ts := newTestServer(t,
2867 func(w http.ResponseWriter, r *http.Request) {},
2868 )
2869 tr := newTransport(t)
2870 tr.Dial = func(network, addr string) (net.Conn, error) {
2871 s, c := net.Pipe()
2872 go func() {
2873 srv := tls.Server(s, tlsConfigInsecure)
2874 srv.Handshake()
2875
2876
2877
2878
2879 var buf [1024]byte
2880 s.Read(buf[:])
2881 }()
2882 return c, nil
2883 }
2884 tr.HTTP2.PingTimeout = 1 * time.Millisecond
2885 tr.HTTP2.SendPingTimeout = 1 * time.Millisecond
2886 c := &http.Client{Transport: tr}
2887 _, err := c.Get(ts.URL)
2888 if err == nil {
2889 t.Fatalf("Get = nil, want error")
2890 }
2891 }
2892
2893 func TestTransportPingWhenReadingMultiplePings(t *testing.T) {
2894 synctest.Test(t, testTransportPingWhenReadingMultiplePings)
2895 }
2896 func testTransportPingWhenReadingMultiplePings(t *testing.T) {
2897 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
2898 h2.SendPingTimeout = 1000 * time.Millisecond
2899 })
2900 tc.greet()
2901
2902 ctx, cancel := context.WithCancel(context.Background())
2903 req, _ := http.NewRequestWithContext(ctx, "GET", "https://dummy.tld/", nil)
2904 rt := tc.roundTrip(req)
2905
2906 tc.wantFrameType(FrameHeaders)
2907 tc.writeHeaders(HeadersFrameParam{
2908 StreamID: rt.streamID(),
2909 EndHeaders: true,
2910 EndStream: false,
2911 BlockFragment: tc.makeHeaderBlockFragment(
2912 ":status", "200",
2913 ),
2914 })
2915
2916 for range 5 {
2917
2918 time.Sleep(999 * time.Millisecond)
2919 if f := tc.readFrame(); f != nil {
2920 t.Fatalf("unexpected frame: %v", f)
2921 }
2922
2923
2924 time.Sleep(1 * time.Millisecond)
2925 f := readFrame[*PingFrame](t, tc)
2926 tc.writePing(true, f.Data)
2927 }
2928
2929
2930 cancel()
2931 synctest.Wait()
2932
2933 tc.wantFrameType(FrameRSTStream)
2934 _, err := rt.readBody()
2935 if err == nil {
2936 t.Fatalf("Response.Body.Read() = %v, want error", err)
2937 }
2938 }
2939
2940 func TestTransportPingWhenReadingPingDisabled(t *testing.T) {
2941 synctest.Test(t, testTransportPingWhenReadingPingDisabled)
2942 }
2943 func testTransportPingWhenReadingPingDisabled(t *testing.T) {
2944 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
2945 h2.SendPingTimeout = 0
2946 })
2947 tc.greet()
2948
2949 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2950 rt := tc.roundTrip(req)
2951
2952 tc.wantFrameType(FrameHeaders)
2953 tc.writeHeaders(HeadersFrameParam{
2954 StreamID: rt.streamID(),
2955 EndHeaders: true,
2956 EndStream: false,
2957 BlockFragment: tc.makeHeaderBlockFragment(
2958 ":status", "200",
2959 ),
2960 })
2961
2962
2963 time.Sleep(1 * time.Minute)
2964 if f := tc.readFrame(); f != nil {
2965 t.Fatalf("unexpected frame: %v", f)
2966 }
2967 }
2968
2969 func TestTransportRetryAfterGOAWAYNoRetry(t *testing.T) {
2970 synctest.Test(t, testTransportRetryAfterGOAWAYNoRetry)
2971 }
2972 func testTransportRetryAfterGOAWAYNoRetry(t *testing.T) {
2973 tt := newTestTransport(t)
2974
2975 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
2976 rt := tt.roundTrip(req)
2977
2978
2979
2980
2981
2982 tc := tt.getConn()
2983 tc.wantFrameType(FrameSettings)
2984 tc.wantFrameType(FrameWindowUpdate)
2985 tc.wantHeaders(wantHeader{
2986 streamID: 1,
2987 endStream: true,
2988 })
2989 tc.writeSettings()
2990 tc.writeGoAway(0 , ErrCodeInternal, nil)
2991 if rt.err() == nil {
2992 t.Fatalf("after GOAWAY, RoundTrip is not done, want error")
2993 }
2994 }
2995
2996 func TestTransportRetryAfterGOAWAYRetry(t *testing.T) {
2997 synctest.Test(t, testTransportRetryAfterGOAWAYRetry)
2998 }
2999 func testTransportRetryAfterGOAWAYRetry(t *testing.T) {
3000 tt := newTestTransport(t)
3001
3002 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3003 rt := tt.roundTrip(req)
3004
3005
3006
3007
3008
3009 tc := tt.getConn()
3010 tc.wantFrameType(FrameSettings)
3011 tc.wantFrameType(FrameWindowUpdate)
3012 tc.wantHeaders(wantHeader{
3013 streamID: 1,
3014 endStream: true,
3015 })
3016 tc.writeSettings()
3017 tc.writeGoAway(0 , ErrCodeNo, nil)
3018 if rt.done() {
3019 t.Fatalf("after GOAWAY, RoundTrip is done; want it to be retrying")
3020 }
3021
3022
3023 tc = tt.getConn()
3024 tc.wantFrameType(FrameSettings)
3025 tc.wantFrameType(FrameWindowUpdate)
3026 tc.wantHeaders(wantHeader{
3027 streamID: 1,
3028 endStream: true,
3029 })
3030 tc.writeSettings()
3031 tc.writeHeaders(HeadersFrameParam{
3032 StreamID: 1,
3033 EndHeaders: true,
3034 EndStream: true,
3035 BlockFragment: tc.makeHeaderBlockFragment(
3036 ":status", "200",
3037 ),
3038 })
3039
3040 rt.wantStatus(200)
3041 }
3042
3043 func TestTransportRetryAfterGOAWAYSecondRequest(t *testing.T) {
3044 synctest.Test(t, testTransportRetryAfterGOAWAYSecondRequest)
3045 }
3046 func testTransportRetryAfterGOAWAYSecondRequest(t *testing.T) {
3047 tt := newTestTransport(t)
3048
3049
3050 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3051 rt1 := tt.roundTrip(req)
3052 tc := tt.getConn()
3053 tc.wantFrameType(FrameSettings)
3054 tc.wantFrameType(FrameWindowUpdate)
3055 tc.wantHeaders(wantHeader{
3056 streamID: 1,
3057 endStream: true,
3058 })
3059 tc.writeSettings()
3060 tc.wantFrameType(FrameSettings)
3061 tc.writeHeaders(HeadersFrameParam{
3062 StreamID: 1,
3063 EndHeaders: true,
3064 EndStream: true,
3065 BlockFragment: tc.makeHeaderBlockFragment(
3066 ":status", "200",
3067 ),
3068 })
3069 rt1.wantStatus(200)
3070
3071
3072
3073
3074
3075 req, _ = http.NewRequest("GET", "https://dummy.tld/", nil)
3076 rt2 := tt.roundTrip(req)
3077
3078
3079 tc.wantHeaders(wantHeader{
3080 streamID: 3,
3081 endStream: true,
3082 })
3083 tc.writeSettings()
3084 tc.writeGoAway(1 , ErrCodeProtocol, nil)
3085 if rt2.done() {
3086 t.Fatalf("after GOAWAY, RoundTrip is done; want it to be retrying")
3087 }
3088
3089
3090 tc = tt.getConn()
3091 tc.wantFrameType(FrameSettings)
3092 tc.wantFrameType(FrameWindowUpdate)
3093 tc.wantHeaders(wantHeader{
3094 streamID: 1,
3095 endStream: true,
3096 })
3097 tc.writeSettings()
3098 tc.writeHeaders(HeadersFrameParam{
3099 StreamID: 1,
3100 EndHeaders: true,
3101 EndStream: true,
3102 BlockFragment: tc.makeHeaderBlockFragment(
3103 ":status", "200",
3104 ),
3105 })
3106 rt2.wantStatus(200)
3107 }
3108
3109 func TestTransportRetryAfterRefusedStream(t *testing.T) {
3110 synctest.Test(t, testTransportRetryAfterRefusedStream)
3111 }
3112 func testTransportRetryAfterRefusedStream(t *testing.T) {
3113 tt := newTestTransport(t)
3114
3115 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3116 rt := tt.roundTrip(req)
3117
3118
3119 tc := tt.getConn()
3120 tc.wantFrameType(FrameSettings)
3121 tc.wantFrameType(FrameWindowUpdate)
3122 tc.wantHeaders(wantHeader{
3123 streamID: 1,
3124 endStream: true,
3125 })
3126 tc.writeSettings()
3127 tc.wantFrameType(FrameSettings)
3128 tc.writeRSTStream(1, ErrCodeRefusedStream)
3129 if rt.done() {
3130 t.Fatalf("after RST_STREAM, RoundTrip is done; want it to be retrying")
3131 }
3132
3133
3134 tc.wantHeaders(wantHeader{
3135 streamID: 3,
3136 endStream: true,
3137 })
3138 tc.writeSettings()
3139 tc.writeHeaders(HeadersFrameParam{
3140 StreamID: 3,
3141 EndHeaders: true,
3142 EndStream: true,
3143 BlockFragment: tc.makeHeaderBlockFragment(
3144 ":status", "204",
3145 ),
3146 })
3147
3148 rt.wantStatus(204)
3149 }
3150
3151 func TestTransportRetryHasLimit(t *testing.T) { synctest.Test(t, testTransportRetryHasLimit) }
3152 func testTransportRetryHasLimit(t *testing.T) {
3153 tt := newTestTransport(t)
3154
3155 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3156 rt := tt.roundTrip(req)
3157
3158 tc := tt.getConn()
3159 tc.netconn.SetReadDeadline(time.Time{})
3160 tc.wantFrameType(FrameSettings)
3161 tc.wantFrameType(FrameWindowUpdate)
3162
3163 count := 0
3164 start := time.Now()
3165 for streamID := uint32(1); !rt.done(); streamID += 2 {
3166 count++
3167 tc.wantHeaders(wantHeader{
3168 streamID: streamID,
3169 endStream: true,
3170 })
3171 if streamID == 1 {
3172 tc.writeSettings()
3173 tc.wantFrameType(FrameSettings)
3174 }
3175 tc.writeRSTStream(streamID, ErrCodeRefusedStream)
3176
3177 if totalDelay := time.Since(start); totalDelay > 5*time.Minute {
3178 t.Fatalf("RoundTrip still retrying after %v, should have given up", totalDelay)
3179 }
3180 synctest.Wait()
3181 }
3182 if got, want := count, 5; got < count {
3183 t.Errorf("RoundTrip made %v attempts, want at least %v", got, want)
3184 }
3185 if rt.err() == nil {
3186 t.Errorf("RoundTrip succeeded, want error")
3187 }
3188 }
3189
3190 func TestTransportResponseDataBeforeHeaders(t *testing.T) {
3191 synctest.Test(t, testTransportResponseDataBeforeHeaders)
3192 }
3193 func testTransportResponseDataBeforeHeaders(t *testing.T) {
3194
3195 log.SetOutput(io.Discard)
3196 t.Cleanup(func() { log.SetOutput(os.Stderr) })
3197
3198 tc := newTestClientConn(t)
3199 tc.greet()
3200
3201
3202 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3203 rt1 := tc.roundTrip(req)
3204 tc.wantFrameType(FrameHeaders)
3205 tc.writeHeaders(HeadersFrameParam{
3206 StreamID: rt1.streamID(),
3207 EndHeaders: true,
3208 EndStream: true,
3209 BlockFragment: tc.makeHeaderBlockFragment(
3210 ":status", "200",
3211 ),
3212 })
3213 rt1.wantStatus(200)
3214
3215
3216 rt2 := tc.roundTrip(req)
3217 tc.wantFrameType(FrameHeaders)
3218 tc.writeData(rt2.streamID(), true, []byte("payload"))
3219 if err, ok := rt2.err().(StreamError); !ok || err.Code != ErrCodeProtocol {
3220 t.Fatalf("expected stream PROTOCOL_ERROR, got: %v", err)
3221 }
3222 }
3223
3224 func TestTransportMaxFrameReadSize(t *testing.T) {
3225 for _, test := range []struct {
3226 maxReadFrameSize uint32
3227 want uint32
3228 }{{
3229 maxReadFrameSize: 64000,
3230 want: 64000,
3231 }, {
3232 maxReadFrameSize: 1024,
3233
3234
3235
3236
3237
3238
3239
3240
3241 want: DefaultMaxReadFrameSize,
3242 }} {
3243 synctestSubtest(t, fmt.Sprint(test.maxReadFrameSize), func(t *testing.T) {
3244 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
3245 h2.MaxReadFrameSize = int(test.maxReadFrameSize)
3246 })
3247
3248 fr := readFrame[*SettingsFrame](t, tc)
3249 got, ok := fr.Value(SettingMaxFrameSize)
3250 if !ok {
3251 t.Errorf("Transport.MaxReadFrameSize = %v; server got no setting, want %v", test.maxReadFrameSize, test.want)
3252 } else if got != test.want {
3253 t.Errorf("Transport.MaxReadFrameSize = %v; server got %v, want %v", test.maxReadFrameSize, got, test.want)
3254 }
3255 })
3256 }
3257 }
3258
3259 func TestTransportRequestsLowServerLimit(t *testing.T) {
3260 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
3261 }, func(h2 *http.HTTP2Config) {
3262 h2.MaxConcurrentStreams = 1
3263 })
3264
3265 var (
3266 connCountMu sync.Mutex
3267 connCount int
3268 )
3269 tr := newTransport(t)
3270 tr.DialTLS = func(network, addr string) (net.Conn, error) {
3271 connCountMu.Lock()
3272 defer connCountMu.Unlock()
3273 connCount++
3274 return tls.Dial(network, addr, tlsConfigInsecure)
3275 }
3276
3277 const reqCount = 3
3278 for range reqCount {
3279 req, err := http.NewRequest("GET", ts.URL, nil)
3280 if err != nil {
3281 t.Fatal(err)
3282 }
3283 res, err := tr.RoundTrip(req)
3284 if err != nil {
3285 t.Fatal(err)
3286 }
3287 if got, want := res.StatusCode, 200; got != want {
3288 t.Errorf("StatusCode = %v; want %v", got, want)
3289 }
3290 if res != nil && res.Body != nil {
3291 res.Body.Close()
3292 }
3293 }
3294
3295 if connCount != 1 {
3296 t.Errorf("created %v connections for %v requests, want 1", connCount, reqCount)
3297 }
3298 }
3299
3300
3301 func TestTransportRequestsStallAtServerLimit(t *testing.T) {
3302 synctest.Test(t, testTransportRequestsStallAtServerLimit)
3303 }
3304 func testTransportRequestsStallAtServerLimit(t *testing.T) {
3305 const maxConcurrent = 2
3306
3307 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
3308 h2.StrictMaxConcurrentRequests = true
3309 })
3310 tc.greet(Setting{SettingMaxConcurrentStreams, maxConcurrent})
3311
3312 cancelClientRequest := make(chan struct{})
3313
3314
3315
3316 var rts []*testRoundTrip
3317 for k := range maxConcurrent + 2 {
3318 req, _ := http.NewRequest("GET", fmt.Sprintf("https://dummy.tld/%d", k), nil)
3319 if k == maxConcurrent {
3320 req.Cancel = cancelClientRequest
3321 }
3322 rt := tc.roundTrip(req)
3323 rts = append(rts, rt)
3324
3325 if k < maxConcurrent {
3326
3327 tc.wantHeaders(wantHeader{
3328 streamID: rt.streamID(),
3329 endStream: true,
3330 header: http.Header{
3331 ":authority": []string{"dummy.tld"},
3332 ":method": []string{"GET"},
3333 ":path": []string{fmt.Sprintf("/%d", k)},
3334 },
3335 })
3336 } else {
3337
3338
3339 if fr := tc.readFrame(); fr != nil {
3340 t.Fatalf("after making new request while at stream limit, got unexpected frame: %v", fr)
3341 }
3342 }
3343
3344 if rt.done() {
3345 t.Fatalf("rt %v done", k)
3346 }
3347 }
3348
3349
3350
3351 close(cancelClientRequest)
3352 synctest.Wait()
3353 if err := rts[maxConcurrent].err(); err == nil {
3354 t.Fatalf("RoundTrip(%d) should have failed due to cancel, did not", maxConcurrent)
3355 }
3356
3357
3358 for i, rt := range rts {
3359 if i != maxConcurrent && rt.done() {
3360 t.Fatalf("RoundTrip(%d) is done, but should not be", i)
3361 }
3362 }
3363
3364
3365 tc.writeHeaders(HeadersFrameParam{
3366 StreamID: rts[0].streamID(),
3367 EndHeaders: true,
3368 EndStream: true,
3369 BlockFragment: tc.makeHeaderBlockFragment(
3370 ":status", "200",
3371 ),
3372 })
3373 synctest.Wait()
3374 tc.wantHeaders(wantHeader{
3375 streamID: rts[maxConcurrent+1].streamID(),
3376 endStream: true,
3377 header: http.Header{
3378 ":authority": []string{"dummy.tld"},
3379 ":method": []string{"GET"},
3380 ":path": []string{fmt.Sprintf("/%d", maxConcurrent+1)},
3381 },
3382 })
3383 rts[0].wantStatus(200)
3384 }
3385
3386 func TestTransportMaxDecoderHeaderTableSize(t *testing.T) {
3387 synctest.Test(t, testTransportMaxDecoderHeaderTableSize)
3388 }
3389 func testTransportMaxDecoderHeaderTableSize(t *testing.T) {
3390 var reqSize, resSize uint32 = 8192, 16384
3391 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
3392 h2.MaxDecoderHeaderTableSize = int(reqSize)
3393 })
3394
3395 fr := readFrame[*SettingsFrame](t, tc)
3396 if v, ok := fr.Value(SettingHeaderTableSize); !ok {
3397 t.Fatalf("missing SETTINGS_HEADER_TABLE_SIZE setting")
3398 } else if v != reqSize {
3399 t.Fatalf("received SETTINGS_HEADER_TABLE_SIZE = %d, want %d", v, reqSize)
3400 }
3401
3402 tc.writeSettings(Setting{SettingHeaderTableSize, resSize})
3403 synctest.Wait()
3404 if got, want := tc.cc.TestPeerMaxHeaderTableSize(), resSize; got != want {
3405 t.Fatalf("peerHeaderTableSize = %d, want %d", got, want)
3406 }
3407 }
3408
3409 func TestTransportMaxEncoderHeaderTableSize(t *testing.T) {
3410 synctest.Test(t, testTransportMaxEncoderHeaderTableSize)
3411 }
3412 func testTransportMaxEncoderHeaderTableSize(t *testing.T) {
3413 var peerAdvertisedMaxHeaderTableSize uint32 = 16384
3414 const wantMaxEncoderHeaderTableSize = 8192
3415 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
3416 h2.MaxEncoderHeaderTableSize = wantMaxEncoderHeaderTableSize
3417 })
3418 tc.greet(Setting{SettingHeaderTableSize, peerAdvertisedMaxHeaderTableSize})
3419
3420 if got, want := tc.cc.TestHPACKEncoder().MaxDynamicTableSize(), uint32(wantMaxEncoderHeaderTableSize); got != want {
3421 t.Fatalf("henc.MaxDynamicTableSize() = %d, want %d", got, want)
3422 }
3423 }
3424
3425
3426
3427 func TestTransportAllocationsAfterResponseBodyClose(t *testing.T) {
3428 synctest.Test(t, testTransportAllocationsAfterResponseBodyClose)
3429 }
3430 func testTransportAllocationsAfterResponseBodyClose(t *testing.T) {
3431 tc := newTestClientConn(t)
3432 tc.greet()
3433
3434
3435 req, _ := http.NewRequest("PUT", "https://dummy.tld/", nil)
3436 rt := tc.roundTrip(req)
3437 tc.wantFrameType(FrameHeaders)
3438
3439
3440 tc.writeHeaders(HeadersFrameParam{
3441 StreamID: rt.streamID(),
3442 EndHeaders: true,
3443 EndStream: false,
3444 BlockFragment: tc.makeHeaderBlockFragment(
3445 ":status", "200",
3446 ),
3447 })
3448 tc.writeData(rt.streamID(), false, make([]byte, 64))
3449 tc.wantIdle()
3450
3451
3452 respBody := rt.response().Body
3453 var buf [1]byte
3454 if _, err := respBody.Read(buf[:]); err != nil {
3455 t.Error(err)
3456 }
3457 if err := respBody.Close(); err != nil {
3458 t.Error(err)
3459 }
3460 tc.wantFrameType(FrameRSTStream)
3461
3462
3463 tc.writeData(rt.streamID(), false, make([]byte, 64))
3464
3465 if _, err := respBody.Read(buf[:]); err == nil {
3466 t.Error("read from closed body unexpectedly succeeded")
3467 }
3468 }
3469
3470
3471
3472 func TestTransportNoBodyMeansNoDATA(t *testing.T) { synctest.Test(t, testTransportNoBodyMeansNoDATA) }
3473 func testTransportNoBodyMeansNoDATA(t *testing.T) {
3474 tc := newTestClientConn(t)
3475 tc.greet()
3476
3477 req, _ := http.NewRequest("GET", "https://dummy.tld/", http.NoBody)
3478 rt := tc.roundTrip(req)
3479
3480 tc.wantHeaders(wantHeader{
3481 streamID: rt.streamID(),
3482 endStream: true,
3483 header: http.Header{
3484 ":authority": []string{"dummy.tld"},
3485 ":method": []string{"GET"},
3486 ":path": []string{"/"},
3487 },
3488 })
3489 if fr := tc.readFrame(); fr != nil {
3490 t.Fatalf("unexpected frame after headers: %v", fr)
3491 }
3492 }
3493
3494 func benchSimpleRoundTrip(b *testing.B, nReqHeaders, nResHeader int) {
3495 DisableGoroutineTracking(b)
3496 b.ReportAllocs()
3497 ts := newTestServer(b,
3498 func(w http.ResponseWriter, r *http.Request) {
3499 for i := range nResHeader {
3500 name := fmt.Sprint("A-", i)
3501 w.Header().Set(name, "*")
3502 }
3503 },
3504 optQuiet,
3505 )
3506
3507
3508
3509
3510 ts.Config.MaxHeaderValueCount = 30 + nReqHeaders
3511
3512 tr := newTransport(b)
3513
3514 req, err := http.NewRequest("GET", ts.URL, nil)
3515 if err != nil {
3516 b.Fatal(err)
3517 }
3518
3519 for i := range nReqHeaders {
3520 name := fmt.Sprint("A-", i)
3521 req.Header.Set(name, "*")
3522 }
3523
3524 b.ResetTimer()
3525
3526 for i := 0; i < b.N; i++ {
3527 res, err := tr.RoundTrip(req)
3528 if err != nil {
3529 if res != nil {
3530 res.Body.Close()
3531 }
3532 b.Fatalf("RoundTrip err = %v; want nil", err)
3533 }
3534 res.Body.Close()
3535 if res.StatusCode != http.StatusOK {
3536 b.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK)
3537 }
3538 }
3539 }
3540
3541 type infiniteReader struct{}
3542
3543 func (r infiniteReader) Read(b []byte) (int, error) {
3544 return len(b), nil
3545 }
3546
3547
3548
3549 func TestTransportResponseAndResetWithoutConsumingBodyRace(t *testing.T) {
3550 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
3551 w.WriteHeader(http.StatusOK)
3552 })
3553
3554 tr := newTransport(t)
3555
3556
3557 req, _ := http.NewRequest("PUT", ts.URL, infiniteReader{})
3558 res, err := tr.RoundTrip(req)
3559 if err != nil {
3560 t.Fatal(err)
3561 }
3562 if res.StatusCode != http.StatusOK {
3563 t.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK)
3564 }
3565 }
3566
3567
3568
3569 func TestTransportHandlesInvalidStatuslessResponse(t *testing.T) {
3570 synctest.Test(t, testTransportHandlesInvalidStatuslessResponse)
3571 }
3572 func testTransportHandlesInvalidStatuslessResponse(t *testing.T) {
3573 tc := newTestClientConn(t)
3574 tc.greet()
3575
3576 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3577 rt := tc.roundTrip(req)
3578
3579 tc.wantFrameType(FrameHeaders)
3580 tc.writeHeaders(HeadersFrameParam{
3581 StreamID: rt.streamID(),
3582 EndHeaders: true,
3583 EndStream: false,
3584 BlockFragment: tc.makeHeaderBlockFragment(
3585 "content-type", "text/html",
3586 ),
3587 })
3588 tc.writeData(rt.streamID(), true, []byte("payload"))
3589 }
3590
3591 func BenchmarkClientRequestHeaders(b *testing.B) {
3592 b.Run(" 0 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0, 0) })
3593 b.Run(" 10 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 10, 0) })
3594 b.Run(" 100 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 100, 0) })
3595 b.Run("1000 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 1000, 0) })
3596 }
3597
3598 func BenchmarkClientResponseHeaders(b *testing.B) {
3599 b.Run(" 0 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0, 0) })
3600 b.Run(" 10 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0, 10) })
3601 b.Run(" 100 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0, 100) })
3602 b.Run("1000 Headers", func(b *testing.B) { benchSimpleRoundTrip(b, 0, 1000) })
3603 }
3604
3605 func BenchmarkDownloadFrameSize(b *testing.B) {
3606 b.Run(" 16k Frame", func(b *testing.B) { benchLargeDownloadRoundTrip(b, 16*1024) })
3607 b.Run(" 64k Frame", func(b *testing.B) { benchLargeDownloadRoundTrip(b, 64*1024) })
3608 b.Run("128k Frame", func(b *testing.B) { benchLargeDownloadRoundTrip(b, 128*1024) })
3609 b.Run("256k Frame", func(b *testing.B) { benchLargeDownloadRoundTrip(b, 256*1024) })
3610 b.Run("512k Frame", func(b *testing.B) { benchLargeDownloadRoundTrip(b, 512*1024) })
3611 }
3612 func benchLargeDownloadRoundTrip(b *testing.B, frameSize uint32) {
3613 DisableGoroutineTracking(b)
3614 const transferSize = 1024 * 1024 * 1024
3615 b.ReportAllocs()
3616 ts := newTestServer(b,
3617 func(w http.ResponseWriter, r *http.Request) {
3618
3619 w.Header().Set("Content-Length", strconv.Itoa(transferSize))
3620 w.Header().Set("Content-Transfer-Encoding", "binary")
3621 var data [1024 * 1024]byte
3622 for range transferSize / (1024 * 1024) {
3623 w.Write(data[:])
3624 }
3625 }, optQuiet,
3626 )
3627
3628 tr := newTransport(b)
3629 tr.HTTP2.MaxReadFrameSize = int(frameSize)
3630
3631 req, err := http.NewRequest("GET", ts.URL, nil)
3632 if err != nil {
3633 b.Fatal(err)
3634 }
3635
3636 b.N = 3
3637 b.SetBytes(transferSize)
3638 b.ResetTimer()
3639
3640 for i := 0; i < b.N; i++ {
3641 res, err := tr.RoundTrip(req)
3642 if err != nil {
3643 if res != nil {
3644 res.Body.Close()
3645 }
3646 b.Fatalf("RoundTrip err = %v; want nil", err)
3647 }
3648 data, _ := io.ReadAll(res.Body)
3649 if len(data) != transferSize {
3650 b.Fatalf("Response length invalid")
3651 }
3652 res.Body.Close()
3653 if res.StatusCode != http.StatusOK {
3654 b.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK)
3655 }
3656 }
3657 }
3658
3659 func BenchmarkClientGzip(b *testing.B) {
3660 DisableGoroutineTracking(b)
3661 b.ReportAllocs()
3662
3663 const responseSize = 1024 * 1024
3664
3665 var buf bytes.Buffer
3666 gz := gzip.NewWriter(&buf)
3667 if _, err := io.CopyN(gz, crand.Reader, responseSize); err != nil {
3668 b.Fatal(err)
3669 }
3670 gz.Close()
3671
3672 data := buf.Bytes()
3673 ts := newTestServer(b,
3674 func(w http.ResponseWriter, r *http.Request) {
3675 w.Header().Set("Content-Encoding", "gzip")
3676 w.Write(data)
3677 },
3678 optQuiet,
3679 )
3680
3681 tr := newTransport(b)
3682
3683 req, err := http.NewRequest("GET", ts.URL, nil)
3684 if err != nil {
3685 b.Fatal(err)
3686 }
3687
3688 b.ResetTimer()
3689
3690 for i := 0; i < b.N; i++ {
3691 res, err := tr.RoundTrip(req)
3692 if err != nil {
3693 b.Fatalf("RoundTrip err = %v; want nil", err)
3694 }
3695 if res.StatusCode != http.StatusOK {
3696 b.Fatalf("Response code = %v; want %v", res.StatusCode, http.StatusOK)
3697 }
3698 n, err := io.Copy(io.Discard, res.Body)
3699 res.Body.Close()
3700 if err != nil {
3701 b.Fatalf("RoundTrip err = %v; want nil", err)
3702 }
3703 if n != responseSize {
3704 b.Fatalf("RoundTrip expected %d bytes, got %d", responseSize, n)
3705 }
3706 }
3707 }
3708
3709
3710
3711
3712 func TestClientConnCloseAtHeaders(t *testing.T) { synctest.Test(t, testClientConnCloseAtHeaders) }
3713 func testClientConnCloseAtHeaders(t *testing.T) {
3714 tc := newTestClientConn(t)
3715 tc.greet()
3716
3717 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3718 rt := tc.roundTrip(req)
3719 tc.wantFrameType(FrameHeaders)
3720
3721 tc.cc.Close()
3722 synctest.Wait()
3723 if err := rt.err(); err != ErrClientConnForceClosed {
3724 t.Fatalf("RoundTrip error = %v, want errClientConnForceClosed", err)
3725 }
3726 }
3727
3728
3729
3730 func TestClientConnCloseAtBody(t *testing.T) { synctest.Test(t, testClientConnCloseAtBody) }
3731 func testClientConnCloseAtBody(t *testing.T) {
3732 tc := newTestClientConn(t)
3733 tc.greet()
3734
3735 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3736 rt := tc.roundTrip(req)
3737 tc.wantFrameType(FrameHeaders)
3738
3739 tc.writeHeaders(HeadersFrameParam{
3740 StreamID: rt.streamID(),
3741 EndHeaders: true,
3742 EndStream: false,
3743 BlockFragment: tc.makeHeaderBlockFragment(
3744 ":status", "200",
3745 ),
3746 })
3747 tc.writeData(rt.streamID(), false, make([]byte, 64))
3748 resp := rt.response()
3749 tc.cc.Close()
3750 synctest.Wait()
3751
3752 if _, err := io.Copy(io.Discard, resp.Body); err == nil {
3753 t.Error("expected a Copy error, got nil")
3754 }
3755 }
3756
3757
3758
3759 func TestClientConnShutdown(t *testing.T) { synctest.Test(t, testClientConnShutdown) }
3760 func testClientConnShutdown(t *testing.T) {
3761 tc := newTestClientConn(t)
3762 tc.greet()
3763
3764 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3765 rt := tc.roundTrip(req)
3766 tc.wantFrameType(FrameHeaders)
3767
3768 go tc.cc.Shutdown(context.Background())
3769 synctest.Wait()
3770
3771 tc.wantFrameType(FrameGoAway)
3772 tc.wantIdle()
3773 body := []byte("body")
3774 tc.writeHeaders(HeadersFrameParam{
3775 StreamID: rt.streamID(),
3776 EndHeaders: true,
3777 EndStream: false,
3778 BlockFragment: tc.makeHeaderBlockFragment(
3779 ":status", "200",
3780 ),
3781 })
3782 tc.writeData(rt.streamID(), true, body)
3783
3784 rt.wantStatus(200)
3785 rt.wantBody(body)
3786
3787
3788 tc.wantClosed()
3789 }
3790
3791
3792
3793
3794 func TestClientConnShutdownCancel(t *testing.T) { synctest.Test(t, testClientConnShutdownCancel) }
3795 func testClientConnShutdownCancel(t *testing.T) {
3796 tc := newTestClientConn(t)
3797 tc.greet()
3798
3799 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3800 rt := tc.roundTrip(req)
3801 tc.wantFrameType(FrameHeaders)
3802
3803 ctx, cancel := context.WithCancel(t.Context())
3804 var shutdownErr error
3805 go func() {
3806 shutdownErr = tc.cc.Shutdown(ctx)
3807 }()
3808 synctest.Wait()
3809
3810 tc.wantFrameType(FrameGoAway)
3811 tc.wantIdle()
3812
3813 cancel()
3814 synctest.Wait()
3815
3816 if shutdownErr != context.Canceled {
3817 t.Fatalf("ClientConn.Shutdown(ctx) did not return context.Canceled after cancelling context")
3818 }
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829 if rt.done() {
3830 t.Fatal("RoundTrip unexpectedly returned during shutdown")
3831 }
3832 }
3833
3834 type errReader struct {
3835 body []byte
3836 err error
3837 }
3838
3839 func (r *errReader) Read(p []byte) (int, error) {
3840 if len(r.body) > 0 {
3841 n := copy(p, r.body)
3842 r.body = r.body[n:]
3843 return n, nil
3844 }
3845 return 0, r.err
3846 }
3847
3848 func testTransportBodyReadError(t *testing.T, body []byte) {
3849 synctest.Test(t, func(t *testing.T) {
3850 testTransportBodyReadErrorBubble(t, body)
3851 })
3852 }
3853 func testTransportBodyReadErrorBubble(t *testing.T, body []byte) {
3854 tc := newTestClientConn(t)
3855 tc.greet()
3856
3857 bodyReadError := errors.New("body read error")
3858 b := tc.newRequestBody()
3859 b.Write(body)
3860 b.closeWithError(bodyReadError)
3861 req, _ := http.NewRequest("PUT", "https://dummy.tld/", b)
3862 rt := tc.roundTrip(req)
3863
3864 tc.wantFrameType(FrameHeaders)
3865 var receivedBody []byte
3866 readFrames:
3867 for {
3868 switch f := tc.readFrame().(type) {
3869 case *DataFrame:
3870 receivedBody = append(receivedBody, f.Data()...)
3871 case *RSTStreamFrame:
3872 break readFrames
3873 default:
3874 t.Fatalf("unexpected frame: %v", f)
3875 case nil:
3876 t.Fatalf("transport is idle, want RST_STREAM")
3877 }
3878 }
3879 if !bytes.Equal(receivedBody, body) {
3880 t.Fatalf("body: %q; expected %q", receivedBody, body)
3881 }
3882
3883 if err := rt.err(); err != bodyReadError {
3884 t.Fatalf("err = %v; want %v", err, bodyReadError)
3885 }
3886 }
3887
3888 func TestTransportBodyReadError_Immediately(t *testing.T) { testTransportBodyReadError(t, nil) }
3889 func TestTransportBodyReadError_Some(t *testing.T) { testTransportBodyReadError(t, []byte("123")) }
3890
3891
3892
3893
3894 func TestTransportBodyEagerEndStream(t *testing.T) { synctest.Test(t, testTransportBodyEagerEndStream) }
3895 func testTransportBodyEagerEndStream(t *testing.T) {
3896 const reqBody = "some request body"
3897 const resBody = "some response body"
3898
3899 tc := newTestClientConn(t)
3900 tc.greet()
3901
3902 body := strings.NewReader(reqBody)
3903 req, _ := http.NewRequest("PUT", "https://dummy.tld/", body)
3904 tc.roundTrip(req)
3905
3906 tc.wantFrameType(FrameHeaders)
3907 f := readFrame[*DataFrame](t, tc)
3908 if !f.StreamEnded() {
3909 t.Fatalf("data frame without END_STREAM %v", f)
3910 }
3911 }
3912
3913 type chunkReader struct {
3914 chunks [][]byte
3915 }
3916
3917 func (r *chunkReader) Read(p []byte) (int, error) {
3918 if len(r.chunks) > 0 {
3919 n := copy(p, r.chunks[0])
3920 r.chunks = r.chunks[1:]
3921 return n, nil
3922 }
3923 panic("shouldn't read this many times")
3924 }
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934 func TestTransportBodyLargerThanSpecifiedContentLength_len3(t *testing.T) {
3935 body := &chunkReader{[][]byte{
3936 []byte("123"),
3937 []byte("456"),
3938 }}
3939 synctest.Test(t, func(t *testing.T) {
3940 testTransportBodyLargerThanSpecifiedContentLength(t, body, 3)
3941 })
3942 }
3943
3944 func TestTransportBodyLargerThanSpecifiedContentLength_len2(t *testing.T) {
3945 body := &chunkReader{[][]byte{
3946 []byte("123"),
3947 }}
3948 synctest.Test(t, func(t *testing.T) {
3949 testTransportBodyLargerThanSpecifiedContentLength(t, body, 2)
3950 })
3951 }
3952
3953 func testTransportBodyLargerThanSpecifiedContentLength(t *testing.T, body *chunkReader, contentLen int64) {
3954 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
3955 r.Body.Read(make([]byte, 6))
3956 })
3957
3958 tr := newTransport(t)
3959
3960 req, _ := http.NewRequest("POST", ts.URL, body)
3961 req.ContentLength = contentLen
3962 _, err := tr.RoundTrip(req)
3963 if err != ErrReqBodyTooLong {
3964 t.Fatalf("expected %v, got %v", ErrReqBodyTooLong, err)
3965 }
3966 }
3967
3968
3969 func TestTransportNewClientConnCloseOnWriteError(t *testing.T) {
3970 synctest.Test(t, testTransportNewClientConnCloseOnWriteError)
3971 }
3972 func testTransportNewClientConnCloseOnWriteError(t *testing.T) {
3973
3974
3975
3976
3977
3978
3979
3980 t.Skip("TODO: test fails because write errors don't cause the conn to close")
3981
3982 tc := newTestClientConn(t)
3983
3984 synctest.Wait()
3985 writeErr := errors.New("write error")
3986 tc.netconn.loc.setWriteError(writeErr)
3987
3988 tc.writeSettings()
3989 tc.wantIdle()
3990
3991
3992 tc.wantFrameType(FrameSettings)
3993 tc.wantFrameType(FrameWindowUpdate)
3994 tc.wantIdle()
3995
3996 synctest.Wait()
3997 if !tc.netconn.IsClosedByPeer() {
3998 t.Error("expected closed conn")
3999 }
4000 }
4001
4002 func TestTransportRoundtripCloseOnWriteError(t *testing.T) {
4003 synctest.Test(t, testTransportRoundtripCloseOnWriteError)
4004 }
4005 func testTransportRoundtripCloseOnWriteError(t *testing.T) {
4006 tc := newTestClientConn(t)
4007 tc.greet()
4008
4009 body := tc.newRequestBody()
4010 body.writeBytes(1)
4011 req, _ := http.NewRequest("GET", "https://dummy.tld/", body)
4012 rt := tc.roundTrip(req)
4013
4014 writeErr := errors.New("write error")
4015 tc.closeWriteWithError(writeErr)
4016
4017 body.writeBytes(1)
4018 if err := rt.err(); err != writeErr {
4019 t.Fatalf("RoundTrip error %v, want %v", err, writeErr)
4020 }
4021
4022 rt2 := tc.roundTrip(req)
4023 if err := rt2.err(); err != ErrClientConnUnusable {
4024 t.Fatalf("RoundTrip error %v, want errClientConnUnusable", err)
4025 }
4026 }
4027
4028
4029
4030
4031 func TestTransportBodyRewindRace(t *testing.T) {
4032 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4033 w.Header().Set("Connection", "close")
4034 w.WriteHeader(http.StatusOK)
4035 return
4036 })
4037
4038 tr := newTransport(t)
4039 tr.MaxConnsPerHost = 1
4040 client := &http.Client{
4041 Transport: tr,
4042 }
4043
4044 const clients = 50
4045
4046 var wg sync.WaitGroup
4047 wg.Add(clients)
4048 for range clients {
4049 req, err := http.NewRequest("POST", ts.URL, bytes.NewBufferString("abcdef"))
4050 if err != nil {
4051 t.Fatalf("unexpected new request error: %v", err)
4052 }
4053
4054 go func() {
4055 defer wg.Done()
4056 res, err := client.Do(req)
4057 if err == nil {
4058 res.Body.Close()
4059 }
4060 }()
4061 }
4062
4063 wg.Wait()
4064 }
4065
4066 type errorReader struct{ err error }
4067
4068 func (r errorReader) Read(p []byte) (int, error) { return 0, r.err }
4069
4070
4071
4072 func TestTransportServerResetStreamAtHeaders(t *testing.T) {
4073 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4074 w.WriteHeader(http.StatusUnauthorized)
4075 return
4076 })
4077
4078 tr := newTransport(t)
4079 tr.MaxConnsPerHost = 1
4080 tr.ExpectContinueTimeout = 10 * time.Second
4081
4082 client := &http.Client{
4083 Transport: tr,
4084 }
4085
4086 req, err := http.NewRequest("POST", ts.URL, errorReader{io.EOF})
4087 if err != nil {
4088 t.Fatalf("unexpected new request error: %v", err)
4089 }
4090 req.ContentLength = 0
4091 req.Header.Set("Expect", "100-continue")
4092 res, err := client.Do(req)
4093 if err != nil {
4094 t.Fatal(err)
4095 }
4096 res.Body.Close()
4097 }
4098
4099 type trackingReader struct {
4100 rdr io.Reader
4101 wasRead uint32
4102 }
4103
4104 func (tr *trackingReader) Read(p []byte) (int, error) {
4105 atomic.StoreUint32(&tr.wasRead, 1)
4106 return tr.rdr.Read(p)
4107 }
4108
4109 func (tr *trackingReader) WasRead() bool {
4110 return atomic.LoadUint32(&tr.wasRead) != 0
4111 }
4112
4113 func TestTransportExpectContinue(t *testing.T) {
4114 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4115 switch r.URL.Path {
4116 case "/reject":
4117 w.WriteHeader(403)
4118 default:
4119 io.Copy(io.Discard, r.Body)
4120 }
4121 })
4122
4123 tr := newTransport(t)
4124 tr.MaxConnsPerHost = 1
4125 tr.ExpectContinueTimeout = 10 * time.Second
4126
4127 client := &http.Client{
4128 Transport: tr,
4129 }
4130
4131 testCases := []struct {
4132 Name string
4133 Path string
4134 Body *trackingReader
4135 ExpectedCode int
4136 ShouldRead bool
4137 }{
4138 {
4139 Name: "read-all",
4140 Path: "/",
4141 Body: &trackingReader{rdr: strings.NewReader("hello")},
4142 ExpectedCode: 200,
4143 ShouldRead: true,
4144 },
4145 {
4146 Name: "reject",
4147 Path: "/reject",
4148 Body: &trackingReader{rdr: strings.NewReader("hello")},
4149 ExpectedCode: 403,
4150 ShouldRead: false,
4151 },
4152 }
4153
4154 for _, tc := range testCases {
4155 t.Run(tc.Name, func(t *testing.T) {
4156 startTime := time.Now()
4157
4158 req, err := http.NewRequest("POST", ts.URL+tc.Path, tc.Body)
4159 if err != nil {
4160 t.Fatal(err)
4161 }
4162 req.Header.Set("Expect", "100-continue")
4163 res, err := client.Do(req)
4164 if err != nil {
4165 t.Fatal(err)
4166 }
4167 res.Body.Close()
4168
4169 if delta := time.Since(startTime); delta >= tr.ExpectContinueTimeout {
4170 t.Error("Request didn't finish before expect continue timeout")
4171 }
4172 if res.StatusCode != tc.ExpectedCode {
4173 t.Errorf("Unexpected status code, got %d, expected %d", res.StatusCode, tc.ExpectedCode)
4174 }
4175 if tc.Body.WasRead() != tc.ShouldRead {
4176 t.Errorf("Unexpected read status, got %v, expected %v", tc.Body.WasRead(), tc.ShouldRead)
4177 }
4178 })
4179 }
4180 }
4181
4182 type closeChecker struct {
4183 io.ReadCloser
4184 closed chan struct{}
4185 }
4186
4187 func newCloseChecker(r io.ReadCloser) *closeChecker {
4188 return &closeChecker{r, make(chan struct{})}
4189 }
4190
4191 func newStaticCloseChecker(body string) *closeChecker {
4192 return newCloseChecker(io.NopCloser(strings.NewReader("body")))
4193 }
4194
4195 func (rc *closeChecker) Read(b []byte) (n int, err error) {
4196 select {
4197 default:
4198 case <-rc.closed:
4199
4200
4201
4202 return 0, errors.New("read after Body.Close")
4203 }
4204 return rc.ReadCloser.Read(b)
4205 }
4206
4207 func (rc *closeChecker) Close() error {
4208 close(rc.closed)
4209 return rc.ReadCloser.Close()
4210 }
4211
4212 func (rc *closeChecker) isClosed() error {
4213
4214
4215
4216 timeout := time.Duration(10 * time.Second)
4217 select {
4218 case <-rc.closed:
4219 case <-time.After(timeout):
4220 return fmt.Errorf("body not closed after %v", timeout)
4221 }
4222 return nil
4223 }
4224
4225
4226 type blockingWriteConn struct {
4227 net.Conn
4228 writeOnce sync.Once
4229 writec chan struct{}
4230 unblockc chan struct{}
4231 count, limit int
4232 }
4233
4234 func newBlockingWriteConn(conn net.Conn, limit int) *blockingWriteConn {
4235 return &blockingWriteConn{
4236 Conn: conn,
4237 limit: limit,
4238 writec: make(chan struct{}),
4239 unblockc: make(chan struct{}),
4240 }
4241 }
4242
4243
4244 func (c *blockingWriteConn) wait() {
4245 <-c.writec
4246 }
4247
4248
4249 func (c *blockingWriteConn) unblock() {
4250 close(c.unblockc)
4251 }
4252
4253 func (c *blockingWriteConn) Write(b []byte) (n int, err error) {
4254 if c.count+len(b) > c.limit {
4255 c.writeOnce.Do(func() {
4256 close(c.writec)
4257 })
4258 <-c.unblockc
4259 }
4260 n, err = c.Conn.Write(b)
4261 c.count += n
4262 return n, err
4263 }
4264
4265
4266
4267 func TestTransportFrameBufferReuse(t *testing.T) {
4268 filler := hex.EncodeToString([]byte(randString(2048)))
4269
4270 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4271 if got, want := r.Header.Get("Big"), filler; got != want {
4272 t.Errorf(`r.Header.Get("Big") = %q, want %q`, got, want)
4273 }
4274 b, err := io.ReadAll(r.Body)
4275 if err != nil {
4276 t.Errorf("error reading request body: %v", err)
4277 }
4278 if got, want := string(b), filler; got != want {
4279 t.Errorf("request body = %q, want %q", got, want)
4280 }
4281 if got, want := r.Trailer.Get("Big"), filler; got != want {
4282 t.Errorf(`r.Trailer.Get("Big") = %q, want %q`, got, want)
4283 }
4284 })
4285
4286 tr := newTransport(t)
4287
4288 var wg sync.WaitGroup
4289 defer wg.Wait()
4290 for range 10 {
4291 wg.Go(func() {
4292 req, err := http.NewRequest("POST", ts.URL, strings.NewReader(filler))
4293 if err != nil {
4294 t.Error(err)
4295 return
4296 }
4297 req.Header.Set("Big", filler)
4298 req.Trailer = make(http.Header)
4299 req.Trailer.Set("Big", filler)
4300 res, err := tr.RoundTrip(req)
4301 if err != nil {
4302 t.Error(err)
4303 return
4304 }
4305 if got, want := res.StatusCode, 200; got != want {
4306 t.Errorf("StatusCode = %v; want %v", got, want)
4307 }
4308 if res != nil && res.Body != nil {
4309 res.Body.Close()
4310 }
4311 })
4312 }
4313
4314 }
4315
4316
4317
4318
4319
4320 func TestTransportBlockingRequestWrite(t *testing.T) {
4321 filler := hex.EncodeToString([]byte(randString(2048)))
4322 for _, test := range []struct {
4323 name string
4324 req *http.Request
4325 }{{
4326 name: "headers",
4327 req: func() *http.Request {
4328 req, _ := http.NewRequest("POST", "https://dummy.tld/", nil)
4329 req.Header.Set("Big", filler)
4330 return req
4331 }(),
4332 }, {
4333 name: "body",
4334 req: func() *http.Request {
4335 req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader(filler))
4336 return req
4337 }(),
4338 }, {
4339 name: "trailer",
4340 req: func() *http.Request {
4341 req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader("body"))
4342 req.Trailer = make(http.Header)
4343 req.Trailer.Set("Big", filler)
4344 return req
4345 }(),
4346 }} {
4347 t.Run(test.name, func(t *testing.T) {
4348 synctest.Test(t, func(t *testing.T) {
4349 testTransportBlockingRequestWrite(t, test.req)
4350 })
4351 })
4352 }
4353 }
4354 func testTransportBlockingRequestWrite(t *testing.T, req2 *http.Request) {
4355 tt := newTestTransport(t)
4356
4357 smallReq := func() *http.Request {
4358 req, _ := http.NewRequest("GET", req2.URL.String(), nil)
4359 return req
4360 }
4361
4362
4363 rt1 := tt.roundTrip(smallReq())
4364 tc1 := tt.getConn()
4365 tc1.wantFrameType(FrameSettings)
4366 tc1.wantFrameType(FrameWindowUpdate)
4367 tc1.wantHeaders(wantHeader{
4368 streamID: 1,
4369 endStream: true,
4370 })
4371 tc1.writeSettings(Setting{SettingMaxConcurrentStreams, 1})
4372 tc1.writeHeaders(HeadersFrameParam{
4373 StreamID: 1,
4374 EndHeaders: true,
4375 EndStream: true,
4376 BlockFragment: tc1.makeHeaderBlockFragment(
4377 ":status", "200",
4378 ),
4379 })
4380 rt1.wantStatus(200)
4381 tc1.wantFrameType(FrameSettings)
4382
4383
4384 tc1.netconn.SetReadBufferSize(1024)
4385 rt2 := tt.roundTrip(req2)
4386
4387
4388
4389 rt3 := tt.roundTrip(smallReq())
4390 tc2 := tt.getConn()
4391 tc2.wantFrameType(FrameSettings)
4392 tc2.wantFrameType(FrameWindowUpdate)
4393 tc2.wantHeaders(wantHeader{
4394 streamID: 1,
4395 endStream: true,
4396 })
4397 tc2.writeSettings()
4398 tc2.writeHeaders(HeadersFrameParam{
4399 StreamID: 1,
4400 EndHeaders: true,
4401 EndStream: true,
4402 BlockFragment: tc1.makeHeaderBlockFragment(
4403 ":status", "200",
4404 ),
4405 })
4406 rt3.wantStatus(200)
4407 tc2.wantFrameType(FrameSettings)
4408
4409 if rt2.done() {
4410 t.Errorf("RoundTrip 2 is done, expect it to be still pending")
4411 }
4412 }
4413
4414 func TestTransportCloseRequestBody(t *testing.T) {
4415 var statusCode int
4416 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4417 w.WriteHeader(statusCode)
4418 })
4419
4420 tr := newTransport(t)
4421 ctx := context.Background()
4422 cc, err := tr.NewClientConn(ctx, "https", ts.Listener.Addr().String())
4423 if err != nil {
4424 t.Fatal(err)
4425 }
4426 defer cc.Close()
4427
4428 for _, status := range []int{200, 401} {
4429 t.Run(fmt.Sprintf("status=%d", status), func(t *testing.T) {
4430 statusCode = status
4431 pr, pw := io.Pipe()
4432 body := newCloseChecker(pr)
4433 req, err := http.NewRequest("PUT", "https://dummy.tld/", body)
4434 if err != nil {
4435 t.Fatal(err)
4436 }
4437 res, err := cc.RoundTrip(req)
4438 if err != nil {
4439 t.Fatal(err)
4440 }
4441 res.Body.Close()
4442 pw.Close()
4443 if err := body.isClosed(); err != nil {
4444 t.Fatal(err)
4445 }
4446 })
4447 }
4448 }
4449
4450 func TestTransportNoRetryOnStreamProtocolError(t *testing.T) {
4451 synctest.Test(t, testTransportNoRetryOnStreamProtocolError)
4452 }
4453 func testTransportNoRetryOnStreamProtocolError(t *testing.T) {
4454
4455
4456
4457
4458
4459 tt := newTestTransport(t)
4460
4461
4462
4463
4464
4465
4466 req1, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
4467 rt1 := tt.roundTrip(req1)
4468 tc1 := tt.getConn()
4469 tc1.wantFrameType(FrameSettings)
4470 tc1.wantFrameType(FrameWindowUpdate)
4471 tc1.wantHeaders(wantHeader{
4472 streamID: 1,
4473 endStream: true,
4474 })
4475 tc1.writeSettings()
4476 tc1.wantFrameType(FrameSettings)
4477
4478
4479 req2, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
4480 rt2 := tt.roundTrip(req2)
4481 tc1.wantHeaders(wantHeader{
4482 streamID: 3,
4483 endStream: true,
4484 })
4485
4486
4487 tc1.writeRSTStream(3, ErrCodeProtocol)
4488 if rt1.done() {
4489 t.Fatalf("After protocol error on RoundTrip #2, RoundTrip #1 is done; want still in progress")
4490 }
4491 if !rt2.done() {
4492 t.Fatalf("After protocol error on RoundTrip #2, RoundTrip #2 is in progress; want done")
4493 }
4494
4495 if tt.hasConn() {
4496 t.Fatalf("After protocol error on RoundTrip #2, RoundTrip #2 is unexpectedly retried")
4497 }
4498
4499
4500 tc1.writeHeaders(HeadersFrameParam{
4501 StreamID: 1,
4502 EndHeaders: true,
4503 EndStream: true,
4504 BlockFragment: tc1.makeHeaderBlockFragment(
4505 ":status", "200",
4506 ),
4507 })
4508 rt1.wantStatus(200)
4509 }
4510
4511 func TestClientConnReservations(t *testing.T) { synctest.Test(t, testClientConnReservations) }
4512 func testClientConnReservations(t *testing.T) {
4513 tc := newTestClientConn(t)
4514 tc.greet(
4515 Setting{ID: SettingMaxConcurrentStreams, Val: InitialMaxConcurrentStreams},
4516 )
4517
4518 doRoundTrip := func() {
4519 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
4520 rt := tc.roundTrip(req)
4521 tc.wantFrameType(FrameHeaders)
4522 tc.writeHeaders(HeadersFrameParam{
4523 StreamID: rt.streamID(),
4524 EndHeaders: true,
4525 EndStream: true,
4526 BlockFragment: tc.makeHeaderBlockFragment(
4527 ":status", "200",
4528 ),
4529 })
4530 rt.wantStatus(200)
4531 }
4532
4533 n := 0
4534 for n <= InitialMaxConcurrentStreams && tc.cc.ReserveNewRequest() {
4535 n++
4536 }
4537 if n != InitialMaxConcurrentStreams {
4538 t.Errorf("did %v reservations; want %v", n, InitialMaxConcurrentStreams)
4539 }
4540 doRoundTrip()
4541 n2 := 0
4542 for n2 <= 5 && tc.cc.ReserveNewRequest() {
4543 n2++
4544 }
4545 if n2 != 1 {
4546 t.Fatalf("after one RoundTrip, did %v reservations; want 1", n2)
4547 }
4548
4549
4550 for i := 0; i < n; i++ {
4551 doRoundTrip()
4552 }
4553
4554 n2 = 0
4555 for n2 <= InitialMaxConcurrentStreams && tc.cc.ReserveNewRequest() {
4556 n2++
4557 }
4558 if n2 != n {
4559 t.Errorf("after reset, reservations = %v; want %v", n2, n)
4560 }
4561 }
4562
4563 func TestTransportTimeoutServerHangs(t *testing.T) { synctest.Test(t, testTransportTimeoutServerHangs) }
4564 func testTransportTimeoutServerHangs(t *testing.T) {
4565 tc := newTestClientConn(t)
4566 tc.greet()
4567
4568 ctx, cancel := context.WithCancel(context.Background())
4569 req, _ := http.NewRequestWithContext(ctx, "PUT", "https://dummy.tld/", nil)
4570 rt := tc.roundTrip(req)
4571
4572 tc.wantFrameType(FrameHeaders)
4573 time.Sleep(5 * time.Second)
4574 if f := tc.readFrame(); f != nil {
4575 t.Fatalf("unexpected frame: %v", f)
4576 }
4577 if rt.done() {
4578 t.Fatalf("after 5 seconds with no response, RoundTrip unexpectedly returned")
4579 }
4580
4581 cancel()
4582 synctest.Wait()
4583 if rt.err() != context.Canceled {
4584 t.Fatalf("RoundTrip error: %v; want context.Canceled", rt.err())
4585 }
4586 }
4587
4588 func TestTransportContentLengthWithoutBody(t *testing.T) {
4589 for _, test := range []struct {
4590 name string
4591 contentLength string
4592 wantBody string
4593 wantErr error
4594 wantContentLength int64
4595 }{
4596 {
4597 name: "non-zero content length",
4598 contentLength: "42",
4599 wantErr: io.ErrUnexpectedEOF,
4600 wantContentLength: 42,
4601 },
4602 {
4603 name: "zero content length",
4604 contentLength: "0",
4605 wantErr: nil,
4606 wantContentLength: 0,
4607 },
4608 } {
4609 synctestSubtest(t, test.name, func(t *testing.T) {
4610 contentLength := ""
4611 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4612 w.Header().Set("Content-Length", contentLength)
4613 })
4614 tr := newTransport(t)
4615
4616 contentLength = test.contentLength
4617
4618 req, _ := http.NewRequest("GET", ts.URL, nil)
4619 res, err := tr.RoundTrip(req)
4620 if err != nil {
4621 t.Fatal(err)
4622 }
4623 defer res.Body.Close()
4624 body, err := io.ReadAll(res.Body)
4625
4626 if err != test.wantErr {
4627 t.Errorf("Expected error %v, got: %v", test.wantErr, err)
4628 }
4629 if len(body) > 0 {
4630 t.Errorf("Expected empty body, got: %v", body)
4631 }
4632 if res.ContentLength != test.wantContentLength {
4633 t.Errorf("Expected content length %d, got: %d", test.wantContentLength, res.ContentLength)
4634 }
4635 })
4636 }
4637 }
4638
4639 func TestTransportCloseResponseBodyWhileRequestBodyHangs(t *testing.T) {
4640 synctest.Test(t, testTransportCloseResponseBodyWhileRequestBodyHangs)
4641 }
4642 func testTransportCloseResponseBodyWhileRequestBodyHangs(t *testing.T) {
4643 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4644 w.WriteHeader(200)
4645 w.(http.Flusher).Flush()
4646 io.Copy(io.Discard, r.Body)
4647 })
4648
4649 tr := newTransport(t)
4650
4651 pr, pw := net.Pipe()
4652 req, err := http.NewRequest("GET", ts.URL, pr)
4653 if err != nil {
4654 t.Fatal(err)
4655 }
4656 res, err := tr.RoundTrip(req)
4657 if err != nil {
4658 t.Fatal(err)
4659 }
4660
4661 res.Body.Close()
4662 pw.Close()
4663 }
4664
4665 func TestTransport300ResponseBody(t *testing.T) { synctest.Test(t, testTransport300ResponseBody) }
4666 func testTransport300ResponseBody(t *testing.T) {
4667 reqc := make(chan struct{})
4668 body := []byte("response body")
4669 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4670 w.WriteHeader(300)
4671 w.(http.Flusher).Flush()
4672 <-reqc
4673 w.Write(body)
4674 })
4675
4676 tr := newTransport(t)
4677
4678 pr, pw := net.Pipe()
4679 req, err := http.NewRequest("GET", ts.URL, pr)
4680 if err != nil {
4681 t.Fatal(err)
4682 }
4683 res, err := tr.RoundTrip(req)
4684 if err != nil {
4685 t.Fatal(err)
4686 }
4687 close(reqc)
4688 got, err := io.ReadAll(res.Body)
4689 if err != nil {
4690 t.Fatalf("error reading response body: %v", err)
4691 }
4692 if !bytes.Equal(got, body) {
4693 t.Errorf("got response body %q, want %q", string(got), string(body))
4694 }
4695 res.Body.Close()
4696 pw.Close()
4697 }
4698
4699 func TestTransportWriteByteTimeout(t *testing.T) {
4700 ts := newTestServer(t, nil, func(s *http.Server) {
4701 s.Protocols = protocols("h2c")
4702 })
4703 tr := newTransport(t)
4704 tr.Protocols = protocols("h2c")
4705 tr.Dial = func(network, addr string) (net.Conn, error) {
4706 _, c := net.Pipe()
4707 return c, nil
4708 }
4709 tr.HTTP2.WriteByteTimeout = 1 * time.Millisecond
4710 defer tr.CloseIdleConnections()
4711 c := &http.Client{Transport: tr}
4712
4713 _, err := c.Get(ts.URL)
4714 if !errors.Is(err, os.ErrDeadlineExceeded) {
4715 t.Fatalf("Get on unresponsive connection: got %q; want ErrDeadlineExceeded", err)
4716 }
4717 }
4718
4719 type slowWriteConn struct {
4720 net.Conn
4721 hasWriteDeadline bool
4722 }
4723
4724 func (c *slowWriteConn) SetWriteDeadline(t time.Time) error {
4725 c.hasWriteDeadline = !t.IsZero()
4726 return nil
4727 }
4728
4729 func (c *slowWriteConn) Write(b []byte) (n int, err error) {
4730 if c.hasWriteDeadline && len(b) > 1 {
4731 n, err = c.Conn.Write(b[:1])
4732 if err != nil {
4733 return n, err
4734 }
4735 return n, fmt.Errorf("slow write: %w", os.ErrDeadlineExceeded)
4736 }
4737 return c.Conn.Write(b)
4738 }
4739
4740 func TestTransportSlowWrites(t *testing.T) { synctest.Test(t, testTransportSlowWrites) }
4741 func testTransportSlowWrites(t *testing.T) {
4742 ts := newTestServer(t, nil, func(s *http.Server) {
4743 s.Protocols = protocols("h2c")
4744 })
4745 tr := newTransport(t)
4746 tr.Protocols = protocols("h2c")
4747 tr.Dial = func(network, addr string) (net.Conn, error) {
4748 c, err := net.Dial(network, addr)
4749 return &slowWriteConn{Conn: c}, err
4750 }
4751 tr.HTTP2.WriteByteTimeout = 1 * time.Millisecond
4752 c := &http.Client{Transport: tr}
4753
4754 const bodySize = 1 << 20
4755 resp, err := c.Post(ts.URL, "text/foo", io.LimitReader(neverEnding('A'), bodySize))
4756 if err != nil {
4757 t.Fatal(err)
4758 }
4759 resp.Body.Close()
4760 }
4761
4762 func TestTransportClosesConnAfterGoAwayNoStreams(t *testing.T) {
4763 synctest.Test(t, func(t *testing.T) {
4764 testTransportClosesConnAfterGoAway(t, 0)
4765 })
4766 }
4767 func TestTransportClosesConnAfterGoAwayLastStream(t *testing.T) {
4768 synctest.Test(t, func(t *testing.T) {
4769 testTransportClosesConnAfterGoAway(t, 1)
4770 })
4771 }
4772
4773
4774
4775
4776
4777
4778
4779 func testTransportClosesConnAfterGoAway(t *testing.T, lastStream uint32) {
4780 tc := newTestClientConn(t)
4781 tc.greet()
4782
4783 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
4784 rt := tc.roundTrip(req)
4785
4786 tc.wantFrameType(FrameHeaders)
4787 tc.writeGoAway(lastStream, ErrCodeNo, nil)
4788
4789 if lastStream > 0 {
4790
4791 tc.writeHeaders(HeadersFrameParam{
4792 StreamID: rt.streamID(),
4793 EndHeaders: true,
4794 EndStream: true,
4795 BlockFragment: tc.makeHeaderBlockFragment(
4796 ":status", "200",
4797 ),
4798 })
4799 }
4800
4801 tc.closeWrite()
4802 err := rt.err()
4803 if gotErr, wantErr := err != nil, lastStream == 0; gotErr != wantErr {
4804 t.Errorf("RoundTrip got error %v (want error: %v)", err, wantErr)
4805 }
4806 if !tc.isClosed() {
4807 t.Errorf("ClientConn did not close its net.Conn, expected it to")
4808 }
4809 }
4810
4811 type slowCloser struct {
4812 closing chan struct{}
4813 closed chan struct{}
4814 }
4815
4816 func (r *slowCloser) Read([]byte) (int, error) {
4817 return 0, io.EOF
4818 }
4819
4820 func (r *slowCloser) Close() error {
4821 close(r.closing)
4822 <-r.closed
4823 return nil
4824 }
4825
4826 func TestTransportSlowClose(t *testing.T) {
4827 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
4828 })
4829
4830 client := ts.Client()
4831 body := &slowCloser{
4832 closing: make(chan struct{}),
4833 closed: make(chan struct{}),
4834 }
4835
4836 reqc := make(chan struct{})
4837 go func() {
4838 defer close(reqc)
4839 res, err := client.Post(ts.URL, "text/plain", body)
4840 if err != nil {
4841 t.Error(err)
4842 }
4843 res.Body.Close()
4844 }()
4845 defer func() {
4846 close(body.closed)
4847 <-reqc
4848 }()
4849
4850 <-body.closing
4851
4852 res, err := client.Get(ts.URL)
4853 if err != nil {
4854 t.Fatal(err)
4855 }
4856 res.Body.Close()
4857 }
4858
4859 func TestTransportDialTLSContext(t *testing.T) {
4860 blockCh := make(chan struct{})
4861 serverTLSConfigFunc := func(ts *httptest.Server) {
4862 ts.Config.TLSConfig = &tls.Config{
4863
4864
4865 ClientAuth: tls.RequestClientCert,
4866 }
4867 }
4868 ts := newTestServer(t,
4869 func(w http.ResponseWriter, r *http.Request) {},
4870 serverTLSConfigFunc,
4871 )
4872 tr := newTransport(t)
4873 tr.TLSClientConfig = &tls.Config{
4874 GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) {
4875
4876
4877 close(blockCh)
4878 <-cri.Context().Done()
4879 return nil, cri.Context().Err()
4880 },
4881 InsecureSkipVerify: true,
4882 }
4883 req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
4884 if err != nil {
4885 t.Fatal(err)
4886 }
4887 ctx, cancel := context.WithCancel(context.Background())
4888 defer cancel()
4889 req = req.WithContext(ctx)
4890 errCh := make(chan error)
4891 go func() {
4892 defer close(errCh)
4893 res, err := tr.RoundTrip(req)
4894 if err != nil {
4895 errCh <- err
4896 return
4897 }
4898 res.Body.Close()
4899 }()
4900
4901 <-blockCh
4902
4903 cancel()
4904
4905 err = <-errCh
4906 if err == nil {
4907 t.Fatal("cancelling context during client certificate fetch did not error as expected")
4908 return
4909 }
4910 if !errors.Is(err, context.Canceled) {
4911 t.Fatalf("unexpected error returned after cancellation: %v", err)
4912 }
4913 }
4914
4915
4916
4917
4918
4919 func TestDialRaceResumesDial(t *testing.T) {
4920 t.Skip("https://go.dev/issue/77908: test fails when using an http.Transport")
4921 blockCh := make(chan struct{})
4922 serverTLSConfigFunc := func(ts *httptest.Server) {
4923 ts.Config.TLSConfig = &tls.Config{
4924
4925
4926 ClientAuth: tls.RequestClientCert,
4927 }
4928 }
4929 ts := newTestServer(t,
4930 func(w http.ResponseWriter, r *http.Request) {},
4931 serverTLSConfigFunc,
4932 )
4933 tr := newTransport(t)
4934 tr.TLSClientConfig = &tls.Config{
4935 GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) {
4936 select {
4937 case <-blockCh:
4938
4939 return &tls.Certificate{}, nil
4940 default:
4941 }
4942 close(blockCh)
4943 <-cri.Context().Done()
4944 return nil, cri.Context().Err()
4945 },
4946 InsecureSkipVerify: true,
4947 }
4948 req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
4949 if err != nil {
4950 t.Fatal(err)
4951 }
4952
4953 ctx1, cancel1 := context.WithCancel(context.Background())
4954 defer cancel1()
4955 req1 := req.WithContext(ctx1)
4956 ctx2 := t.Context()
4957 req2 := req.WithContext(ctx2)
4958 errCh := make(chan error)
4959 go func() {
4960 res, err := tr.RoundTrip(req1)
4961 if err != nil {
4962 errCh <- err
4963 return
4964 }
4965 res.Body.Close()
4966 }()
4967 successCh := make(chan struct{})
4968 go func() {
4969
4970
4971 <-blockCh
4972 res, err := tr.RoundTrip(req2)
4973 if err != nil {
4974 errCh <- err
4975 return
4976 }
4977 res.Body.Close()
4978
4979
4980 close(successCh)
4981 }()
4982
4983 <-blockCh
4984
4985 cancel1()
4986
4987 err = <-errCh
4988 if err == nil {
4989 t.Fatal("cancelling context during client certificate fetch did not error as expected")
4990 return
4991 }
4992 if !errors.Is(err, context.Canceled) {
4993 t.Fatalf("unexpected error returned after cancellation: %v", err)
4994 }
4995 select {
4996 case err := <-errCh:
4997 t.Fatalf("unexpected second error: %v", err)
4998 case <-successCh:
4999 }
5000 }
5001
5002 func TestTransportDataAfter1xxHeader(t *testing.T) { synctest.Test(t, testTransportDataAfter1xxHeader) }
5003 func testTransportDataAfter1xxHeader(t *testing.T) {
5004
5005 log.SetOutput(io.Discard)
5006 defer log.SetOutput(os.Stderr)
5007
5008
5009 tc := newTestClientConn(t)
5010 tc.greet()
5011
5012 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
5013 rt := tc.roundTrip(req)
5014
5015 tc.wantFrameType(FrameHeaders)
5016 tc.writeHeaders(HeadersFrameParam{
5017 StreamID: rt.streamID(),
5018 EndHeaders: true,
5019 EndStream: false,
5020 BlockFragment: tc.makeHeaderBlockFragment(
5021 ":status", "100",
5022 ),
5023 })
5024 tc.writeData(rt.streamID(), true, []byte{0})
5025 err := rt.err()
5026 if err, ok := err.(StreamError); !ok || err.Code != ErrCodeProtocol {
5027 t.Errorf("RoundTrip error: %v; want ErrCodeProtocol", err)
5028 }
5029 tc.wantFrameType(FrameRSTStream)
5030 }
5031
5032 func TestIssue66763Race(t *testing.T) {
5033 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {},
5034 func(s *http.Server) {
5035 s.Protocols = protocols("h2c")
5036 })
5037 tr := newTransport(t)
5038 tr.IdleConnTimeout = 1 * time.Nanosecond
5039 tr.Protocols = protocols("h2c")
5040
5041 donec := make(chan struct{})
5042 go func() {
5043
5044
5045
5046 conn, err := tr.NewClientConn(t.Context(), "http", ts.URL)
5047 close(donec)
5048 if err == nil {
5049 conn.Close()
5050 }
5051 }()
5052
5053
5054
5055 <-donec
5056 }
5057
5058
5059
5060 func TestIssue67671(t *testing.T) {
5061 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {},
5062 func(s *http.Server) {
5063 s.Protocols = protocols("h2c")
5064 })
5065 tr := newTransport(t)
5066 tr.Protocols = protocols("h2c")
5067 req, _ := http.NewRequest("GET", ts.URL, nil)
5068 req.Close = true
5069 for range 2 {
5070 res, err := tr.RoundTrip(req)
5071 if err != nil {
5072 t.Fatal(err)
5073 }
5074 res.Body.Close()
5075 }
5076 }
5077
5078 func TestTransport1xxLimits(t *testing.T) {
5079 for _, test := range []struct {
5080 name string
5081 opt any
5082 ctxfn func(context.Context) context.Context
5083 hcount int
5084 limited bool
5085 }{{
5086 name: "default",
5087 hcount: 10,
5088 limited: false,
5089 }, {
5090 name: "MaxResponseHeaderBytes",
5091 opt: func(tr *http.Transport) {
5092 tr.MaxResponseHeaderBytes = 10000
5093 },
5094 hcount: 10,
5095 limited: true,
5096 }, {
5097 name: "limit by client trace",
5098 ctxfn: func(ctx context.Context) context.Context {
5099 count := 0
5100 return httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
5101 Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
5102 count++
5103 if count >= 10 {
5104 return errors.New("too many 1xx")
5105 }
5106 return nil
5107 },
5108 })
5109 },
5110 hcount: 10,
5111 limited: true,
5112 }, {
5113 name: "limit disabled by client trace",
5114 opt: func(tr *http.Transport) {
5115 tr.MaxResponseHeaderBytes = 10000
5116 },
5117 ctxfn: func(ctx context.Context) context.Context {
5118 return httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
5119 Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
5120 return nil
5121 },
5122 })
5123 },
5124 hcount: 20,
5125 limited: false,
5126 }} {
5127 synctestSubtest(t, test.name, func(t *testing.T) {
5128 tc := newTestClientConn(t, test.opt)
5129 tc.greet()
5130
5131 ctx := context.Background()
5132 if test.ctxfn != nil {
5133 ctx = test.ctxfn(ctx)
5134 }
5135 req, _ := http.NewRequestWithContext(ctx, "GET", "https://dummy.tld/", nil)
5136 rt := tc.roundTrip(req)
5137 tc.wantFrameType(FrameHeaders)
5138
5139 for i := 0; i < test.hcount; i++ {
5140 if fr, err := tc.fr.ReadFrame(); err != os.ErrDeadlineExceeded {
5141 t.Fatalf("after writing %v 1xx headers: read %v, %v; want idle", i, fr, err)
5142 }
5143 tc.writeHeaders(HeadersFrameParam{
5144 StreamID: rt.streamID(),
5145 EndHeaders: true,
5146 EndStream: false,
5147 BlockFragment: tc.makeHeaderBlockFragment(
5148 ":status", "103",
5149 "x-field", strings.Repeat("a", 1000),
5150 ),
5151 })
5152 }
5153 if test.limited {
5154 tc.wantFrameType(FrameRSTStream)
5155 } else {
5156 tc.wantIdle()
5157 }
5158 })
5159 }
5160 }
5161
5162
5163
5164 func TestTransportSendPingWithReset(t *testing.T) { synctest.Test(t, testTransportSendPingWithReset) }
5165 func testTransportSendPingWithReset(t *testing.T) {
5166 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
5167 h2.StrictMaxConcurrentRequests = true
5168 })
5169
5170 const maxConcurrent = 3
5171 tc.greet(Setting{SettingMaxConcurrentStreams, maxConcurrent})
5172
5173
5174 var rts []*testRoundTrip
5175 for i := range maxConcurrent + 1 {
5176 req := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5177 rt := tc.roundTrip(req)
5178 if i >= maxConcurrent {
5179 tc.wantIdle()
5180 continue
5181 }
5182 tc.wantFrameType(FrameHeaders)
5183 rts = append(rts, rt)
5184 }
5185
5186
5187 rts[0].cancel()
5188 tc.wantRSTStream(rts[0].streamID(), ErrCodeCancel)
5189 pf := readFrame[*PingFrame](t, tc)
5190 tc.wantIdle()
5191
5192
5193 rts[1].cancel()
5194 tc.wantRSTStream(rts[1].streamID(), ErrCodeCancel)
5195 tc.wantIdle()
5196
5197
5198
5199 tc.writePing(true, pf.Data)
5200 tc.wantFrameType(FrameHeaders)
5201 tc.wantIdle()
5202 }
5203
5204
5205
5206
5207
5208 func TestTransportNoPingAfterResetWithFrames(t *testing.T) {
5209 synctest.Test(t, testTransportNoPingAfterResetWithFrames)
5210 }
5211 func testTransportNoPingAfterResetWithFrames(t *testing.T) {
5212 tc := newTestClientConn(t, func(h2 *http.HTTP2Config) {
5213 h2.StrictMaxConcurrentRequests = true
5214 })
5215
5216 const maxConcurrent = 1
5217 tc.greet(Setting{SettingMaxConcurrentStreams, maxConcurrent})
5218
5219
5220
5221 req1 := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5222 rt1 := tc.roundTrip(req1)
5223 tc.wantFrameType(FrameHeaders)
5224 tc.writeHeaders(HeadersFrameParam{
5225 StreamID: rt1.streamID(),
5226 EndHeaders: true,
5227 BlockFragment: tc.makeHeaderBlockFragment(
5228 ":status", "200",
5229 ),
5230 })
5231 rt1.wantStatus(200)
5232
5233
5234
5235 req2 := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5236 rt2 := tc.roundTrip(req2)
5237 tc.wantIdle()
5238
5239
5240
5241 rt1.cancel()
5242 tc.wantRSTStream(rt1.streamID(), ErrCodeCancel)
5243 tc.wantFrameType(FrameHeaders)
5244
5245
5246
5247
5248 rt2.cancel()
5249 tc.wantRSTStream(rt2.streamID(), ErrCodeCancel)
5250 tc.wantFrameType(FramePing)
5251 }
5252
5253
5254
5255 func TestTransportSendNoMoreThanOnePingWithReset(t *testing.T) {
5256 synctest.Test(t, testTransportSendNoMoreThanOnePingWithReset)
5257 }
5258 func testTransportSendNoMoreThanOnePingWithReset(t *testing.T) {
5259 tc := newTestClientConn(t)
5260 tc.greet()
5261
5262 makeAndResetRequest := func() {
5263 t.Helper()
5264 ctx, cancel := context.WithCancel(context.Background())
5265 req := Must(http.NewRequestWithContext(ctx, "GET", "https://dummy.tld/", nil))
5266 rt := tc.roundTrip(req)
5267 tc.wantFrameType(FrameHeaders)
5268 cancel()
5269 tc.wantRSTStream(rt.streamID(), ErrCodeCancel)
5270 }
5271
5272
5273
5274 makeAndResetRequest()
5275 pf1 := readFrame[*PingFrame](t, tc)
5276 tc.wantIdle()
5277
5278
5279
5280
5281
5282 makeAndResetRequest()
5283 tc.wantIdle()
5284
5285
5286
5287 tc.writeHeaders(HeadersFrameParam{
5288 StreamID: 1,
5289 EndHeaders: true,
5290 EndStream: true,
5291 BlockFragment: tc.makeHeaderBlockFragment(
5292 ":status", "200",
5293 ),
5294 })
5295 tc.wantIdle()
5296
5297
5298
5299
5300 makeAndResetRequest()
5301 tc.wantIdle()
5302
5303
5304 tc.writePing(true, pf1.Data)
5305 tc.wantIdle()
5306
5307
5308
5309
5310 makeAndResetRequest()
5311 tc.wantIdle()
5312
5313
5314 tc.writeHeaders(HeadersFrameParam{
5315 StreamID: 3,
5316 EndHeaders: true,
5317 EndStream: true,
5318 BlockFragment: tc.makeHeaderBlockFragment(
5319 ":status", "200",
5320 ),
5321 })
5322 tc.wantIdle()
5323
5324
5325
5326 makeAndResetRequest()
5327 tc.wantFrameType(FramePing)
5328 }
5329
5330 func TestTransportConnBecomesUnresponsive(t *testing.T) {
5331 synctest.Test(t, testTransportConnBecomesUnresponsive)
5332 }
5333 func testTransportConnBecomesUnresponsive(t *testing.T) {
5334
5335
5336
5337 tt := newTestTransport(t)
5338
5339 const maxConcurrent = 3
5340
5341 t.Logf("first request opens a new connection and succeeds")
5342 req1 := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5343 rt1 := tt.roundTrip(req1)
5344 tc1 := tt.getConn()
5345 tc1.wantFrameType(FrameSettings)
5346 tc1.wantFrameType(FrameWindowUpdate)
5347 hf1 := readFrame[*HeadersFrame](t, tc1)
5348 tc1.writeSettings(Setting{SettingMaxConcurrentStreams, maxConcurrent})
5349 tc1.wantFrameType(FrameSettings)
5350 tc1.writeHeaders(HeadersFrameParam{
5351 StreamID: hf1.StreamID,
5352 EndHeaders: true,
5353 EndStream: true,
5354 BlockFragment: tc1.makeHeaderBlockFragment(
5355 ":status", "200",
5356 ),
5357 })
5358 rt1.wantStatus(200)
5359 rt1.response().Body.Close()
5360
5361
5362
5363
5364 for i := range maxConcurrent {
5365 t.Logf("request %v receives no response and is canceled", i)
5366 ctx, cancel := context.WithCancel(context.Background())
5367 req := Must(http.NewRequestWithContext(ctx, "GET", "https://dummy.tld/", nil))
5368 tt.roundTrip(req)
5369 if tt.hasConn() {
5370 t.Fatalf("new connection created; expect existing conn to be reused")
5371 }
5372 tc1.wantFrameType(FrameHeaders)
5373 cancel()
5374 tc1.wantFrameType(FrameRSTStream)
5375 if i == 0 {
5376 tc1.wantFrameType(FramePing)
5377 }
5378 tc1.wantIdle()
5379 }
5380
5381
5382
5383 req2 := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5384 rt2 := tt.roundTrip(req2)
5385 tc2 := tt.getConn()
5386 tc2.wantFrameType(FrameSettings)
5387 tc2.wantFrameType(FrameWindowUpdate)
5388 hf := readFrame[*HeadersFrame](t, tc2)
5389 tc2.writeSettings(Setting{SettingMaxConcurrentStreams, maxConcurrent})
5390 tc2.wantFrameType(FrameSettings)
5391 tc2.writeHeaders(HeadersFrameParam{
5392 StreamID: hf.StreamID,
5393 EndHeaders: true,
5394 EndStream: true,
5395 BlockFragment: tc2.makeHeaderBlockFragment(
5396 ":status", "200",
5397 ),
5398 })
5399 rt2.wantStatus(200)
5400 rt2.response().Body.Close()
5401 }
5402
5403
5404
5405
5406
5407
5408 func newTestTransportWithUnusedConn(t *testing.T, opts ...any) *testTransport {
5409 tt := newTestTransport(t, opts...)
5410
5411 waitc := make(chan struct{})
5412 dialContext := tt.tr1.DialContext
5413 tt.tr1.DialContext = func(ctx context.Context, network, address string) (net.Conn, error) {
5414 <-waitc
5415 return dialContext(ctx, network, address)
5416 }
5417
5418 req := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5419 rt := tt.roundTrip(req)
5420 rt.cancel()
5421 if rt.err() == nil {
5422 t.Fatalf("RoundTrip still running after request is canceled")
5423 }
5424
5425 close(waitc)
5426 synctest.Wait()
5427 return tt
5428 }
5429
5430
5431 func TestTransportUnusedConnOK(t *testing.T) { synctest.Test(t, testTransportUnusedConnOK) }
5432 func testTransportUnusedConnOK(t *testing.T) {
5433 tt := newTestTransportWithUnusedConn(t)
5434
5435 req := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5436 tc := tt.getConn()
5437 tc.wantFrameType(FrameSettings)
5438 tc.wantFrameType(FrameWindowUpdate)
5439
5440
5441
5442 rt := tt.roundTrip(req)
5443 tc.wantHeaders(wantHeader{
5444 streamID: 1,
5445 endStream: true,
5446 header: http.Header{
5447 ":authority": []string{"dummy.tld"},
5448 ":method": []string{"GET"},
5449 ":path": []string{"/"},
5450 },
5451 })
5452
5453 tc.writeSettings()
5454 tc.writeSettingsAck()
5455 tc.wantFrameType(FrameSettings)
5456
5457 tc.writeHeaders(HeadersFrameParam{
5458 StreamID: 1,
5459 EndHeaders: true,
5460 EndStream: true,
5461 BlockFragment: tc.makeHeaderBlockFragment(
5462 ":status", "200",
5463 ),
5464 })
5465 rt.wantStatus(200)
5466 rt.wantBody(nil)
5467 }
5468
5469
5470 func TestTransportUnusedConnImmediateFailureUsed(t *testing.T) {
5471 synctest.Test(t, testTransportUnusedConnImmediateFailureUsed)
5472 }
5473 func testTransportUnusedConnImmediateFailureUsed(t *testing.T) {
5474 tt := newTestTransportWithUnusedConn(t)
5475
5476
5477 tc1 := tt.getConn()
5478 tc1.closeWrite()
5479
5480
5481
5482
5483 req := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5484 rt := tt.roundTrip(req)
5485 if err := rt.err(); err == nil || errors.Is(err, ErrNoCachedConn) {
5486 t.Fatalf("RoundTrip with broken conn: got %v, want an error other than ErrNoCachedConn", err)
5487 }
5488
5489
5490
5491
5492 _ = tt.roundTrip(req)
5493 tc2 := tt.getConn()
5494 tc2.wantFrameType(FrameSettings)
5495 tc2.wantFrameType(FrameWindowUpdate)
5496 tc2.wantFrameType(FrameHeaders)
5497 }
5498
5499
5500 func TestTransportUnusedConnIdleTimoutBeforeUse(t *testing.T) {
5501 synctest.Test(t, testTransportUnusedConnIdleTimoutBeforeUse)
5502 }
5503 func testTransportUnusedConnIdleTimoutBeforeUse(t *testing.T) {
5504 tt := newTestTransportWithUnusedConn(t, func(t1 *http.Transport) {
5505 t1.IdleConnTimeout = 1 * time.Second
5506 })
5507
5508 _ = tt.getConn()
5509
5510
5511 time.Sleep(2 * time.Second)
5512 synctest.Wait()
5513
5514
5515
5516
5517
5518 req := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5519 _ = tt.roundTrip(req)
5520 tc2 := tt.getConn()
5521 tc2.wantFrameType(FrameSettings)
5522 tc2.wantFrameType(FrameWindowUpdate)
5523 tc2.wantFrameType(FrameHeaders)
5524 }
5525
5526
5527
5528 func TestTransportTLSNextProtoConnImmediateFailureUnused(t *testing.T) {
5529 synctest.Test(t, testTransportTLSNextProtoConnImmediateFailureUnused)
5530 }
5531 func testTransportTLSNextProtoConnImmediateFailureUnused(t *testing.T) {
5532 tt := newTestTransportWithUnusedConn(t, func(t1 *http.Transport) {
5533 t1.IdleConnTimeout = 1 * time.Second
5534 })
5535
5536
5537 tc1 := tt.getConn()
5538 tc1.closeWrite()
5539
5540
5541
5542 time.Sleep(10 * time.Second)
5543
5544
5545
5546
5547 req := Must(http.NewRequest("GET", "https://dummy.tld/", nil))
5548 _ = tt.roundTrip(req)
5549 tc2 := tt.getConn()
5550 tc2.wantFrameType(FrameSettings)
5551 tc2.wantFrameType(FrameWindowUpdate)
5552 tc2.wantFrameType(FrameHeaders)
5553 }
5554
5555 func TestTransportDoNotHangOnZeroMaxFrameSize(t *testing.T) {
5556 synctest.Test(t, testTransportDoNotHangOnZeroMaxFrameSize)
5557 }
5558 func testTransportDoNotHangOnZeroMaxFrameSize(t *testing.T) {
5559 tc := newTestClientConn(t)
5560 tc.writeSettings(Setting{ID: SettingMaxFrameSize, Val: 0})
5561 tc.wantFrameType(FrameSettings)
5562
5563 req, _ := http.NewRequest("POST", "https://dummy.tld/", strings.NewReader("body"))
5564 tc.roundTrip(req)
5565
5566 }
5567
5568 func TestExtendedConnectClientWithServerSupport(t *testing.T) {
5569 t.Skip("https://go.dev/issue/53208 -- net/http needs to support the :protocol header")
5570 SetDisableExtendedConnectProtocol(t, false)
5571 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
5572 if r.Header.Get(":protocol") != "extended-connect" {
5573 t.Fatalf("unexpected :protocol header received")
5574 }
5575 t.Log(io.Copy(w, r.Body))
5576 })
5577 tr := newTransport(t)
5578 pr, pw := io.Pipe()
5579 pwDone := make(chan struct{})
5580 req, _ := http.NewRequest("CONNECT", ts.URL, pr)
5581 req.Header.Set(":protocol", "extended-connect")
5582 req.Header.Set("X-A", "A")
5583 req.Header.Set("X-B", "B")
5584 req.Header.Set("X-C", "C")
5585 go func() {
5586 pw.Write([]byte("hello, extended connect"))
5587 pw.Close()
5588 close(pwDone)
5589 }()
5590
5591 res, err := tr.RoundTrip(req)
5592 if err != nil {
5593 t.Fatal(err)
5594 }
5595 body, err := io.ReadAll(res.Body)
5596 if err != nil {
5597 t.Fatal(err)
5598 }
5599 if !bytes.Equal(body, []byte("hello, extended connect")) {
5600 t.Fatal("unexpected body received")
5601 }
5602 }
5603
5604 func TestExtendedConnectClientWithoutServerSupport(t *testing.T) {
5605 t.Skip("https://go.dev/issue/53208 -- net/http needs to support the :protocol header")
5606 SetDisableExtendedConnectProtocol(t, true)
5607 ts := newTestServer(t, func(w http.ResponseWriter, r *http.Request) {
5608 io.Copy(w, r.Body)
5609 })
5610 tr := newTransport(t)
5611 pr, pw := io.Pipe()
5612 pwDone := make(chan struct{})
5613 req, _ := http.NewRequest("CONNECT", ts.URL, pr)
5614 req.Header.Set(":protocol", "extended-connect")
5615 req.Header.Set("X-A", "A")
5616 req.Header.Set("X-B", "B")
5617 req.Header.Set("X-C", "C")
5618 go func() {
5619 pw.Write([]byte("hello, extended connect"))
5620 pw.Close()
5621 close(pwDone)
5622 }()
5623
5624 _, err := tr.RoundTrip(req)
5625 if !errors.Is(err, ErrExtendedConnectNotSupported) {
5626 t.Fatalf("expected error errExtendedConnectNotSupported, got: %v", err)
5627 }
5628 }
5629
5630
5631
5632 func TestExtendedConnectReadFrameError(t *testing.T) {
5633 synctest.Test(t, testExtendedConnectReadFrameError)
5634 }
5635 func testExtendedConnectReadFrameError(t *testing.T) {
5636 t.Skip("https://go.dev/issue/53208 -- net/http needs to support the :protocol header")
5637 tc := newTestClientConn(t)
5638 tc.wantFrameType(FrameSettings)
5639 tc.wantFrameType(FrameWindowUpdate)
5640
5641 req, _ := http.NewRequest("CONNECT", "https://dummy.tld/", nil)
5642 req.Header.Set(":protocol", "extended-connect")
5643 rt := tc.roundTrip(req)
5644 tc.wantIdle()
5645
5646 tc.closeWrite()
5647 if !rt.done() {
5648 t.Fatalf("after connection closed: RoundTrip still running; want done")
5649 }
5650 if rt.err() == nil {
5651 t.Fatalf("after connection closed: RoundTrip succeeded; want error")
5652 }
5653 }
5654
View as plain text