Source file
src/net/http/transport_test.go
1
2
3
4
5
6
7
8
9
10 package http_test
11
12 import (
13 "bufio"
14 "bytes"
15 "compress/gzip"
16 "context"
17 "crypto/rand"
18 "crypto/tls"
19 "crypto/x509"
20 "encoding/binary"
21 "errors"
22 "fmt"
23 "go/token"
24 "internal/nettest"
25 "internal/nettrace"
26 "io"
27 "log"
28 mrand "math/rand"
29 "net"
30 "net/http"
31 . "net/http"
32 "net/http/httptest"
33 "net/http/httptrace"
34 "net/http/httputil"
35 "net/http/internal/testcert"
36 "net/textproto"
37 "net/url"
38 "os"
39 "path/filepath"
40 "reflect"
41 "runtime"
42 "slices"
43 "strconv"
44 "strings"
45 "sync"
46 "sync/atomic"
47 "testing"
48 "testing/iotest"
49 "testing/synctest"
50 "time"
51
52 "golang.org/x/net/http/httpguts"
53 )
54
55
56
57
58
59 var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
60 if r.FormValue("close") == "true" {
61 w.Header().Set("Connection", "close")
62 }
63 w.Header().Set("X-Saw-Close", fmt.Sprint(r.Close))
64 w.Write([]byte(r.RemoteAddr))
65
66
67
68 if c, ok := ResponseWriterConnForTesting(w); ok {
69 fmt.Fprintf(w, ", %T %p", c, c)
70 }
71 })
72
73
74 type testCloseConn struct {
75 net.Conn
76 set *testConnSet
77 }
78
79 func (c *testCloseConn) Close() error {
80 c.set.remove(c)
81 return c.Conn.Close()
82 }
83
84
85
86 type testConnSet struct {
87 t *testing.T
88 mu sync.Mutex
89 closed map[net.Conn]bool
90 list []net.Conn
91 }
92
93 func (tcs *testConnSet) insert(c net.Conn) {
94 tcs.mu.Lock()
95 defer tcs.mu.Unlock()
96 tcs.closed[c] = false
97 tcs.list = append(tcs.list, c)
98 }
99
100 func (tcs *testConnSet) remove(c net.Conn) {
101 tcs.mu.Lock()
102 defer tcs.mu.Unlock()
103 tcs.closed[c] = true
104 }
105
106
107 func makeTestDial(t *testing.T) (*testConnSet, func(n, addr string) (net.Conn, error)) {
108 connSet := &testConnSet{
109 t: t,
110 closed: make(map[net.Conn]bool),
111 }
112 dial := func(n, addr string) (net.Conn, error) {
113 c, err := net.Dial(n, addr)
114 if err != nil {
115 return nil, err
116 }
117 tc := &testCloseConn{c, connSet}
118 connSet.insert(tc)
119 return tc, nil
120 }
121 return connSet, dial
122 }
123
124 func (tcs *testConnSet) check(t *testing.T) {
125 tcs.mu.Lock()
126 defer tcs.mu.Unlock()
127 for i := 4; i >= 0; i-- {
128 for i, c := range tcs.list {
129 if tcs.closed[c] {
130 continue
131 }
132 if i != 0 {
133
134
135 tcs.mu.Unlock()
136 time.Sleep(50 * time.Millisecond)
137 tcs.mu.Lock()
138 continue
139 }
140 t.Errorf("TCP connection #%d, %p (of %d total) was not closed", i+1, c, len(tcs.list))
141 }
142 }
143 }
144
145 func TestReuseRequest(t *testing.T) { runSynctest(t, testReuseRequest) }
146 func testReuseRequest(t *testing.T, mode testMode) {
147 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
148 w.Write([]byte("{}"))
149 })).ts
150
151 c := ts.Client()
152 req, _ := NewRequest("GET", ts.URL, nil)
153 res, err := c.Do(req)
154 if err != nil {
155 t.Fatal(err)
156 }
157 err = res.Body.Close()
158 if err != nil {
159 t.Fatal(err)
160 }
161
162 res, err = c.Do(req)
163 if err != nil {
164 t.Fatal(err)
165 }
166 err = res.Body.Close()
167 if err != nil {
168 t.Fatal(err)
169 }
170 }
171
172
173
174 func TestTransportKeepAlives(t *testing.T) {
175 runSynctest(t, testTransportKeepAlives, []testMode{http1Mode})
176 }
177 func testTransportKeepAlives(t *testing.T, mode testMode) {
178 ts := newClientServerTest(t, mode, hostPortHandler).ts
179
180 c := ts.Client()
181 for _, disableKeepAlive := range []bool{false, true} {
182 c.Transport.(*Transport).DisableKeepAlives = disableKeepAlive
183 fetch := func(n int) string {
184 res, err := c.Get(ts.URL)
185 if err != nil {
186 t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err)
187 }
188 body, err := io.ReadAll(res.Body)
189 if err != nil {
190 t.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive, n, err)
191 }
192 return string(body)
193 }
194
195 body1 := fetch(1)
196 body2 := fetch(2)
197
198 bodiesDiffer := body1 != body2
199 if bodiesDiffer != disableKeepAlive {
200 t.Errorf("error in disableKeepAlive=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
201 disableKeepAlive, bodiesDiffer, body1, body2)
202 }
203 }
204 }
205
206 func TestTransportConnectionCloseOnResponse(t *testing.T) {
207 runNoSynctest(t, testTransportConnectionCloseOnResponse, http3SkippedMode)
208 }
209 func testTransportConnectionCloseOnResponse(t *testing.T, mode testMode) {
210 ts := newClientServerTest(t, mode, hostPortHandler, optRealNet).ts
211
212 connSet, testDial := makeTestDial(t)
213
214 c := ts.Client()
215 tr := c.Transport.(*Transport)
216 tr.Dial = testDial
217
218 for _, connectionClose := range []bool{false, true} {
219 fetch := func(n int) string {
220 req := new(Request)
221 var err error
222 req.URL, err = url.Parse(ts.URL + fmt.Sprintf("/?close=%v", connectionClose))
223 if err != nil {
224 t.Fatalf("URL parse error: %v", err)
225 }
226 req.Method = "GET"
227 req.Proto = "HTTP/1.1"
228 req.ProtoMajor = 1
229 req.ProtoMinor = 1
230
231 res, err := c.Do(req)
232 if err != nil {
233 t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
234 }
235 defer res.Body.Close()
236 body, err := io.ReadAll(res.Body)
237 if err != nil {
238 t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
239 }
240 return string(body)
241 }
242
243 body1 := fetch(1)
244 body2 := fetch(2)
245 bodiesDiffer := body1 != body2
246 if bodiesDiffer != connectionClose {
247 t.Errorf("error in connectionClose=%v. unexpected bodiesDiffer=%v; body1=%q; body2=%q",
248 connectionClose, bodiesDiffer, body1, body2)
249 }
250
251 tr.CloseIdleConnections()
252 }
253
254 connSet.check(t)
255 }
256
257
258
259
260
261
262
263 func TestTransportConnectionCloseOnRequest(t *testing.T) {
264 runNoSynctest(t, testTransportConnectionCloseOnRequest, []testMode{http1Mode})
265 }
266 func testTransportConnectionCloseOnRequest(t *testing.T, mode testMode) {
267 ts := newClientServerTest(t, mode, hostPortHandler, optRealNet).ts
268
269 connSet, testDial := makeTestDial(t)
270
271 c := ts.Client()
272 tr := c.Transport.(*Transport)
273 tr.Dial = testDial
274 for _, reqClose := range []bool{false, true} {
275 fetch := func(n int) string {
276 req := new(Request)
277 var err error
278 req.URL, err = url.Parse(ts.URL)
279 if err != nil {
280 t.Fatalf("URL parse error: %v", err)
281 }
282 req.Method = "GET"
283 req.Proto = "HTTP/1.1"
284 req.ProtoMajor = 1
285 req.ProtoMinor = 1
286 req.Close = reqClose
287
288 res, err := c.Do(req)
289 if err != nil {
290 t.Fatalf("error in Request.Close=%v, req #%d, Do: %v", reqClose, n, err)
291 }
292 if got, want := res.Header.Get("X-Saw-Close"), fmt.Sprint(reqClose); got != want {
293 t.Errorf("for Request.Close = %v; handler's X-Saw-Close was %v; want %v",
294 reqClose, got, !reqClose)
295 }
296 body, err := io.ReadAll(res.Body)
297 if err != nil {
298 t.Fatalf("for Request.Close=%v, on request %v/2: ReadAll: %v", reqClose, n, err)
299 }
300 return string(body)
301 }
302
303 body1 := fetch(1)
304 body2 := fetch(2)
305
306 got := 1
307 if body1 != body2 {
308 got++
309 }
310 want := 1
311 if reqClose {
312 want = 2
313 }
314 if got != want {
315 t.Errorf("for Request.Close=%v: server saw %v unique connections, wanted %v\n\nbodies were: %q and %q",
316 reqClose, got, want, body1, body2)
317 }
318
319 tr.CloseIdleConnections()
320 }
321
322 connSet.check(t)
323 }
324
325
326
327
328 func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) {
329 runSynctest(t, testTransportConnectionCloseOnRequestDisableKeepAlive, []testMode{http1Mode})
330 }
331 func testTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T, mode testMode) {
332 ts := newClientServerTest(t, mode, hostPortHandler).ts
333
334 c := ts.Client()
335 c.Transport.(*Transport).DisableKeepAlives = true
336
337 res, err := c.Get(ts.URL)
338 if err != nil {
339 t.Fatal(err)
340 }
341 res.Body.Close()
342 if res.Header.Get("X-Saw-Close") != "true" {
343 t.Errorf("handler didn't see Connection: close ")
344 }
345 }
346
347
348
349 func TestTransportRespectRequestWantsClose(t *testing.T) {
350 runNoSynctest(t, testTransportRespectRequestWantsClose, []testMode{http1Mode})
351 }
352 func testTransportRespectRequestWantsClose(t *testing.T, mode testMode) {
353 tests := []struct {
354 disableKeepAlives bool
355 close bool
356 }{
357 {disableKeepAlives: false, close: false},
358 {disableKeepAlives: false, close: true},
359 {disableKeepAlives: true, close: false},
360 {disableKeepAlives: true, close: true},
361 }
362
363 for _, tc := range tests {
364 synctest.Subtest(t, fmt.Sprintf("DisableKeepAlive=%v,RequestClose=%v", tc.disableKeepAlives, tc.close),
365 func(t *testing.T) {
366 ts := newClientServerTest(t, mode, hostPortHandler).ts
367
368 c := ts.Client()
369 c.Transport.(*Transport).DisableKeepAlives = tc.disableKeepAlives
370 req, err := NewRequest("GET", ts.URL, nil)
371 if err != nil {
372 t.Fatal(err)
373 }
374 count := 0
375 trace := &httptrace.ClientTrace{
376 WroteHeaderField: func(key string, field []string) {
377 if key != "Connection" {
378 return
379 }
380 if httpguts.HeaderValuesContainsToken(field, "close") {
381 count += 1
382 }
383 },
384 }
385 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
386 req.Close = tc.close
387 res, err := c.Do(req)
388 if err != nil {
389 t.Fatal(err)
390 }
391 defer res.Body.Close()
392 if want := tc.disableKeepAlives || tc.close; count > 1 || (count == 1) != want {
393 t.Errorf("expecting want:%v, got 'Connection: close':%d", want, count)
394 }
395 })
396 }
397
398 }
399
400 func TestTransportIdleCacheKeys(t *testing.T) {
401 runNoSynctest(t, testTransportIdleCacheKeys, []testMode{http1Mode})
402 }
403 func testTransportIdleCacheKeys(t *testing.T, mode testMode) {
404 ts := newClientServerTest(t, mode, hostPortHandler, optRealNet).ts
405 c := ts.Client()
406 tr := c.Transport.(*Transport)
407
408 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
409 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
410 }
411
412 resp, err := c.Get(ts.URL)
413 if err != nil {
414 t.Error(err)
415 }
416 io.ReadAll(resp.Body)
417
418 keys := tr.IdleConnKeysForTesting()
419 if e, g := 1, len(keys); e != g {
420 t.Fatalf("After Get expected %d idle conn cache keys; got %d", e, g)
421 }
422
423 if e := "|http|" + ts.Listener.Addr().String(); keys[0] != e {
424 t.Errorf("Expected idle cache key %q; got %q", e, keys[0])
425 }
426
427 tr.CloseIdleConnections()
428 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
429 t.Errorf("After CloseIdleConnections expected %d idle conn cache keys; got %d", e, g)
430 }
431 }
432
433
434
435 func TestTransportReadToEndReusesConn(t *testing.T) { runSynctest(t, testTransportReadToEndReusesConn) }
436 func testTransportReadToEndReusesConn(t *testing.T, mode testMode) {
437 const msg = "foobar"
438 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
439 w.Header().Set("Remote-Addr", r.RemoteAddr)
440 if r.URL.Path == "/chunked/" {
441 w.WriteHeader(200)
442 w.(Flusher).Flush()
443 } else {
444 w.Header().Set("Content-Length", strconv.Itoa(len(msg)))
445 w.WriteHeader(200)
446 }
447 w.Write([]byte(msg))
448 })).ts
449
450 for pi, path := range []string{"/content-length/", "/chunked/"} {
451 wantLen := []int{len(msg), -1}[pi]
452 addrSeen := make(map[string]int)
453 for range 3 {
454 res, err := ts.Client().Get(ts.URL + path)
455 if err != nil {
456 t.Errorf("Get %s: %v", path, err)
457 continue
458 }
459 defer res.Body.Close()
460
461 if res.ContentLength != int64(wantLen) {
462 t.Errorf("%s res.ContentLength = %d; want %d", path, res.ContentLength, wantLen)
463 }
464 got, err := io.ReadAll(res.Body)
465 if string(got) != msg || err != nil {
466 t.Errorf("%s ReadAll(Body) = %q, %v; want %q, nil", path, string(got), err, msg)
467 }
468 addrSeen[res.Header.Get("Remote-Addr")]++
469 }
470 if len(addrSeen) != 1 {
471 t.Errorf("for %s, server saw %d distinct client addresses; want 1", path, len(addrSeen))
472 }
473 }
474 }
475
476
477
478
479
480 func TestTransportNotReadToEndConnectionReuse(t *testing.T) {
481 runNoSynctest(t, testTransportNotReadToEndConnectionReuse, []testMode{http1Mode, https1Mode})
482 }
483 func testTransportNotReadToEndConnectionReuse(t *testing.T, mode testMode) {
484 tests := []struct {
485 name string
486 bodyLen int
487 contentLenKnown bool
488 headRequest bool
489 timeBetweenReqs time.Duration
490 responseTime time.Duration
491 wantReuse bool
492 }{
493 {
494 name: "unconsumed body within drain limit",
495 bodyLen: 200 * 1024,
496 timeBetweenReqs: http.MaxPostCloseReadTime,
497 wantReuse: true,
498 },
499 {
500 name: "unconsumed body within drain limit with known length",
501 bodyLen: 200 * 1024,
502 contentLenKnown: true,
503 timeBetweenReqs: http.MaxPostCloseReadTime,
504 wantReuse: true,
505 },
506 {
507 name: "unconsumed body larger than drain limit",
508 bodyLen: 500 * 1024,
509 timeBetweenReqs: http.MaxPostCloseReadTime,
510 wantReuse: false,
511 },
512 {
513 name: "unconsumed body larger than drain limit with known length",
514 bodyLen: 500 * 1024,
515 contentLenKnown: true,
516 timeBetweenReqs: http.MaxPostCloseReadTime,
517 wantReuse: false,
518 },
519 {
520 name: "new requests start before drain for old requests are finished",
521 bodyLen: 200 * 1024,
522 timeBetweenReqs: 0,
523 responseTime: time.Minute,
524 wantReuse: false,
525 },
526 {
527
528
529 name: "unconsumed body larger than drain limit for HEAD request",
530 bodyLen: 500 * 1024,
531 headRequest: true,
532 wantReuse: true,
533 },
534 }
535
536 for _, tc := range tests {
537 subtest := func(t *testing.T) {
538 addrSeen := make(map[string]int)
539 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
540 addrSeen[r.RemoteAddr]++
541 time.Sleep(tc.responseTime)
542 if tc.contentLenKnown {
543 w.Header().Add("Content-Length", strconv.Itoa(tc.bodyLen))
544 }
545 w.Write(slices.Repeat([]byte("a"), tc.bodyLen))
546 })).ts
547
548 var wg sync.WaitGroup
549 for range 10 {
550 wg.Go(func() {
551 method := http.MethodGet
552 if tc.headRequest {
553 method = http.MethodHead
554 }
555 ctx, cancel := context.WithCancel(context.Background())
556 req, err := http.NewRequestWithContext(ctx, method, ts.URL, nil)
557 if err != nil {
558 log.Fatal(err)
559 }
560 resp, err := ts.Client().Do(req)
561 if err != nil {
562 t.Fatal(err)
563 }
564 if resp.StatusCode != http.StatusOK {
565 t.Errorf("expected HTTP 200, got: %v", resp.StatusCode)
566 }
567 resp.Body.Close()
568
569
570 cancel()
571 if n, err := resp.Body.Read([]byte{}); n != 0 || err == nil {
572 t.Errorf("read after body has been closed should not succeed, but read %v byte with %v error", n, err)
573 }
574 })
575 time.Sleep(tc.timeBetweenReqs)
576 synctest.Wait()
577 }
578 wg.Wait()
579 if (len(addrSeen) == 1) != tc.wantReuse {
580 t.Errorf("want connection reuse to be %v, but %v connections were created", tc.wantReuse, len(addrSeen))
581 }
582 }
583 synctest.Subtest(t, tc.name, subtest)
584 }
585 }
586
587 func TestTransportMaxPerHostIdleConns(t *testing.T) {
588 runNoSynctest(t, testTransportMaxPerHostIdleConns, []testMode{http1Mode})
589 }
590 func testTransportMaxPerHostIdleConns(t *testing.T, mode testMode) {
591 stop := make(chan struct{})
592 defer close(stop)
593
594 resch := make(chan string)
595 gotReq := make(chan bool)
596 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
597 gotReq <- true
598 var msg string
599 select {
600 case <-stop:
601 return
602 case msg = <-resch:
603 }
604 _, err := w.Write([]byte(msg))
605 if err != nil {
606 t.Errorf("Write: %v", err)
607 return
608 }
609 }), optRealNet).ts
610
611 c := ts.Client()
612 tr := c.Transport.(*Transport)
613 maxIdleConnsPerHost := 2
614 tr.MaxIdleConnsPerHost = maxIdleConnsPerHost
615
616
617
618 donech := make(chan bool)
619 doReq := func() {
620 defer func() {
621 select {
622 case <-stop:
623 return
624 case donech <- t.Failed():
625 }
626 }()
627 resp, err := c.Get(ts.URL)
628 if err != nil {
629 t.Error(err)
630 return
631 }
632 if _, err := io.ReadAll(resp.Body); err != nil {
633 t.Errorf("ReadAll: %v", err)
634 return
635 }
636 }
637 go doReq()
638 <-gotReq
639 go doReq()
640 <-gotReq
641 go doReq()
642 <-gotReq
643
644 if e, g := 0, len(tr.IdleConnKeysForTesting()); e != g {
645 t.Fatalf("Before writes, expected %d idle conn cache keys; got %d", e, g)
646 }
647
648 resch <- "res1"
649 <-donech
650 keys := tr.IdleConnKeysForTesting()
651 if e, g := 1, len(keys); e != g {
652 t.Fatalf("after first response, expected %d idle conn cache keys; got %d", e, g)
653 }
654 addr := ts.Listener.Addr().String()
655 cacheKey := "|http|" + addr
656 if keys[0] != cacheKey {
657 t.Fatalf("Expected idle cache key %q; got %q", cacheKey, keys[0])
658 }
659 if e, g := 1, tr.IdleConnCountForTesting("http", addr); e != g {
660 t.Errorf("after first response, expected %d idle conns; got %d", e, g)
661 }
662
663 resch <- "res2"
664 <-donech
665 if g, w := tr.IdleConnCountForTesting("http", addr), 2; g != w {
666 t.Errorf("after second response, idle conns = %d; want %d", g, w)
667 }
668
669 resch <- "res3"
670 <-donech
671 if g, w := tr.IdleConnCountForTesting("http", addr), maxIdleConnsPerHost; g != w {
672 t.Errorf("after third response, idle conns = %d; want %d", g, w)
673 }
674 }
675
676 func TestTransportMaxConnsPerHostIncludeDialInProgress(t *testing.T) {
677 runNoSynctest(t, testTransportMaxConnsPerHostIncludeDialInProgress, http3SkippedMode)
678 }
679 func testTransportMaxConnsPerHostIncludeDialInProgress(t *testing.T, mode testMode) {
680 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
681 _, err := w.Write([]byte("foo"))
682 if err != nil {
683 t.Fatalf("Write: %v", err)
684 }
685 }), optRealNet).ts
686 c := ts.Client()
687 tr := c.Transport.(*Transport)
688 dialStarted := make(chan struct{})
689 stallDial := make(chan struct{})
690 tr.Dial = func(network, addr string) (net.Conn, error) {
691 dialStarted <- struct{}{}
692 <-stallDial
693 return net.Dial(network, addr)
694 }
695
696 tr.DisableKeepAlives = true
697 tr.MaxConnsPerHost = 1
698
699 preDial := make(chan struct{})
700 reqComplete := make(chan struct{})
701 doReq := func(reqId string) {
702 req, _ := NewRequest("GET", ts.URL, nil)
703 trace := &httptrace.ClientTrace{
704 GetConn: func(hostPort string) {
705 preDial <- struct{}{}
706 },
707 }
708 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
709 resp, err := tr.RoundTrip(req)
710 if err != nil {
711 t.Errorf("unexpected error for request %s: %v", reqId, err)
712 }
713 _, err = io.ReadAll(resp.Body)
714 if err != nil {
715 t.Errorf("unexpected error for request %s: %v", reqId, err)
716 }
717 reqComplete <- struct{}{}
718 }
719
720 go doReq("req1")
721 <-preDial
722 <-dialStarted
723
724
725 go doReq("req2")
726 <-preDial
727 select {
728 case <-dialStarted:
729 t.Error("req2 dial started while req1 dial in progress")
730 return
731 default:
732 }
733
734
735 stallDial <- struct{}{}
736 <-reqComplete
737
738
739 <-dialStarted
740 stallDial <- struct{}{}
741 <-reqComplete
742 }
743
744 func TestTransportMaxConnsPerHost(t *testing.T) {
745 runNoSynctest(t, testTransportMaxConnsPerHost, []testMode{http1Mode, https1Mode, http2Mode})
746 }
747 func testTransportMaxConnsPerHost(t *testing.T, mode testMode) {
748 CondSkipHTTP2(t)
749
750 h := HandlerFunc(func(w ResponseWriter, r *Request) {
751 _, err := w.Write([]byte("foo"))
752 if err != nil {
753 t.Fatalf("Write: %v", err)
754 }
755 })
756
757 ts := newClientServerTest(t, mode, h, optRealNet).ts
758 c := ts.Client()
759 tr := c.Transport.(*Transport)
760 tr.MaxConnsPerHost = 1
761
762 mu := sync.Mutex{}
763 var conns []net.Conn
764 var dialCnt, gotConnCnt, tlsHandshakeCnt int32
765 tr.Dial = func(network, addr string) (net.Conn, error) {
766 atomic.AddInt32(&dialCnt, 1)
767 c, err := net.Dial(network, addr)
768 mu.Lock()
769 defer mu.Unlock()
770 conns = append(conns, c)
771 return c, err
772 }
773
774 doReq := func() {
775 trace := &httptrace.ClientTrace{
776 GotConn: func(connInfo httptrace.GotConnInfo) {
777 if !connInfo.Reused {
778 atomic.AddInt32(&gotConnCnt, 1)
779 }
780 },
781 TLSHandshakeStart: func() {
782 atomic.AddInt32(&tlsHandshakeCnt, 1)
783 },
784 }
785 req, _ := NewRequest("GET", ts.URL, nil)
786 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
787
788 resp, err := c.Do(req)
789 if err != nil {
790 t.Fatalf("request failed: %v", err)
791 }
792 defer resp.Body.Close()
793 _, err = io.ReadAll(resp.Body)
794 if err != nil {
795 t.Fatalf("read body failed: %v", err)
796 }
797 }
798
799 wg := sync.WaitGroup{}
800 for i := 0; i < 10; i++ {
801 wg.Add(1)
802 go func() {
803 defer wg.Done()
804 doReq()
805 }()
806 }
807 wg.Wait()
808
809 expected := int32(tr.MaxConnsPerHost)
810 if dialCnt != expected {
811 t.Errorf("round 1: too many dials: %d != %d", dialCnt, expected)
812 }
813 if gotConnCnt != expected {
814 t.Errorf("round 1: too many get connections: %d != %d", gotConnCnt, expected)
815 }
816 if ts.TLS != nil && tlsHandshakeCnt != expected {
817 t.Errorf("round 1: too many tls handshakes: %d != %d", tlsHandshakeCnt, expected)
818 }
819
820 if t.Failed() {
821 t.FailNow()
822 }
823
824 mu.Lock()
825 for _, c := range conns {
826 c.Close()
827 }
828 conns = nil
829 mu.Unlock()
830 tr.CloseIdleConnections()
831
832 doReq()
833 expected++
834 if dialCnt != expected {
835 t.Errorf("round 2: too many dials: %d", dialCnt)
836 }
837 if gotConnCnt != expected {
838 t.Errorf("round 2: too many get connections: %d != %d", gotConnCnt, expected)
839 }
840 if ts.TLS != nil && tlsHandshakeCnt != expected {
841 t.Errorf("round 2: too many tls handshakes: %d != %d", tlsHandshakeCnt, expected)
842 }
843 }
844
845 func TestTransportMaxConnsPerHostDialCancellation(t *testing.T) {
846 runSynctest(t, testTransportMaxConnsPerHostDialCancellation,
847 testNotParallel,
848 []testMode{http1Mode, https1Mode, http2Mode},
849 )
850 }
851
852 func testTransportMaxConnsPerHostDialCancellation(t *testing.T, mode testMode) {
853 CondSkipHTTP2(t)
854
855 h := HandlerFunc(func(w ResponseWriter, r *Request) {
856 _, err := w.Write([]byte("foo"))
857 if err != nil {
858 t.Fatalf("Write: %v", err)
859 }
860 })
861
862 cst := newClientServerTest(t, mode, h)
863 defer cst.close()
864 ts := cst.ts
865 c := ts.Client()
866 tr := c.Transport.(*Transport)
867 tr.MaxConnsPerHost = 1
868
869
870 ctx, cancel := context.WithCancel(context.Background())
871 defer cancel()
872 SetPendingDialHooks(t, cancel, nil)
873
874 req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil)
875 _, err := c.Do(req)
876 if !errors.Is(err, context.Canceled) {
877 t.Errorf("expected error %v, got %v", context.Canceled, err)
878 }
879
880
881 SetPendingDialHooks(t, nil, nil)
882 req, _ = NewRequest("GET", ts.URL, nil)
883 resp, err := c.Do(req)
884 if err != nil {
885 t.Fatalf("request failed: %v", err)
886 }
887 defer resp.Body.Close()
888 _, err = io.ReadAll(resp.Body)
889 if err != nil {
890 t.Fatalf("read body failed: %v", err)
891 }
892 }
893
894 func TestTransportRemovesDeadIdleConnections(t *testing.T) {
895 runSynctest(t, testTransportRemovesDeadIdleConnections, []testMode{http1Mode})
896 }
897 func testTransportRemovesDeadIdleConnections(t *testing.T, mode testMode) {
898 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
899 io.WriteString(w, r.RemoteAddr)
900 })).ts
901
902 c := ts.Client()
903 tr := c.Transport.(*Transport)
904
905 doReq := func(name string) {
906
907
908 res, err := c.Post(ts.URL, "", nil)
909 if err != nil {
910 t.Fatalf("%s: %v", name, err)
911 }
912 if res.StatusCode != 200 {
913 t.Fatalf("%s: %v", name, res.Status)
914 }
915 defer res.Body.Close()
916 slurp, err := io.ReadAll(res.Body)
917 if err != nil {
918 t.Fatalf("%s: %v", name, err)
919 }
920 t.Logf("%s: ok (%q)", name, slurp)
921 }
922
923 doReq("first")
924 keys1 := tr.IdleConnKeysForTesting()
925
926 ts.CloseClientConnections()
927
928 var keys2 []string
929 waitCondition(t, 10*time.Millisecond, func(d time.Duration) bool {
930 keys2 = tr.IdleConnKeysForTesting()
931 if len(keys2) != 0 {
932 if d > 0 {
933 t.Logf("Transport hasn't noticed idle connection's death in %v.\nbefore: %q\n after: %q\n", d, keys1, keys2)
934 }
935 return false
936 }
937 return true
938 })
939
940 doReq("second")
941 }
942
943
944
945 func TestTransportServerClosingUnexpectedly(t *testing.T) {
946 runSynctest(t, testTransportServerClosingUnexpectedly, []testMode{http1Mode})
947 }
948 func testTransportServerClosingUnexpectedly(t *testing.T, mode testMode) {
949 ts := newClientServerTest(t, mode, hostPortHandler).ts
950 c := ts.Client()
951
952 fetch := func(n, retries int) string {
953 condFatalf := func(format string, arg ...any) {
954 if retries <= 0 {
955 t.Fatalf(format, arg...)
956 }
957 t.Logf("retrying shortly after expected error: "+format, arg...)
958 time.Sleep(time.Second / time.Duration(retries))
959 }
960 for retries >= 0 {
961 retries--
962 res, err := c.Get(ts.URL)
963 if err != nil {
964 condFatalf("error in req #%d, GET: %v", n, err)
965 continue
966 }
967 body, err := io.ReadAll(res.Body)
968 if err != nil {
969 condFatalf("error in req #%d, ReadAll: %v", n, err)
970 continue
971 }
972 res.Body.Close()
973 return string(body)
974 }
975 panic("unreachable")
976 }
977
978 body1 := fetch(1, 0)
979 body2 := fetch(2, 0)
980
981
982
983
984
985
986
987
988 ExportCloseTransportConnsAbruptly(c.Transport.(*Transport))
989
990 body3 := fetch(3, 5)
991
992 if body1 != body2 {
993 t.Errorf("expected body1 and body2 to be equal")
994 }
995 if body2 == body3 {
996 t.Errorf("expected body2 and body3 to be different")
997 }
998 }
999
1000
1001
1002 func TestStressSurpriseServerCloses(t *testing.T) {
1003 runSynctest(t, testStressSurpriseServerCloses, []testMode{http1Mode})
1004 }
1005 func testStressSurpriseServerCloses(t *testing.T, mode testMode) {
1006 if testing.Short() {
1007 t.Skip("skipping test in short mode")
1008 }
1009 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1010 w.Header().Set("Content-Length", "5")
1011 w.Header().Set("Content-Type", "text/plain")
1012 w.Write([]byte("Hello"))
1013 w.(Flusher).Flush()
1014 conn, buf, _ := w.(Hijacker).Hijack()
1015 buf.Flush()
1016 conn.Close()
1017 })).ts
1018 c := ts.Client()
1019
1020
1021
1022
1023
1024
1025
1026 const (
1027 numClients = 20
1028 reqsPerClient = 25
1029 )
1030 var wg sync.WaitGroup
1031 wg.Add(numClients * reqsPerClient)
1032 for i := 0; i < numClients; i++ {
1033 go func() {
1034 for i := 0; i < reqsPerClient; i++ {
1035 res, err := c.Get(ts.URL)
1036 if err == nil {
1037
1038
1039
1040
1041
1042
1043 res.Body.Close()
1044 }
1045 wg.Done()
1046 }
1047 }()
1048 }
1049
1050
1051 wg.Wait()
1052 }
1053
1054
1055
1056 func TestTransportHeadResponses(t *testing.T) { runSynctest(t, testTransportHeadResponses) }
1057 func testTransportHeadResponses(t *testing.T, mode testMode) {
1058 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1059 if r.Method != "HEAD" {
1060 panic("expected HEAD; got " + r.Method)
1061 }
1062 w.Header().Set("Content-Length", "123")
1063 w.WriteHeader(200)
1064 })).ts
1065 c := ts.Client()
1066
1067 for i := 0; i < 2; i++ {
1068 res, err := c.Head(ts.URL)
1069 if err != nil {
1070 t.Errorf("error on loop %d: %v", i, err)
1071 continue
1072 }
1073 if e, g := "123", res.Header.Get("Content-Length"); e != g {
1074 t.Errorf("loop %d: expected Content-Length header of %q, got %q", i, e, g)
1075 }
1076 if e, g := int64(123), res.ContentLength; e != g {
1077 t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g)
1078 }
1079 if all, err := io.ReadAll(res.Body); err != nil {
1080 t.Errorf("loop %d: Body ReadAll: %v", i, err)
1081 } else if len(all) != 0 {
1082 t.Errorf("Bogus body %q", all)
1083 }
1084 }
1085 }
1086
1087
1088
1089 func TestTransportHeadChunkedResponse(t *testing.T) {
1090 runSynctest(t, testTransportHeadChunkedResponse, []testMode{http1Mode}, testNotParallel)
1091 }
1092 func testTransportHeadChunkedResponse(t *testing.T, mode testMode) {
1093 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
1094 if r.Method != "HEAD" {
1095 panic("expected HEAD; got " + r.Method)
1096 }
1097 w.Header().Set("Transfer-Encoding", "chunked")
1098 w.Header().Set("x-client-ipport", r.RemoteAddr)
1099 w.WriteHeader(200)
1100 })).ts
1101 c := ts.Client()
1102
1103
1104
1105 didRead := make(chan bool)
1106 SetReadLoopBeforeNextReadHook(func() { didRead <- true })
1107 defer SetReadLoopBeforeNextReadHook(nil)
1108
1109 res1, err := c.Head(ts.URL)
1110 <-didRead
1111
1112 if err != nil {
1113 t.Fatalf("request 1 error: %v", err)
1114 }
1115
1116 res2, err := c.Head(ts.URL)
1117 <-didRead
1118
1119 if err != nil {
1120 t.Fatalf("request 2 error: %v", err)
1121 }
1122 if v1, v2 := res1.Header.Get("x-client-ipport"), res2.Header.Get("x-client-ipport"); v1 != v2 {
1123 t.Errorf("ip/ports differed between head requests: %q vs %q", v1, v2)
1124 }
1125 }
1126
1127 var roundTripTests = []struct {
1128 accept string
1129 expectAccept string
1130 compressed bool
1131 }{
1132
1133 {"", "gzip", false},
1134
1135 {"foo", "foo", false},
1136
1137 {"gzip", "gzip", true},
1138 }
1139
1140
1141 func TestRoundTripGzip(t *testing.T) { runSynctest(t, testRoundTripGzip) }
1142 func testRoundTripGzip(t *testing.T, mode testMode) {
1143 const responseBody = "test response body"
1144 ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
1145 accept := req.Header.Get("Accept-Encoding")
1146 if expect := req.FormValue("expect_accept"); accept != expect {
1147 t.Errorf("in handler, test %v: Accept-Encoding = %q, want %q",
1148 req.FormValue("testnum"), accept, expect)
1149 }
1150 if accept == "gzip" {
1151 rw.Header().Set("Content-Encoding", "gzip")
1152 gz := gzip.NewWriter(rw)
1153 gz.Write([]byte(responseBody))
1154 gz.Close()
1155 } else {
1156 rw.Header().Set("Content-Encoding", accept)
1157 rw.Write([]byte(responseBody))
1158 }
1159 })).ts
1160 tr := ts.Client().Transport.(*Transport)
1161
1162 for i, test := range roundTripTests {
1163
1164 req, _ := NewRequest("GET", fmt.Sprintf("%s/?testnum=%d&expect_accept=%s", ts.URL, i, test.expectAccept), nil)
1165 if test.accept != "" {
1166 req.Header.Set("Accept-Encoding", test.accept)
1167 }
1168 res, err := tr.RoundTrip(req)
1169 if err != nil {
1170 t.Errorf("%d. RoundTrip: %v", i, err)
1171 continue
1172 }
1173 var body []byte
1174 if test.compressed {
1175 var r *gzip.Reader
1176 r, err = gzip.NewReader(res.Body)
1177 if err != nil {
1178 t.Errorf("%d. gzip NewReader: %v", i, err)
1179 continue
1180 }
1181 body, err = io.ReadAll(r)
1182 res.Body.Close()
1183 } else {
1184 body, err = io.ReadAll(res.Body)
1185 }
1186 if err != nil {
1187 t.Errorf("%d. Error: %q", i, err)
1188 continue
1189 }
1190 if g, e := string(body), responseBody; g != e {
1191 t.Errorf("%d. body = %q; want %q", i, g, e)
1192 }
1193 if g, e := req.Header.Get("Accept-Encoding"), test.accept; g != e {
1194 t.Errorf("%d. Accept-Encoding = %q; want %q (it was mutated, in violation of RoundTrip contract)", i, g, e)
1195 }
1196 if g, e := res.Header.Get("Content-Encoding"), test.accept; g != e {
1197 t.Errorf("%d. Content-Encoding = %q; want %q", i, g, e)
1198 }
1199 }
1200
1201 }
1202
1203 func TestTransportGzip(t *testing.T) { runSynctest(t, testTransportGzip) }
1204 func testTransportGzip(t *testing.T, mode testMode) {
1205 const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
1206 const nRandBytes = 1024 * 1024
1207 ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
1208 if req.Method == "HEAD" {
1209 if g := req.Header.Get("Accept-Encoding"); g != "" {
1210 t.Errorf("HEAD request sent with Accept-Encoding of %q; want none", g)
1211 }
1212 return
1213 }
1214 if g, e := req.Header.Get("Accept-Encoding"), "gzip"; g != e {
1215 t.Errorf("Accept-Encoding = %q, want %q", g, e)
1216 }
1217 rw.Header().Set("Content-Encoding", "gzip")
1218
1219 var w io.Writer = rw
1220 var buf bytes.Buffer
1221 if req.FormValue("chunked") == "0" {
1222 w = &buf
1223 defer io.Copy(rw, &buf)
1224 defer func() {
1225 rw.Header().Set("Content-Length", strconv.Itoa(buf.Len()))
1226 }()
1227 }
1228 gz := gzip.NewWriter(w)
1229 gz.Write([]byte(testString))
1230 if req.FormValue("body") == "large" {
1231 io.CopyN(gz, rand.Reader, nRandBytes)
1232 }
1233 gz.Close()
1234 })).ts
1235 c := ts.Client()
1236
1237 for _, chunked := range []string{"1", "0"} {
1238
1239 res, err := c.Get(ts.URL + "/?body=large&chunked=" + chunked)
1240 if err != nil {
1241 t.Fatalf("large get: %v", err)
1242 }
1243 buf := make([]byte, len(testString))
1244 n, err := io.ReadFull(res.Body, buf)
1245 if err != nil {
1246 t.Fatalf("partial read of large response: size=%d, %v", n, err)
1247 }
1248 if e, g := testString, string(buf); e != g {
1249 t.Errorf("partial read got %q, expected %q", g, e)
1250 }
1251 res.Body.Close()
1252
1253 n, err = res.Body.Read(buf)
1254 if n != 0 || err == nil {
1255 t.Errorf("expected error post-closed large Read; got = %d, %v", n, err)
1256 }
1257
1258
1259 res, err = c.Get(ts.URL + "/?chunked=" + chunked)
1260 if err != nil {
1261 t.Fatal(err)
1262 }
1263 body, err := io.ReadAll(res.Body)
1264 if err != nil {
1265 t.Fatal(err)
1266 }
1267 if g, e := string(body), testString; g != e {
1268 t.Fatalf("body = %q; want %q", g, e)
1269 }
1270 if g, e := res.Header.Get("Content-Encoding"), ""; g != e {
1271 t.Fatalf("Content-Encoding = %q; want %q", g, e)
1272 }
1273
1274
1275 n, err = res.Body.Read(buf)
1276 if n != 0 || err == nil {
1277 t.Errorf("expected Read error after exhausted reads; got %d, %v", n, err)
1278 }
1279 res.Body.Close()
1280 n, err = res.Body.Read(buf)
1281 if n != 0 || err == nil {
1282 t.Errorf("expected Read error after Close; got %d, %v", n, err)
1283 }
1284 }
1285
1286
1287 res, err := c.Head(ts.URL)
1288 if err != nil {
1289 t.Fatalf("Head: %v", err)
1290 }
1291 if res.StatusCode != 200 {
1292 t.Errorf("Head status=%d; want=200", res.StatusCode)
1293 }
1294 }
1295
1296
1297
1298 type transport100ContinueTest struct {
1299 t *testing.T
1300
1301 reqdone chan struct{}
1302 resp *Response
1303 respErr error
1304
1305 conn net.Conn
1306 reader *bufio.Reader
1307 }
1308
1309 const transport100ContinueTestBody = "request body"
1310
1311
1312
1313 func newTransport100ContinueTest(t *testing.T, timeout time.Duration) *transport100ContinueTest {
1314 ln := newLocalListener(t)
1315 defer ln.Close()
1316
1317 test := &transport100ContinueTest{
1318 t: t,
1319 reqdone: make(chan struct{}),
1320 }
1321
1322 tr := &Transport{
1323 ExpectContinueTimeout: timeout,
1324 }
1325 go func() {
1326 defer close(test.reqdone)
1327 body := strings.NewReader(transport100ContinueTestBody)
1328 req, _ := NewRequest("PUT", "http://"+ln.Addr().String(), body)
1329 req.Header.Set("Expect", "100-continue")
1330 req.ContentLength = int64(len(transport100ContinueTestBody))
1331 test.resp, test.respErr = tr.RoundTrip(req)
1332 test.resp.Body.Close()
1333 }()
1334
1335 c, err := ln.Accept()
1336 if err != nil {
1337 t.Fatalf("Accept: %v", err)
1338 }
1339 t.Cleanup(func() {
1340 c.Close()
1341 })
1342 br := bufio.NewReader(c)
1343 _, err = ReadRequest(br)
1344 if err != nil {
1345 t.Fatalf("ReadRequest: %v", err)
1346 }
1347 test.conn = c
1348 test.reader = br
1349 t.Cleanup(func() {
1350 <-test.reqdone
1351 tr.CloseIdleConnections()
1352 got, _ := io.ReadAll(test.reader)
1353 if len(got) > 0 {
1354 t.Fatalf("Transport sent unexpected bytes: %q", got)
1355 }
1356 })
1357
1358 return test
1359 }
1360
1361
1362 func (test *transport100ContinueTest) respond(lines ...string) {
1363 for _, line := range lines {
1364 if _, err := test.conn.Write([]byte(line + "\r\n")); err != nil {
1365 test.t.Fatalf("Write: %v", err)
1366 }
1367 }
1368 if _, err := test.conn.Write([]byte("\r\n")); err != nil {
1369 test.t.Fatalf("Write: %v", err)
1370 }
1371 }
1372
1373
1374 func (test *transport100ContinueTest) wantBodySent() {
1375 got, err := io.ReadAll(io.LimitReader(test.reader, int64(len(transport100ContinueTestBody))))
1376 if err != nil {
1377 test.t.Fatalf("unexpected error reading body: %v", err)
1378 }
1379 if got, want := string(got), transport100ContinueTestBody; got != want {
1380 test.t.Fatalf("unexpected body: got %q, want %q", got, want)
1381 }
1382 }
1383
1384
1385 func (test *transport100ContinueTest) wantRequestDone(want int) {
1386 <-test.reqdone
1387 if test.respErr != nil {
1388 test.t.Fatalf("unexpected RoundTrip error: %v", test.respErr)
1389 }
1390 if got := test.resp.StatusCode; got != want {
1391 test.t.Fatalf("unexpected response code: got %v, want %v", got, want)
1392 }
1393 }
1394
1395 func TestTransportExpect100ContinueSent(t *testing.T) {
1396 test := newTransport100ContinueTest(t, 1*time.Hour)
1397
1398 test.respond("HTTP/1.1 100 Continue")
1399 test.wantBodySent()
1400 test.respond("HTTP/1.1 200", "Content-Length: 0")
1401 test.wantRequestDone(200)
1402 }
1403
1404 func TestTransportExpect100Continue200ResponseNoConnClose(t *testing.T) {
1405 test := newTransport100ContinueTest(t, 1*time.Hour)
1406
1407 test.respond("HTTP/1.1 200", "Content-Length: 0")
1408 test.wantBodySent()
1409 test.wantRequestDone(200)
1410 }
1411
1412 func TestTransportExpect100Continue200ResponseWithConnClose(t *testing.T) {
1413 test := newTransport100ContinueTest(t, 1*time.Hour)
1414
1415 test.respond("HTTP/1.1 200", "Connection: close", "Content-Length: 0")
1416 test.wantRequestDone(200)
1417 }
1418
1419 func TestTransportExpect100Continue500ResponseNoConnClose(t *testing.T) {
1420 test := newTransport100ContinueTest(t, 1*time.Hour)
1421
1422 test.respond("HTTP/1.1 500", "Content-Length: 0")
1423 test.wantBodySent()
1424 test.wantRequestDone(500)
1425 }
1426
1427 func TestTransportExpect100Continue500ResponseTimeout(t *testing.T) {
1428 test := newTransport100ContinueTest(t, 5*time.Millisecond)
1429 test.wantBodySent()
1430 test.respond("HTTP/1.1 200", "Content-Length: 0")
1431 test.wantRequestDone(200)
1432 }
1433
1434 func TestSOCKS5Proxy(t *testing.T) {
1435 runNoSynctest(t, testSOCKS5Proxy, []testMode{http1Mode, https1Mode, http2Mode})
1436 }
1437 func testSOCKS5Proxy(t *testing.T, mode testMode) {
1438 ch := make(chan string, 1)
1439 l := newLocalListener(t)
1440 defer l.Close()
1441 defer close(ch)
1442 proxy := func(t *testing.T) {
1443 s, err := l.Accept()
1444 if err != nil {
1445 t.Errorf("socks5 proxy Accept(): %v", err)
1446 return
1447 }
1448 defer s.Close()
1449 var buf [22]byte
1450 if _, err := io.ReadFull(s, buf[:3]); err != nil {
1451 t.Errorf("socks5 proxy initial read: %v", err)
1452 return
1453 }
1454 if want := []byte{5, 1, 0}; !bytes.Equal(buf[:3], want) {
1455 t.Errorf("socks5 proxy initial read: got %v, want %v", buf[:3], want)
1456 return
1457 }
1458 if _, err := s.Write([]byte{5, 0}); err != nil {
1459 t.Errorf("socks5 proxy initial write: %v", err)
1460 return
1461 }
1462 if _, err := io.ReadFull(s, buf[:4]); err != nil {
1463 t.Errorf("socks5 proxy second read: %v", err)
1464 return
1465 }
1466 if want := []byte{5, 1, 0}; !bytes.Equal(buf[:3], want) {
1467 t.Errorf("socks5 proxy second read: got %v, want %v", buf[:3], want)
1468 return
1469 }
1470 var ipLen int
1471 switch buf[3] {
1472 case 1:
1473 ipLen = net.IPv4len
1474 case 4:
1475 ipLen = net.IPv6len
1476 default:
1477 t.Errorf("socks5 proxy second read: unexpected address type %v", buf[4])
1478 return
1479 }
1480 if _, err := io.ReadFull(s, buf[4:ipLen+6]); err != nil {
1481 t.Errorf("socks5 proxy address read: %v", err)
1482 return
1483 }
1484 ip := net.IP(buf[4 : ipLen+4])
1485 port := binary.BigEndian.Uint16(buf[ipLen+4 : ipLen+6])
1486 copy(buf[:3], []byte{5, 0, 0})
1487 if _, err := s.Write(buf[:ipLen+6]); err != nil {
1488 t.Errorf("socks5 proxy connect write: %v", err)
1489 return
1490 }
1491 ch <- fmt.Sprintf("proxy for %s:%d", ip, port)
1492
1493
1494 targetHost := net.JoinHostPort(ip.String(), strconv.Itoa(int(port)))
1495 targetConn, err := net.Dial("tcp", targetHost)
1496 if err != nil {
1497 t.Errorf("net.Dial failed")
1498 return
1499 }
1500 go io.Copy(targetConn, s)
1501 io.Copy(s, targetConn)
1502 targetConn.Close()
1503 }
1504
1505 pu, err := url.Parse("socks5://" + l.Addr().String())
1506 if err != nil {
1507 t.Fatal(err)
1508 }
1509
1510 sentinelHeader := "X-Sentinel"
1511 sentinelValue := "12345"
1512 h := HandlerFunc(func(w ResponseWriter, r *Request) {
1513 w.Header().Set(sentinelHeader, sentinelValue)
1514 })
1515 for _, useTLS := range []bool{false, true} {
1516 t.Run(fmt.Sprintf("useTLS=%v", useTLS), func(t *testing.T) {
1517 ts := newClientServerTest(t, mode, h, optRealNet).ts
1518 go proxy(t)
1519 c := ts.Client()
1520 c.Transport.(*Transport).Proxy = ProxyURL(pu)
1521 r, err := c.Head(ts.URL)
1522 if err != nil {
1523 t.Fatal(err)
1524 }
1525 if r.Header.Get(sentinelHeader) != sentinelValue {
1526 t.Errorf("Failed to retrieve sentinel value")
1527 }
1528 got := <-ch
1529 ts.Close()
1530 tsu, err := url.Parse(ts.URL)
1531 if err != nil {
1532 t.Fatal(err)
1533 }
1534 want := "proxy for " + tsu.Host
1535 if got != want {
1536 t.Errorf("got %q, want %q", got, want)
1537 }
1538 })
1539 }
1540 }
1541
1542 func TestTransportProxy(t *testing.T) {
1543 testCases := []struct{ siteMode, proxyMode testMode }{
1544 {http1Mode, http1Mode},
1545 {http1Mode, https1Mode},
1546 {https1Mode, http1Mode},
1547 {https1Mode, https1Mode},
1548 }
1549 for _, testCase := range testCases {
1550 siteMode := testCase.siteMode
1551 proxyMode := testCase.proxyMode
1552 t.Run(fmt.Sprintf("site=%v/proxy=%v", siteMode, proxyMode), func(t *testing.T) {
1553 siteCh := make(chan *Request, 1)
1554 h1 := HandlerFunc(func(w ResponseWriter, r *Request) {
1555 siteCh <- r
1556 })
1557 proxyCh := make(chan *Request, 1)
1558 h2 := HandlerFunc(func(w ResponseWriter, r *Request) {
1559 proxyCh <- r
1560
1561 if r.Method == "CONNECT" {
1562 hijacker, ok := w.(Hijacker)
1563 if !ok {
1564 t.Errorf("hijack not allowed")
1565 return
1566 }
1567 clientConn, _, err := hijacker.Hijack()
1568 if err != nil {
1569 t.Errorf("hijacking failed")
1570 return
1571 }
1572 res := &Response{
1573 StatusCode: StatusOK,
1574 Proto: "HTTP/1.1",
1575 ProtoMajor: 1,
1576 ProtoMinor: 1,
1577 Header: make(Header),
1578 }
1579
1580 targetConn, err := net.Dial("tcp", r.URL.Host)
1581 if err != nil {
1582 t.Errorf("net.Dial(%q) failed: %v", r.URL.Host, err)
1583 return
1584 }
1585
1586 if err := res.Write(clientConn); err != nil {
1587 t.Errorf("Writing 200 OK failed: %v", err)
1588 return
1589 }
1590
1591 go io.Copy(targetConn, clientConn)
1592 go func() {
1593 io.Copy(clientConn, targetConn)
1594 targetConn.Close()
1595 }()
1596 }
1597 })
1598 ts := newClientServerTest(t, siteMode, h1, optRealNet).ts
1599 proxy := newClientServerTest(t, proxyMode, h2, optRealNet).ts
1600
1601 pu, err := url.Parse(proxy.URL)
1602 if err != nil {
1603 t.Fatal(err)
1604 }
1605
1606
1607
1608
1609 c := proxy.Client()
1610 if siteMode == https1Mode {
1611 c = ts.Client()
1612 }
1613
1614 c.Transport.(*Transport).Proxy = ProxyURL(pu)
1615 if _, err := c.Head(ts.URL); err != nil {
1616 t.Error(err)
1617 }
1618 got := <-proxyCh
1619 c.Transport.(*Transport).CloseIdleConnections()
1620 ts.Close()
1621 proxy.Close()
1622 if siteMode == https1Mode {
1623
1624 if got.Method != "CONNECT" {
1625 t.Errorf("Wrong method for secure proxying: %q", got.Method)
1626 }
1627 gotHost := got.URL.Host
1628 pu, err := url.Parse(ts.URL)
1629 if err != nil {
1630 t.Fatal("Invalid site URL")
1631 }
1632 if wantHost := pu.Host; gotHost != wantHost {
1633 t.Errorf("Got CONNECT host %q, want %q", gotHost, wantHost)
1634 }
1635
1636
1637 next := <-siteCh
1638 if next.Method != "HEAD" {
1639 t.Errorf("Wrong method at destination: %s", next.Method)
1640 }
1641 if nextURL := next.URL.String(); nextURL != "/" {
1642 t.Errorf("Wrong URL at destination: %s", nextURL)
1643 }
1644 } else {
1645 if got.Method != "HEAD" {
1646 t.Errorf("Wrong method for destination: %q", got.Method)
1647 }
1648 gotURL := got.URL.String()
1649 wantURL := ts.URL + "/"
1650 if gotURL != wantURL {
1651 t.Errorf("Got URL %q, want %q", gotURL, wantURL)
1652 }
1653 }
1654 })
1655 }
1656 }
1657
1658
1659
1660
1661 func TestProxyWithInfiniteHeader(t *testing.T) {
1662 ln := newLocalListener(t)
1663 defer ln.Close()
1664 cancelc := make(chan struct{})
1665 defer close(cancelc)
1666
1667
1668
1669 go func() {
1670 c, err := ln.Accept()
1671 if err != nil {
1672 t.Errorf("Accept: %v", err)
1673 return
1674 }
1675 defer c.Close()
1676
1677 br := bufio.NewReader(c)
1678 cr, err := ReadRequest(br)
1679 if err != nil {
1680 t.Errorf("proxy server failed to read CONNECT request")
1681 return
1682 }
1683 if cr.Method != "CONNECT" {
1684 t.Errorf("unexpected method %q", cr.Method)
1685 return
1686 }
1687
1688
1689 for {
1690
1691
1692
1693 runtime.Gosched()
1694 select {
1695 case <-cancelc:
1696 return
1697 default:
1698 c.Write([]byte("infinite stream of bytes"))
1699 }
1700 }
1701 }()
1702
1703 c := &Client{
1704 Transport: &Transport{
1705 Proxy: func(*Request) (*url.URL, error) {
1706 return url.Parse("http://" + ln.Addr().String())
1707 },
1708
1709 MaxResponseHeaderBytes: 1024,
1710 },
1711 }
1712 req, err := NewRequest("GET", "https://golang.fake.tld/", nil)
1713 if err != nil {
1714 t.Fatal(err)
1715 }
1716 _, err = c.Do(req)
1717 if err == nil {
1718 t.Errorf("unexpected Get success")
1719 }
1720 }
1721
1722 func TestOnProxyConnectResponse(t *testing.T) {
1723
1724 var tcases = []struct {
1725 proxyStatusCode int
1726 err error
1727 }{
1728 {
1729 StatusOK,
1730 nil,
1731 },
1732 {
1733 StatusForbidden,
1734 errors.New("403"),
1735 },
1736 }
1737 for _, tcase := range tcases {
1738 h1 := HandlerFunc(func(w ResponseWriter, r *Request) {
1739
1740 })
1741
1742 h2 := HandlerFunc(func(w ResponseWriter, r *Request) {
1743
1744 if r.Method == "CONNECT" {
1745 if tcase.proxyStatusCode != StatusOK {
1746 w.WriteHeader(tcase.proxyStatusCode)
1747 return
1748 }
1749 hijacker, ok := w.(Hijacker)
1750 if !ok {
1751 t.Errorf("hijack not allowed")
1752 return
1753 }
1754 clientConn, _, err := hijacker.Hijack()
1755 if err != nil {
1756 t.Errorf("hijacking failed")
1757 return
1758 }
1759 res := &Response{
1760 StatusCode: StatusOK,
1761 Proto: "HTTP/1.1",
1762 ProtoMajor: 1,
1763 ProtoMinor: 1,
1764 Header: make(Header),
1765 }
1766
1767 targetConn, err := net.Dial("tcp", r.URL.Host)
1768 if err != nil {
1769 t.Errorf("net.Dial(%q) failed: %v", r.URL.Host, err)
1770 return
1771 }
1772
1773 if err := res.Write(clientConn); err != nil {
1774 t.Errorf("Writing 200 OK failed: %v", err)
1775 return
1776 }
1777
1778 go io.Copy(targetConn, clientConn)
1779 go func() {
1780 io.Copy(clientConn, targetConn)
1781 targetConn.Close()
1782 }()
1783 }
1784 })
1785 ts := newClientServerTest(t, https1Mode, h1, optRealNet).ts
1786 proxy := newClientServerTest(t, https1Mode, h2, optRealNet).ts
1787
1788 pu, err := url.Parse(proxy.URL)
1789 if err != nil {
1790 t.Fatal(err)
1791 }
1792
1793 c := proxy.Client()
1794
1795 var (
1796 dials atomic.Int32
1797 closes atomic.Int32
1798 )
1799 c.Transport.(*Transport).DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
1800 conn, err := net.Dial(network, addr)
1801 if err != nil {
1802 return nil, err
1803 }
1804 dials.Add(1)
1805 return noteCloseConn{
1806 Conn: conn,
1807 closeFunc: func() {
1808 closes.Add(1)
1809 },
1810 }, nil
1811 }
1812
1813 c.Transport.(*Transport).Proxy = ProxyURL(pu)
1814 c.Transport.(*Transport).OnProxyConnectResponse = func(ctx context.Context, proxyURL *url.URL, connectReq *Request, connectRes *Response) error {
1815 if proxyURL.String() != pu.String() {
1816 t.Errorf("proxy url got %s, want %s", proxyURL, pu)
1817 }
1818
1819 if "https://"+connectReq.URL.String() != ts.URL {
1820 t.Errorf("connect url got %s, want %s", connectReq.URL, ts.URL)
1821 }
1822 return tcase.err
1823 }
1824 wantCloses := int32(0)
1825 if _, err := c.Head(ts.URL); err != nil {
1826 wantCloses = 1
1827 if tcase.err != nil && !strings.Contains(err.Error(), tcase.err.Error()) {
1828 t.Errorf("got %v, want %v", err, tcase.err)
1829 }
1830 } else {
1831 if tcase.err != nil {
1832 t.Errorf("got %v, want nil", err)
1833 }
1834 }
1835 if got, want := dials.Load(), int32(1); got != want {
1836 t.Errorf("got %v dials, want %v", got, want)
1837 }
1838
1839 if got, want := closes.Load(), wantCloses; got != want {
1840 t.Errorf("got %v closes, want %v", got, want)
1841 }
1842 }
1843 }
1844
1845
1846
1847 func TestTransportProxyHTTPSConnectLeak(t *testing.T) {
1848 cancelc := make(chan struct{})
1849 SetTestHookProxyConnectTimeout(t, func(ctx context.Context, timeout time.Duration) (context.Context, context.CancelFunc) {
1850 ctx, cancel := context.WithCancel(ctx)
1851 go func() {
1852 select {
1853 case <-cancelc:
1854 case <-ctx.Done():
1855 }
1856 cancel()
1857 }()
1858 return ctx, cancel
1859 })
1860
1861 ln := newLocalListener(t)
1862 defer ln.Close()
1863 listenerDone := make(chan struct{})
1864 go func() {
1865 defer close(listenerDone)
1866 c, err := ln.Accept()
1867 if err != nil {
1868 t.Errorf("Accept: %v", err)
1869 return
1870 }
1871 defer c.Close()
1872
1873 br := bufio.NewReader(c)
1874 cr, err := ReadRequest(br)
1875 if err != nil {
1876 t.Errorf("proxy server failed to read CONNECT request")
1877 return
1878 }
1879 if cr.Method != "CONNECT" {
1880 t.Errorf("unexpected method %q", cr.Method)
1881 return
1882 }
1883
1884
1885
1886
1887 close(cancelc)
1888 var buf [1]byte
1889 _, err = br.Read(buf[:])
1890 if err != io.EOF {
1891 t.Errorf("proxy server Read err = %v; want EOF", err)
1892 }
1893 return
1894 }()
1895
1896 c := &Client{
1897 Transport: &Transport{
1898 Proxy: func(*Request) (*url.URL, error) {
1899 return url.Parse("http://" + ln.Addr().String())
1900 },
1901 },
1902 }
1903 req, err := NewRequest("GET", "https://golang.fake.tld/", nil)
1904 if err != nil {
1905 t.Fatal(err)
1906 }
1907 _, err = c.Do(req)
1908 if err == nil {
1909 t.Errorf("unexpected Get success")
1910 }
1911
1912
1913
1914
1915 <-listenerDone
1916 }
1917
1918
1919 func TestTransportDialPreservesNetOpProxyError(t *testing.T) {
1920 var errDial = errors.New("some dial error")
1921
1922 tr := &Transport{
1923 Proxy: func(*Request) (*url.URL, error) {
1924 return url.Parse("http://proxy.fake.tld/")
1925 },
1926 Dial: func(string, string) (net.Conn, error) {
1927 return nil, errDial
1928 },
1929 }
1930 defer tr.CloseIdleConnections()
1931
1932 c := &Client{Transport: tr}
1933 req, _ := NewRequest("GET", "http://fake.tld", nil)
1934 res, err := c.Do(req)
1935 if err == nil {
1936 res.Body.Close()
1937 t.Fatal("wanted a non-nil error")
1938 }
1939
1940 uerr, ok := err.(*url.Error)
1941 if !ok {
1942 t.Fatalf("got %T, want *url.Error", err)
1943 }
1944 oe, ok := uerr.Err.(*net.OpError)
1945 if !ok {
1946 t.Fatalf("url.Error.Err = %T; want *net.OpError", uerr.Err)
1947 }
1948 want := &net.OpError{
1949 Op: "proxyconnect",
1950 Net: "tcp",
1951 Err: errDial,
1952 }
1953 if !reflect.DeepEqual(oe, want) {
1954 t.Errorf("Got error %#v; want %#v", oe, want)
1955 }
1956 }
1957
1958
1959
1960
1961
1962 func TestTransportProxyDialDoesNotMutateProxyConnectHeader(t *testing.T) {
1963 runSynctest(t, testTransportProxyDialDoesNotMutateProxyConnectHeader, http3SkippedMode)
1964 }
1965 func testTransportProxyDialDoesNotMutateProxyConnectHeader(t *testing.T, mode testMode) {
1966 proxy := newClientServerTest(t, mode, NotFoundHandler()).ts
1967 defer proxy.Close()
1968 c := proxy.Client()
1969
1970 tr := c.Transport.(*Transport)
1971 tr.Proxy = func(*Request) (*url.URL, error) {
1972 u, _ := url.Parse(proxy.URL)
1973 u.User = url.UserPassword("aladdin", "opensesame")
1974 return u, nil
1975 }
1976 h := tr.ProxyConnectHeader
1977 if h == nil {
1978 h = make(Header)
1979 }
1980 tr.ProxyConnectHeader = h.Clone()
1981
1982 req, err := NewRequest("GET", "https://golang.fake.tld/", nil)
1983 if err != nil {
1984 t.Fatal(err)
1985 }
1986 _, err = c.Do(req)
1987 if err == nil {
1988 t.Errorf("unexpected Get success")
1989 }
1990
1991 if !reflect.DeepEqual(tr.ProxyConnectHeader, h) {
1992 t.Errorf("tr.ProxyConnectHeader = %v; want %v", tr.ProxyConnectHeader, h)
1993 }
1994 }
1995
1996
1997
1998
1999
2000 func TestTransportGzipRecursive(t *testing.T) { runSynctest(t, testTransportGzipRecursive) }
2001 func testTransportGzipRecursive(t *testing.T, mode testMode) {
2002 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2003 w.Header().Set("Content-Encoding", "gzip")
2004 w.Write(rgz)
2005 })).ts
2006
2007 c := ts.Client()
2008 res, err := c.Get(ts.URL)
2009 if err != nil {
2010 t.Fatal(err)
2011 }
2012 body, err := io.ReadAll(res.Body)
2013 if err != nil {
2014 t.Fatal(err)
2015 }
2016 if !bytes.Equal(body, rgz) {
2017 t.Fatalf("Incorrect result from recursive gz:\nhave=%x\nwant=%x",
2018 body, rgz)
2019 }
2020 if g, e := res.Header.Get("Content-Encoding"), ""; g != e {
2021 t.Fatalf("Content-Encoding = %q; want %q", g, e)
2022 }
2023 }
2024
2025
2026
2027 func TestTransportGzipShort(t *testing.T) { runSynctest(t, testTransportGzipShort) }
2028 func testTransportGzipShort(t *testing.T, mode testMode) {
2029 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2030 w.Header().Set("Content-Encoding", "gzip")
2031 w.Write([]byte{0x1f, 0x8b})
2032 })).ts
2033
2034 c := ts.Client()
2035 res, err := c.Get(ts.URL)
2036 if err != nil {
2037 t.Fatal(err)
2038 }
2039 defer res.Body.Close()
2040 _, err = io.ReadAll(res.Body)
2041 if err == nil {
2042 t.Fatal("Expect an error from reading a body.")
2043 }
2044 if err != io.ErrUnexpectedEOF {
2045 t.Errorf("ReadAll error = %v; want io.ErrUnexpectedEOF", err)
2046 }
2047 }
2048
2049
2050 func waitNumGoroutine(nmax int) int {
2051 nfinal := runtime.NumGoroutine()
2052 for ntries := 10; ntries > 0 && nfinal > nmax; ntries-- {
2053 time.Sleep(50 * time.Millisecond)
2054 runtime.GC()
2055 nfinal = runtime.NumGoroutine()
2056 }
2057 return nfinal
2058 }
2059
2060
2061 func TestTransportPersistConnLeak(t *testing.T) {
2062 runSynctest(t, testTransportPersistConnLeak, testNotParallel)
2063 }
2064 func testTransportPersistConnLeak(t *testing.T, mode testMode) {
2065 if mode == http2Mode || mode == http3Mode {
2066 t.Skip("flaky in HTTP/2 and HTTP/3")
2067 }
2068
2069
2070 const numReq = 25
2071 gotReqCh := make(chan bool, numReq)
2072 unblockCh := make(chan bool, numReq)
2073 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2074 gotReqCh <- true
2075 <-unblockCh
2076 w.Header().Set("Content-Length", "0")
2077 w.WriteHeader(204)
2078 })).ts
2079 c := ts.Client()
2080 tr := c.Transport.(*Transport)
2081
2082 n0 := runtime.NumGoroutine()
2083
2084 didReqCh := make(chan bool, numReq)
2085 failed := make(chan bool, numReq)
2086 for i := 0; i < numReq; i++ {
2087 go func() {
2088 res, err := c.Get(ts.URL)
2089 didReqCh <- true
2090 if err != nil {
2091 t.Logf("client fetch error: %v", err)
2092 failed <- true
2093 return
2094 }
2095 res.Body.Close()
2096 }()
2097 }
2098
2099
2100 for i := 0; i < numReq; i++ {
2101 select {
2102 case <-gotReqCh:
2103
2104 case <-failed:
2105
2106
2107 }
2108 }
2109
2110 nhigh := runtime.NumGoroutine()
2111
2112
2113 close(unblockCh)
2114
2115
2116 for i := 0; i < numReq; i++ {
2117 <-didReqCh
2118 }
2119
2120 tr.CloseIdleConnections()
2121 nfinal := waitNumGoroutine(n0 + 5)
2122
2123 growth := nfinal - n0
2124
2125
2126
2127 if int(growth) > 5 {
2128 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
2129 t.Error("too many new goroutines")
2130 }
2131 }
2132
2133
2134
2135 func TestTransportPersistConnLeakShortBody(t *testing.T) {
2136 runNoSynctest(t, testTransportPersistConnLeakShortBody, testNotParallel)
2137 }
2138 func testTransportPersistConnLeakShortBody(t *testing.T, mode testMode) {
2139 if mode == http2Mode || mode == http3Mode {
2140 t.Skip("flaky in HTTP/2 and HTTP/3")
2141 }
2142
2143
2144 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2145 })).ts
2146 c := ts.Client()
2147 tr := c.Transport.(*Transport)
2148
2149 n0 := runtime.NumGoroutine()
2150 body := []byte("Hello")
2151 for i := 0; i < 20; i++ {
2152 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body))
2153 if err != nil {
2154 t.Fatal(err)
2155 }
2156 req.ContentLength = int64(len(body) - 2)
2157 _, err = c.Do(req)
2158 if err == nil {
2159 t.Fatal("Expect an error from writing too long of a body.")
2160 }
2161 }
2162 nhigh := runtime.NumGoroutine()
2163 tr.CloseIdleConnections()
2164 nfinal := waitNumGoroutine(n0 + 5)
2165
2166 growth := nfinal - n0
2167
2168
2169
2170 t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
2171 if int(growth) > 5 {
2172 t.Error("too many new goroutines")
2173 }
2174 }
2175
2176
2177 type countedConn struct {
2178 net.Conn
2179 }
2180
2181
2182 type countingDialer struct {
2183 dialer net.Dialer
2184 mu sync.Mutex
2185 total, live int64
2186 }
2187
2188 func (d *countingDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
2189 conn, err := d.dialer.DialContext(ctx, network, address)
2190 if err != nil {
2191 return nil, err
2192 }
2193
2194 counted := new(countedConn)
2195 counted.Conn = conn
2196
2197 d.mu.Lock()
2198 defer d.mu.Unlock()
2199 d.total++
2200 d.live++
2201
2202 runtime.AddCleanup(counted, func(dd *countingDialer) { dd.decrement(nil) }, d)
2203 return counted, nil
2204 }
2205
2206 func (d *countingDialer) decrement(*countedConn) {
2207 d.mu.Lock()
2208 defer d.mu.Unlock()
2209 d.live--
2210 }
2211
2212 func (d *countingDialer) Read() (total, live int64) {
2213 d.mu.Lock()
2214 defer d.mu.Unlock()
2215 return d.total, d.live
2216 }
2217
2218 func TestTransportPersistConnLeakNeverIdle(t *testing.T) {
2219 runNoSynctest(t, testTransportPersistConnLeakNeverIdle, []testMode{http1Mode})
2220 }
2221 func testTransportPersistConnLeakNeverIdle(t *testing.T, mode testMode) {
2222 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2223
2224 conn, _, err := w.(Hijacker).Hijack()
2225 if err != nil {
2226 t.Errorf("Hijack failed unexpectedly: %v", err)
2227 return
2228 }
2229 conn.Close()
2230 }), optRealNet).ts
2231
2232 var d countingDialer
2233 c := ts.Client()
2234 c.Transport.(*Transport).DialContext = d.DialContext
2235
2236 body := []byte("Hello")
2237 for i := 0; ; i++ {
2238 total, live := d.Read()
2239 if live < total {
2240 break
2241 }
2242 if i >= 1<<12 {
2243 t.Fatalf("Count of live client net.Conns (%d) not lower than total (%d) after %d Do / GC iterations.", live, total, i)
2244 }
2245
2246 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body))
2247 if err != nil {
2248 t.Fatal(err)
2249 }
2250 _, err = c.Do(req)
2251 if err == nil {
2252 t.Fatal("expected broken connection")
2253 }
2254
2255 runtime.GC()
2256 }
2257 }
2258
2259 type countedContext struct {
2260 context.Context
2261 }
2262
2263 type contextCounter struct {
2264 mu sync.Mutex
2265 live int64
2266 }
2267
2268 func (cc *contextCounter) Track(ctx context.Context) context.Context {
2269 counted := new(countedContext)
2270 counted.Context = ctx
2271 cc.mu.Lock()
2272 defer cc.mu.Unlock()
2273 cc.live++
2274 runtime.AddCleanup(counted, func(c *contextCounter) { cc.decrement(nil) }, cc)
2275 return counted
2276 }
2277
2278 func (cc *contextCounter) decrement(*countedContext) {
2279 cc.mu.Lock()
2280 defer cc.mu.Unlock()
2281 cc.live--
2282 }
2283
2284 func (cc *contextCounter) Read() (live int64) {
2285 cc.mu.Lock()
2286 defer cc.mu.Unlock()
2287 return cc.live
2288 }
2289
2290 func TestTransportPersistConnContextLeakMaxConnsPerHost(t *testing.T) {
2291 runSynctest(t, testTransportPersistConnContextLeakMaxConnsPerHost, http3SkippedMode)
2292 }
2293 func testTransportPersistConnContextLeakMaxConnsPerHost(t *testing.T, mode testMode) {
2294 if mode == http2Mode {
2295 t.Skip("https://go.dev/issue/56021")
2296 }
2297
2298 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2299 runtime.Gosched()
2300 w.WriteHeader(StatusOK)
2301 })).ts
2302
2303 c := ts.Client()
2304 c.Transport.(*Transport).MaxConnsPerHost = 1
2305
2306 ctx := context.Background()
2307 body := []byte("Hello")
2308 doPosts := func(cc *contextCounter) {
2309 var wg sync.WaitGroup
2310 for n := 64; n > 0; n-- {
2311 wg.Add(1)
2312 go func() {
2313 defer wg.Done()
2314
2315 ctx := cc.Track(ctx)
2316 req, err := NewRequest("POST", ts.URL, bytes.NewReader(body))
2317 if err != nil {
2318 t.Error(err)
2319 }
2320
2321 _, err = c.Do(req.WithContext(ctx))
2322 if err != nil {
2323 t.Errorf("Do failed with error: %v", err)
2324 }
2325 }()
2326 }
2327 wg.Wait()
2328 }
2329
2330 var initialCC contextCounter
2331 doPosts(&initialCC)
2332
2333
2334
2335
2336 var flushCC contextCounter
2337 for i := 0; ; i++ {
2338 live := initialCC.Read()
2339 if live == 0 {
2340 break
2341 }
2342 if i >= 100 {
2343 t.Fatalf("%d Contexts still not finalized after %d GC cycles.", live, i)
2344 }
2345 doPosts(&flushCC)
2346 runtime.GC()
2347 }
2348 }
2349
2350
2351 func TestTransportIdleConnCrash(t *testing.T) {
2352 runSynctest(t, testTransportIdleConnCrash, http3SkippedMode)
2353 }
2354 func testTransportIdleConnCrash(t *testing.T, mode testMode) {
2355 var tr *Transport
2356
2357 unblockCh := make(chan bool, 1)
2358 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2359 <-unblockCh
2360 tr.CloseIdleConnections()
2361 })).ts
2362 c := ts.Client()
2363 tr = c.Transport.(*Transport)
2364
2365 didreq := make(chan bool)
2366 go func() {
2367 res, err := c.Get(ts.URL)
2368 if err != nil {
2369 t.Error(err)
2370 } else {
2371 res.Body.Close()
2372 }
2373 didreq <- true
2374 }()
2375 unblockCh <- true
2376 <-didreq
2377 }
2378
2379
2380
2381
2382
2383 func TestIssue3644(t *testing.T) { runSynctest(t, testIssue3644) }
2384 func testIssue3644(t *testing.T, mode testMode) {
2385 const numFoos = 5000
2386 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2387 w.Header().Set("Connection", "close")
2388 for i := 0; i < numFoos; i++ {
2389 w.Write([]byte("foo "))
2390 }
2391 })).ts
2392 c := ts.Client()
2393 res, err := c.Get(ts.URL)
2394 if err != nil {
2395 t.Fatal(err)
2396 }
2397 defer res.Body.Close()
2398 bs, err := io.ReadAll(res.Body)
2399 if err != nil {
2400 t.Fatal(err)
2401 }
2402 if len(bs) != numFoos*len("foo ") {
2403 t.Errorf("unexpected response length")
2404 }
2405 }
2406
2407
2408
2409 func TestIssue3595(t *testing.T) { runSynctest(t, testIssue3595) }
2410 func testIssue3595(t *testing.T, mode testMode) {
2411 const deniedMsg = "sorry, denied."
2412 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2413 Error(w, deniedMsg, StatusUnauthorized)
2414 }))
2415 ts := cst.ts
2416 c := ts.Client()
2417
2418 cst.setDialNettestHook(func(nc *nettest.Conn) {
2419 nc.Peer().SetReadBufferSize(1000)
2420 })
2421
2422 res, err := c.Post(ts.URL, "application/octet-stream", neverEnding('a'))
2423 if err != nil {
2424 t.Fatalf("Post: %v", err)
2425 }
2426 got, err := io.ReadAll(res.Body)
2427 if err != nil {
2428 t.Fatalf("Body ReadAll: %v", err)
2429 }
2430 t.Logf("server response:\n%s", got)
2431 if !strings.Contains(string(got), deniedMsg) {
2432 t.Errorf("response %q does not contain %q", got, deniedMsg)
2433 }
2434 }
2435
2436
2437
2438 func TestChunkedNoContent(t *testing.T) { runSynctest(t, testChunkedNoContent) }
2439 func testChunkedNoContent(t *testing.T, mode testMode) {
2440 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2441 w.WriteHeader(StatusNoContent)
2442 })).ts
2443
2444 c := ts.Client()
2445 for _, closeBody := range []bool{true, false} {
2446 const n = 4
2447 for i := 1; i <= n; i++ {
2448 res, err := c.Get(ts.URL)
2449 if err != nil {
2450 t.Errorf("closingBody=%v, req %d/%d: %v", closeBody, i, n, err)
2451 } else {
2452 if closeBody {
2453 res.Body.Close()
2454 }
2455 }
2456 }
2457 }
2458 }
2459
2460 func TestTransportConcurrency(t *testing.T) {
2461 runSynctest(t, testTransportConcurrency, testNotParallel, []testMode{http1Mode})
2462 }
2463 func testTransportConcurrency(t *testing.T, mode testMode) {
2464
2465 maxProcs, numReqs := 16, 500
2466 if testing.Short() {
2467 maxProcs, numReqs = 4, 50
2468 }
2469 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
2470 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2471 fmt.Fprintf(w, "%v", r.FormValue("echo"))
2472 })).ts
2473
2474 var wg sync.WaitGroup
2475 wg.Add(numReqs)
2476
2477
2478
2479
2480
2481
2482
2483 SetPendingDialHooks(t, func() { wg.Add(1) }, wg.Done)
2484
2485 c := ts.Client()
2486 reqs := make(chan string)
2487 defer close(reqs)
2488
2489 for i := 0; i < maxProcs*2; i++ {
2490 go func() {
2491 for req := range reqs {
2492 res, err := c.Get(ts.URL + "/?echo=" + req)
2493 if err != nil {
2494 if runtime.GOOS == "netbsd" && strings.HasSuffix(err.Error(), ": connection reset by peer") {
2495
2496
2497 t.Logf("error on req %s: %v", req, err)
2498 t.Logf("(see https://go.dev/issue/52168)")
2499 } else {
2500 t.Errorf("error on req %s: %v", req, err)
2501 }
2502 wg.Done()
2503 continue
2504 }
2505 all, err := io.ReadAll(res.Body)
2506 if err != nil {
2507 t.Errorf("read error on req %s: %v", req, err)
2508 } else if string(all) != req {
2509 t.Errorf("body of req %s = %q; want %q", req, all, req)
2510 }
2511 res.Body.Close()
2512 wg.Done()
2513 }
2514 }()
2515 }
2516 for i := 0; i < numReqs; i++ {
2517 reqs <- fmt.Sprintf("request-%d", i)
2518 }
2519 wg.Wait()
2520 }
2521
2522 func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
2523 runSynctest(t, testIssue4191_InfiniteGetTimeout, http3SkippedMode)
2524 }
2525 func testIssue4191_InfiniteGetTimeout(t *testing.T, mode testMode) {
2526 mux := NewServeMux()
2527 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
2528 w.Write([]byte("a"))
2529 NewResponseController(w).Flush()
2530 <-r.Context().Done()
2531 })
2532 cst := newClientServerTest(t, mode, mux)
2533
2534 cst.setDialNettestHook(func(c *nettest.Conn) {
2535 c.SetDeadline(time.Now().Add(1 * time.Millisecond))
2536 })
2537
2538 res, err := cst.c.Get(cst.ts.URL + "/get")
2539 if err != nil {
2540 t.Fatalf("Error issuing GET: %v", err)
2541 }
2542 defer res.Body.Close()
2543
2544 _, err = io.Copy(io.Discard, res.Body)
2545 if err == nil {
2546 t.Errorf("Unexpected successful copy")
2547 }
2548 }
2549
2550 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
2551 runSynctest(t, testIssue4191_InfiniteGetToPutTimeout, []testMode{http1Mode})
2552 }
2553 func testIssue4191_InfiniteGetToPutTimeout(t *testing.T, mode testMode) {
2554 mux := NewServeMux()
2555 mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
2556 w.Write([]byte("a"))
2557 NewResponseController(w).Flush()
2558 <-r.Context().Done()
2559 })
2560 mux.HandleFunc("/put", func(w ResponseWriter, r *Request) {
2561 defer r.Body.Close()
2562 io.Copy(io.Discard, r.Body)
2563 })
2564 cst := newClientServerTest(t, mode, mux)
2565
2566 var getConn *nettest.Conn
2567 cst.setDialNettestHook(func(c *nettest.Conn) {
2568 if getConn == nil {
2569 getConn = c
2570 }
2571 })
2572
2573 sres, err := cst.c.Get(cst.ts.URL + "/get")
2574 if err != nil {
2575 t.Fatalf("Error issuing GET: %v", err)
2576 }
2577
2578 getConn.SetDeadline(time.Now().Add(5 * time.Millisecond))
2579
2580 req, err := NewRequestWithContext(t.Context(), "PUT", cst.ts.URL+"/put", sres.Body)
2581 if err != nil {
2582 sres.Body.Close()
2583 t.Fatalf("NewRequest: %v", err)
2584 }
2585 _, err = cst.c.Do(req)
2586 sres.Body.Close()
2587 if err == nil {
2588 t.Errorf("Unexpected successful PUT")
2589 }
2590 }
2591
2592 func TestTransportResponseHeaderTimeout(t *testing.T) {
2593 runSynctest(t, testTransportResponseHeaderTimeout, http3SkippedMode)
2594 }
2595 func testTransportResponseHeaderTimeout(t *testing.T, mode testMode) {
2596 timeout := 2 * time.Millisecond
2597 retry := true
2598 for retry && !t.Failed() {
2599 var srvWG sync.WaitGroup
2600 inHandler := make(chan bool, 1)
2601 mux := NewServeMux()
2602 mux.HandleFunc("/fast", func(w ResponseWriter, r *Request) {
2603 inHandler <- true
2604 srvWG.Done()
2605 })
2606 mux.HandleFunc("/slow", func(w ResponseWriter, r *Request) {
2607 inHandler <- true
2608 <-r.Context().Done()
2609 srvWG.Done()
2610 })
2611 ts := newClientServerTest(t, mode, mux).ts
2612
2613 c := ts.Client()
2614 c.Transport.(*Transport).ResponseHeaderTimeout = timeout
2615
2616 retry = false
2617 srvWG.Add(3)
2618 tests := []struct {
2619 path string
2620 wantTimeout bool
2621 }{
2622 {path: "/fast"},
2623 {path: "/slow", wantTimeout: true},
2624 {path: "/fast"},
2625 }
2626 for i, tt := range tests {
2627 req, _ := NewRequest("GET", ts.URL+tt.path, nil)
2628 req = req.WithT(t)
2629 res, err := c.Do(req)
2630 <-inHandler
2631 if err != nil {
2632 uerr, ok := err.(*url.Error)
2633 if !ok {
2634 t.Errorf("error is not a url.Error; got: %#v", err)
2635 continue
2636 }
2637 nerr, ok := uerr.Err.(net.Error)
2638 if !ok {
2639 t.Errorf("error does not satisfy net.Error interface; got: %#v", err)
2640 continue
2641 }
2642 if !nerr.Timeout() {
2643 t.Errorf("want timeout error; got: %q", nerr)
2644 continue
2645 }
2646 if !tt.wantTimeout {
2647 if !retry {
2648
2649 t.Logf("unexpected timeout for path %q after %v; retrying with longer timeout", tt.path, timeout)
2650 timeout *= 2
2651 retry = true
2652 }
2653 }
2654 if !strings.Contains(err.Error(), "timeout awaiting response headers") {
2655 t.Errorf("%d. unexpected error: %v", i, err)
2656 }
2657 continue
2658 }
2659 if tt.wantTimeout {
2660 t.Errorf(`no error for path %q; expected "timeout awaiting response headers"`, tt.path)
2661 continue
2662 }
2663 if res.StatusCode != 200 {
2664 t.Errorf("%d for path %q status = %d; want 200", i, tt.path, res.StatusCode)
2665 }
2666 }
2667
2668 srvWG.Wait()
2669 ts.Close()
2670 }
2671 }
2672
2673
2674 type cancelTest struct {
2675 mode testMode
2676 newReq func(req *Request) *Request
2677 cancel func(tr *Transport, req *Request)
2678 checkErr func(when string, err error)
2679 }
2680
2681
2682 func runCancelTestChannel(t *testing.T, mode testMode, f func(t *testing.T, test cancelTest)) {
2683 cancelc := make(chan struct{})
2684 cancelOnce := sync.OnceFunc(func() { close(cancelc) })
2685 f(t, cancelTest{
2686 mode: mode,
2687 newReq: func(req *Request) *Request {
2688 req.Cancel = cancelc
2689 return req
2690 },
2691 cancel: func(tr *Transport, req *Request) {
2692 cancelOnce()
2693 },
2694 checkErr: func(when string, err error) {
2695 if !errors.Is(err, ExportErrRequestCanceled) && !errors.Is(err, ExportErrRequestCanceledConn) {
2696 t.Errorf("%v error = %v, want errRequestCanceled or errRequestCanceledConn", when, err)
2697 }
2698 },
2699 })
2700 }
2701
2702
2703 func runCancelTestContext(t *testing.T, mode testMode, f func(t *testing.T, test cancelTest)) {
2704 ctx, cancel := context.WithCancel(context.Background())
2705 f(t, cancelTest{
2706 mode: mode,
2707 newReq: func(req *Request) *Request {
2708 return req.WithContext(ctx)
2709 },
2710 cancel: func(tr *Transport, req *Request) {
2711 cancel()
2712 },
2713 checkErr: func(when string, err error) {
2714 if !errors.Is(err, context.Canceled) {
2715 t.Errorf("%v error = %v, want context.Canceled", when, err)
2716 }
2717 },
2718 })
2719 }
2720
2721 func runCancelTest(t *testing.T, f func(t *testing.T, test cancelTest), opts ...any) {
2722 runNoSynctest(t, func(t *testing.T, mode testMode) {
2723 synctest.Subtest(t, "RequestCancel", func(t *testing.T) {
2724 if mode == http3Mode {
2725 t.Skip("Request.Cancel not supported for HTTP/3")
2726 }
2727 runCancelTestChannel(t, mode, f)
2728 })
2729 synctest.Subtest(t, "ContextCancel", func(t *testing.T) {
2730 runCancelTestContext(t, mode, f)
2731 })
2732 }, opts...)
2733 }
2734
2735 func TestTransportCancelRequest(t *testing.T) {
2736 runCancelTest(t, testTransportCancelRequest)
2737 }
2738 func testTransportCancelRequest(t *testing.T, test cancelTest) {
2739 const msg = "Hello"
2740 unblockc := make(chan bool)
2741 cst := newClientServerTest(t, test.mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2742 io.WriteString(w, msg)
2743 w.(Flusher).Flush()
2744 <-unblockc
2745 }))
2746 defer close(unblockc)
2747
2748 conn, err := cst.tr.NewClientConn(t.Context(), test.mode.Scheme(), "example.tld:80")
2749 if err != nil {
2750 t.Fatal(err)
2751 }
2752 defer conn.Close()
2753
2754 req, _ := NewRequest("GET", cst.ts.URL, nil)
2755 req = test.newReq(req)
2756 res, err := conn.RoundTrip(req)
2757 if err != nil {
2758 t.Fatal(err)
2759 }
2760 body := make([]byte, len(msg))
2761 n, _ := io.ReadFull(res.Body, body)
2762 if n != len(body) || !bytes.Equal(body, []byte(msg)) {
2763 t.Errorf("Body = %q; want %q", body[:n], msg)
2764 }
2765 synctest.Wait()
2766 if got, want := conn.InFlight(), 1; got != want {
2767 t.Fatalf("Before cancel: InFlight = %v, want %v", got, want)
2768 }
2769 test.cancel(cst.tr, req)
2770
2771 tail, err := io.ReadAll(res.Body)
2772 res.Body.Close()
2773 test.checkErr("Body.Read", err)
2774 if len(tail) > 0 {
2775 t.Errorf("Spurious bytes from Body.Read: %q", tail)
2776 }
2777
2778 synctest.Wait()
2779 if got, want := conn.InFlight(), 0; got != want {
2780 t.Fatalf("After cancel: InFlight = %v, want %v", got, want)
2781 }
2782 }
2783
2784 func testTransportCancelRequestInDo(t *testing.T, test cancelTest, body io.Reader) {
2785 unblockc := make(chan bool)
2786 ts := newClientServerTest(t, test.mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2787 <-unblockc
2788 })).ts
2789 defer close(unblockc)
2790
2791 c := ts.Client()
2792 tr := c.Transport.(*Transport)
2793
2794 req, _ := NewRequest("GET", ts.URL, body)
2795 req = test.newReq(req)
2796 done := false
2797 go func() {
2798 c.Do(req)
2799 done = true
2800 }()
2801 synctest.Wait()
2802 test.cancel(tr, req)
2803 synctest.Wait()
2804 if !done {
2805 t.Errorf("Do of canceled request has not returned")
2806 }
2807 }
2808
2809 func TestTransportCancelRequestInDo(t *testing.T) {
2810 runCancelTest(t, func(t *testing.T, test cancelTest) {
2811 testTransportCancelRequestInDo(t, test, nil)
2812 })
2813 }
2814
2815 func TestTransportCancelRequestWithBodyInDo(t *testing.T) {
2816 runCancelTest(t, func(t *testing.T, test cancelTest) {
2817 testTransportCancelRequestInDo(t, test, bytes.NewBuffer([]byte{0}))
2818 })
2819 }
2820
2821 func TestTransportCancelRequestInDial(t *testing.T) {
2822 runCancelTest(t, testTransportCancelRequestInDial)
2823 }
2824 func testTransportCancelRequestInDial(t *testing.T, test cancelTest) {
2825 var logbuf strings.Builder
2826 eventLog := log.New(&logbuf, "", 0)
2827
2828 unblockDial := make(chan bool)
2829 defer close(unblockDial)
2830
2831 inDial := make(chan bool)
2832 tr := &Transport{
2833 Dial: func(network, addr string) (net.Conn, error) {
2834 eventLog.Println("dial: blocking")
2835 if !<-inDial {
2836 return nil, errors.New("main Test goroutine exited")
2837 }
2838 <-unblockDial
2839 return nil, errors.New("nope")
2840 },
2841 }
2842 cl := &Client{Transport: tr}
2843 gotres := false
2844 req, _ := NewRequest("GET", "http://something.no-network.tld/", nil)
2845 req = test.newReq(req)
2846 go func() {
2847 _, err := cl.Do(req)
2848 eventLog.Printf("Get error = %v", err != nil)
2849 test.checkErr("Get", err)
2850 gotres = true
2851 }()
2852
2853 inDial <- true
2854
2855 eventLog.Printf("canceling")
2856 test.cancel(tr, req)
2857 test.cancel(tr, req)
2858
2859 synctest.Wait()
2860 if !gotres {
2861 t.Errorf("after cancel, Do has not returned")
2862 }
2863 got := logbuf.String()
2864 want := `dial: blocking
2865 canceling
2866 Get error = true
2867 `
2868 if got != want {
2869 t.Errorf("Got events:\n%s\nWant:\n%s", got, want)
2870 }
2871 }
2872
2873
2874 func TestTransportCancelRequestWithBody(t *testing.T) {
2875 runCancelTest(t, testTransportCancelRequestWithBody)
2876 }
2877 func testTransportCancelRequestWithBody(t *testing.T, test cancelTest) {
2878 const msg = "Hello"
2879 unblockc := make(chan struct{})
2880 cst := newClientServerTest(t, test.mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2881 io.WriteString(w, msg)
2882 w.(Flusher).Flush()
2883 <-unblockc
2884 }))
2885 defer close(unblockc)
2886
2887 conn, err := cst.tr.NewClientConn(t.Context(), test.mode.Scheme(), "example.tld:80")
2888 if err != nil {
2889 t.Fatal(err)
2890 }
2891 defer conn.Close()
2892
2893 req, _ := NewRequest("POST", cst.ts.URL, strings.NewReader("withbody"))
2894 req = test.newReq(req)
2895
2896 res, err := conn.RoundTrip(req)
2897 if err != nil {
2898 t.Fatal(err)
2899 }
2900 body := make([]byte, len(msg))
2901 n, _ := io.ReadFull(res.Body, body)
2902 if n != len(body) || !bytes.Equal(body, []byte(msg)) {
2903 t.Errorf("Body = %q; want %q", body[:n], msg)
2904 }
2905 synctest.Wait()
2906 if got, want := conn.InFlight(), 1; got != want {
2907 t.Fatalf("Before cancel: InFlight = %v, want %v", got, want)
2908 }
2909 test.cancel(cst.tr, req)
2910
2911 tail, err := io.ReadAll(res.Body)
2912 res.Body.Close()
2913 test.checkErr("Body.Read", err)
2914 if len(tail) > 0 {
2915 t.Errorf("Spurious bytes from Body.Read: %q", tail)
2916 }
2917
2918 synctest.Wait()
2919 if got, want := conn.InFlight(), 0; got != want {
2920 t.Fatalf("After cancel: InFlight = %v, want %v", got, want)
2921 }
2922 }
2923
2924 func TestTransportCancelRequestBeforeDo(t *testing.T) {
2925 runCancelTest(t, testTransportCancelRequestBeforeDo)
2926 }
2927 func testTransportCancelRequestBeforeDo(t *testing.T, test cancelTest) {
2928 unblockc := make(chan bool)
2929 cst := newClientServerTest(t, test.mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2930 <-unblockc
2931 }))
2932 defer close(unblockc)
2933
2934 c := cst.ts.Client()
2935
2936 req, _ := NewRequest("GET", cst.ts.URL, nil)
2937 req = test.newReq(req)
2938 test.cancel(cst.tr, req)
2939
2940 _, err := c.Do(req)
2941 test.checkErr("Do", err)
2942 }
2943
2944
2945 func TestTransportCancelRequestBeforeResponseHeaders(t *testing.T) {
2946 runCancelTest(t, testTransportCancelRequestBeforeResponseHeaders, []testMode{http1Mode})
2947 }
2948 func testTransportCancelRequestBeforeResponseHeaders(t *testing.T, test cancelTest) {
2949 serverConnCh := make(chan net.Conn, 1)
2950 tr := &Transport{
2951 Dial: func(network, addr string) (net.Conn, error) {
2952 cc, sc := net.Pipe()
2953 serverConnCh <- sc
2954 return cc, nil
2955 },
2956 }
2957 defer tr.CloseIdleConnections()
2958 errc := make(chan error, 1)
2959 req, _ := NewRequest("GET", "http://example.com/", nil)
2960 req = test.newReq(req)
2961 go func() {
2962 _, err := tr.RoundTrip(req)
2963 errc <- err
2964 }()
2965
2966 sc := <-serverConnCh
2967 verb := make([]byte, 3)
2968 if _, err := io.ReadFull(sc, verb); err != nil {
2969 t.Errorf("Error reading HTTP verb from server: %v", err)
2970 }
2971 if string(verb) != "GET" {
2972 t.Errorf("server received %q; want GET", verb)
2973 }
2974 defer sc.Close()
2975
2976 test.cancel(tr, req)
2977
2978 err := <-errc
2979 if err == nil {
2980 t.Fatalf("unexpected success from RoundTrip")
2981 }
2982 test.checkErr("RoundTrip", err)
2983 }
2984
2985
2986
2987
2988 func TestTransportCloseResponseBody(t *testing.T) {
2989 runSynctest(t, testTransportCloseResponseBody)
2990 }
2991 func testTransportCloseResponseBody(t *testing.T, mode testMode) {
2992 writeErr := make(chan error, 1)
2993 msg := []byte("young\n")
2994 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
2995 for {
2996 _, err := w.Write(msg)
2997 if err != nil {
2998 writeErr <- err
2999 return
3000 }
3001 w.(Flusher).Flush()
3002 }
3003 }))
3004 ts := cst.ts
3005 cst.setDialNettestHook(func(nc *nettest.Conn) {
3006 nc.SetReadBufferSize(1024)
3007 })
3008
3009 c := ts.Client()
3010 req, _ := NewRequestWithContext(t.Context(), "GET", ts.URL, nil)
3011 res, err := c.Do(req)
3012 if err != nil {
3013 t.Fatal(err)
3014 }
3015
3016 const repeats = 3
3017 buf := make([]byte, len(msg)*repeats)
3018 want := bytes.Repeat(msg, repeats)
3019
3020 _, err = io.ReadFull(res.Body, buf)
3021 if err != nil {
3022 t.Fatal(err)
3023 }
3024 if !bytes.Equal(buf, want) {
3025 t.Fatalf("read %q; want %q", buf, want)
3026 }
3027
3028 if err := res.Body.Close(); err != nil {
3029 t.Errorf("Close = %v", err)
3030 }
3031
3032 if err := <-writeErr; err == nil {
3033 t.Errorf("expected non-nil write error")
3034 }
3035 }
3036
3037 type fooProto struct{}
3038
3039 func (fooProto) RoundTrip(req *Request) (*Response, error) {
3040 res := &Response{
3041 Status: "200 OK",
3042 StatusCode: 200,
3043 Header: make(Header),
3044 Body: io.NopCloser(strings.NewReader("You wanted " + req.URL.String())),
3045 }
3046 return res, nil
3047 }
3048
3049 func TestTransportAltProto(t *testing.T) {
3050 tr := &Transport{}
3051 c := &Client{Transport: tr}
3052 tr.RegisterProtocol("foo", fooProto{})
3053 res, err := c.Get("foo://bar.com/path")
3054 if err != nil {
3055 t.Fatal(err)
3056 }
3057 bodyb, err := io.ReadAll(res.Body)
3058 if err != nil {
3059 t.Fatal(err)
3060 }
3061 body := string(bodyb)
3062 if e := "You wanted foo://bar.com/path"; body != e {
3063 t.Errorf("got response %q, want %q", body, e)
3064 }
3065 }
3066
3067 func TestTransportNoHost(t *testing.T) {
3068 tr := &Transport{}
3069 _, err := tr.RoundTrip(&Request{
3070 Header: make(Header),
3071 URL: &url.URL{
3072 Scheme: "http",
3073 },
3074 })
3075 want := "http: no Host in request URL"
3076 if got := fmt.Sprint(err); got != want {
3077 t.Errorf("error = %v; want %q", err, want)
3078 }
3079 }
3080
3081
3082 func TestTransportEmptyMethod(t *testing.T) {
3083 req, _ := NewRequest("GET", "http://foo.com/", nil)
3084 req.Method = ""
3085 got, err := httputil.DumpRequestOut(req, false)
3086 if err != nil {
3087 t.Fatal(err)
3088 }
3089 if !strings.Contains(string(got), "GET ") {
3090 t.Fatalf("expected substring 'GET '; got: %s", got)
3091 }
3092 }
3093
3094 func TestTransportSocketLateBinding(t *testing.T) {
3095 runNoSynctest(t, testTransportSocketLateBinding, http3SkippedMode)
3096 }
3097 func testTransportSocketLateBinding(t *testing.T, mode testMode) {
3098 mux := NewServeMux()
3099 fooGate := make(chan bool, 1)
3100 mux.HandleFunc("/foo", func(w ResponseWriter, r *Request) {
3101 w.Header().Set("foo-ipport", r.RemoteAddr)
3102 w.(Flusher).Flush()
3103 <-fooGate
3104 })
3105 mux.HandleFunc("/bar", func(w ResponseWriter, r *Request) {
3106 w.Header().Set("bar-ipport", r.RemoteAddr)
3107 })
3108 ts := newClientServerTest(t, mode, mux, optRealNet).ts
3109
3110 dialGate := make(chan bool, 1)
3111 dialing := make(chan bool)
3112 c := ts.Client()
3113 c.Transport.(*Transport).Dial = func(n, addr string) (net.Conn, error) {
3114 for {
3115 select {
3116 case ok := <-dialGate:
3117 if !ok {
3118 return nil, errors.New("manually closed")
3119 }
3120 return net.Dial(n, addr)
3121 case dialing <- true:
3122 }
3123 }
3124 }
3125 defer close(dialGate)
3126
3127 dialGate <- true
3128 fooRes, err := c.Get(ts.URL + "/foo")
3129 if err != nil {
3130 t.Fatal(err)
3131 }
3132 fooAddr := fooRes.Header.Get("foo-ipport")
3133 if fooAddr == "" {
3134 t.Fatal("No addr on /foo request")
3135 }
3136
3137 fooDone := make(chan struct{})
3138 go func() {
3139
3140
3141
3142
3143 if mode == http2Mode {
3144
3145
3146
3147
3148 select {
3149 case <-dialing:
3150 t.Errorf("unexpected second Dial in HTTP/2 mode")
3151 case <-time.After(10 * time.Millisecond):
3152 }
3153 } else {
3154 <-dialing
3155 }
3156 fooGate <- true
3157 io.Copy(io.Discard, fooRes.Body)
3158 fooRes.Body.Close()
3159 close(fooDone)
3160 }()
3161 defer func() {
3162 <-fooDone
3163 }()
3164
3165 barRes, err := c.Get(ts.URL + "/bar")
3166 if err != nil {
3167 t.Fatal(err)
3168 }
3169 barAddr := barRes.Header.Get("bar-ipport")
3170 if barAddr != fooAddr {
3171 t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr)
3172 }
3173 barRes.Body.Close()
3174 }
3175
3176
3177 func TestTransportReading100Continue(t *testing.T) {
3178 const numReqs = 5
3179 reqBody := func(n int) string { return fmt.Sprintf("request body %d", n) }
3180 reqID := func(n int) string { return fmt.Sprintf("REQ-ID-%d", n) }
3181
3182 send100Response := func(w *io.PipeWriter, r *io.PipeReader) {
3183 defer w.Close()
3184 defer r.Close()
3185 br := bufio.NewReader(r)
3186 n := 0
3187 for {
3188 n++
3189 req, err := ReadRequest(br)
3190 if err == io.EOF {
3191 return
3192 }
3193 if err != nil {
3194 t.Error(err)
3195 return
3196 }
3197 slurp, err := io.ReadAll(req.Body)
3198 if err != nil {
3199 t.Errorf("Server request body slurp: %v", err)
3200 return
3201 }
3202 id := req.Header.Get("Request-Id")
3203 resCode := req.Header.Get("X-Want-Response-Code")
3204 if resCode == "" {
3205 resCode = "100 Continue"
3206 if string(slurp) != reqBody(n) {
3207 t.Errorf("Server got %q, %v; want %q", slurp, err, reqBody(n))
3208 }
3209 }
3210 body := fmt.Sprintf("Response number %d", n)
3211 v := []byte(strings.Replace(fmt.Sprintf(`HTTP/1.1 %s
3212 Date: Thu, 28 Feb 2013 17:55:41 GMT
3213
3214 HTTP/1.1 200 OK
3215 Content-Type: text/html
3216 Echo-Request-Id: %s
3217 Content-Length: %d
3218
3219 %s`, resCode, id, len(body), body), "\n", "\r\n", -1))
3220 w.Write(v)
3221 if id == reqID(numReqs) {
3222 return
3223 }
3224 }
3225
3226 }
3227
3228 tr := &Transport{
3229 Dial: func(n, addr string) (net.Conn, error) {
3230 sr, sw := io.Pipe()
3231 cr, cw := io.Pipe()
3232 conn := &rwTestConn{
3233 Reader: cr,
3234 Writer: sw,
3235 closeFunc: func() error {
3236 sw.Close()
3237 cw.Close()
3238 return nil
3239 },
3240 }
3241 go send100Response(cw, sr)
3242 return conn, nil
3243 },
3244 DisableKeepAlives: false,
3245 }
3246 defer tr.CloseIdleConnections()
3247 c := &Client{Transport: tr}
3248
3249 testResponse := func(req *Request, name string, wantCode int) {
3250 t.Helper()
3251 res, err := c.Do(req)
3252 if err != nil {
3253 t.Fatalf("%s: Do: %v", name, err)
3254 }
3255 if res.StatusCode != wantCode {
3256 t.Fatalf("%s: Response Statuscode=%d; want %d", name, res.StatusCode, wantCode)
3257 }
3258 if id, idBack := req.Header.Get("Request-Id"), res.Header.Get("Echo-Request-Id"); id != "" && id != idBack {
3259 t.Errorf("%s: response id %q != request id %q", name, idBack, id)
3260 }
3261 _, err = io.ReadAll(res.Body)
3262 if err != nil {
3263 t.Fatalf("%s: Slurp error: %v", name, err)
3264 }
3265 }
3266
3267
3268 for i := 1; i <= numReqs; i++ {
3269 req, _ := NewRequest("POST", "http://dummy.tld/", strings.NewReader(reqBody(i)))
3270 req.Header.Set("Request-Id", reqID(i))
3271 testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200)
3272 }
3273 }
3274
3275
3276
3277 func TestTransportIgnore1xxResponses(t *testing.T) {
3278 runSynctest(t, testTransportIgnore1xxResponses, []testMode{http1Mode})
3279 }
3280 func testTransportIgnore1xxResponses(t *testing.T, mode testMode) {
3281 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3282 conn, buf, _ := w.(Hijacker).Hijack()
3283 buf.Write([]byte("HTTP/1.1 123 OneTwoThree\r\nFoo: bar\r\n\r\nHTTP/1.1 200 OK\r\nBar: baz\r\nContent-Length: 5\r\n\r\nHello"))
3284 buf.Flush()
3285 conn.Close()
3286 }))
3287 cst.tr.DisableKeepAlives = true
3288
3289 var got strings.Builder
3290
3291 req, _ := NewRequest("GET", cst.ts.URL, nil)
3292 req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
3293 Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
3294 fmt.Fprintf(&got, "1xx: code=%v, header=%v\n", code, header)
3295 return nil
3296 },
3297 }))
3298 res, err := cst.c.Do(req)
3299 if err != nil {
3300 t.Fatal(err)
3301 }
3302 defer res.Body.Close()
3303
3304 res.Write(&got)
3305 want := "1xx: code=123, header=map[Foo:[bar]]\nHTTP/1.1 200 OK\r\nContent-Length: 5\r\nBar: baz\r\n\r\nHello"
3306 if got.String() != want {
3307 t.Errorf(" got: %q\nwant: %q\n", got.String(), want)
3308 }
3309 }
3310
3311 func TestTransportLimits1xxResponses(t *testing.T) {
3312 runSynctest(t, testTransportLimits1xxResponses, http3SkippedMode)
3313 }
3314 func testTransportLimits1xxResponses(t *testing.T, mode testMode) {
3315 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3316 w.Header().Add("X-Header", strings.Repeat("a", 100))
3317 for i := 0; i < 10; i++ {
3318 w.WriteHeader(123)
3319 }
3320 w.WriteHeader(204)
3321 }))
3322 cst.tr.DisableKeepAlives = true
3323 cst.tr.MaxResponseHeaderBytes = 1000
3324
3325 res, err := cst.c.Get(cst.ts.URL)
3326 if err == nil {
3327 res.Body.Close()
3328 t.Fatalf("RoundTrip succeeded; want error")
3329 }
3330 for _, want := range []string{
3331 "response headers exceeded",
3332 "too many 1xx",
3333 "header list too large",
3334 } {
3335 if strings.Contains(err.Error(), want) {
3336 return
3337 }
3338 }
3339 t.Errorf(`got error %q; want "response headers exceeded" or "too many 1xx"`, err)
3340 }
3341
3342 func TestTransportDoesNotLimitDelivered1xxResponses(t *testing.T) {
3343 runSynctest(t, testTransportDoesNotLimitDelivered1xxResponses, http3SkippedMode)
3344 }
3345 func testTransportDoesNotLimitDelivered1xxResponses(t *testing.T, mode testMode) {
3346 if mode == http2Mode {
3347 t.Skip("skip until x/net/http2 updated")
3348 }
3349 const num1xx = 10
3350 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3351 w.Header().Add("X-Header", strings.Repeat("a", 100))
3352 for i := 0; i < 10; i++ {
3353 w.WriteHeader(123)
3354 }
3355 w.WriteHeader(204)
3356 }))
3357 cst.tr.DisableKeepAlives = true
3358 cst.tr.MaxResponseHeaderBytes = 1000
3359
3360 got1xx := 0
3361 ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
3362 Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
3363 got1xx++
3364 return nil
3365 },
3366 })
3367 req, _ := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil)
3368 res, err := cst.c.Do(req)
3369 if err != nil {
3370 t.Fatal(err)
3371 }
3372 res.Body.Close()
3373 if got1xx != num1xx {
3374 t.Errorf("Got %v 1xx responses, want %x", got1xx, num1xx)
3375 }
3376 }
3377
3378
3379
3380 func TestTransportTreat101Terminal(t *testing.T) {
3381 runSynctest(t, testTransportTreat101Terminal, []testMode{http1Mode})
3382 }
3383 func testTransportTreat101Terminal(t *testing.T, mode testMode) {
3384 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3385 conn, buf, _ := w.(Hijacker).Hijack()
3386 buf.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n\r\n"))
3387 buf.Write([]byte("HTTP/1.1 204 No Content\r\n\r\n"))
3388 buf.Flush()
3389 conn.Close()
3390 }))
3391 res, err := cst.c.Get(cst.ts.URL)
3392 if err != nil {
3393 t.Fatal(err)
3394 }
3395 defer res.Body.Close()
3396 if res.StatusCode != StatusSwitchingProtocols {
3397 t.Errorf("StatusCode = %v; want 101 Switching Protocols", res.StatusCode)
3398 }
3399 }
3400
3401 type proxyFromEnvTest struct {
3402 req string
3403
3404 env string
3405 httpsenv string
3406 noenv string
3407 reqmeth string
3408
3409 want string
3410 wanterr error
3411 }
3412
3413 func (t proxyFromEnvTest) String() string {
3414 var buf strings.Builder
3415 space := func() {
3416 if buf.Len() > 0 {
3417 buf.WriteByte(' ')
3418 }
3419 }
3420 if t.env != "" {
3421 fmt.Fprintf(&buf, "http_proxy=%q", t.env)
3422 }
3423 if t.httpsenv != "" {
3424 space()
3425 fmt.Fprintf(&buf, "https_proxy=%q", t.httpsenv)
3426 }
3427 if t.noenv != "" {
3428 space()
3429 fmt.Fprintf(&buf, "no_proxy=%q", t.noenv)
3430 }
3431 if t.reqmeth != "" {
3432 space()
3433 fmt.Fprintf(&buf, "request_method=%q", t.reqmeth)
3434 }
3435 req := "http://example.com"
3436 if t.req != "" {
3437 req = t.req
3438 }
3439 space()
3440 fmt.Fprintf(&buf, "req=%q", req)
3441 return strings.TrimSpace(buf.String())
3442 }
3443
3444 var proxyFromEnvTests = []proxyFromEnvTest{
3445 {env: "127.0.0.1:8080", want: "http://127.0.0.1:8080"},
3446 {env: "cache.corp.example.com:1234", want: "http://cache.corp.example.com:1234"},
3447 {env: "cache.corp.example.com", want: "http://cache.corp.example.com"},
3448 {env: "https://cache.corp.example.com", want: "https://cache.corp.example.com"},
3449 {env: "http://127.0.0.1:8080", want: "http://127.0.0.1:8080"},
3450 {env: "https://127.0.0.1:8080", want: "https://127.0.0.1:8080"},
3451 {env: "socks5://127.0.0.1", want: "socks5://127.0.0.1"},
3452 {env: "socks5h://127.0.0.1", want: "socks5h://127.0.0.1"},
3453
3454
3455 {req: "http://insecure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://http.proxy.tld"},
3456
3457 {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "secure.proxy.tld", want: "http://secure.proxy.tld"},
3458 {req: "https://secure.tld/", env: "http.proxy.tld", httpsenv: "https://secure.proxy.tld", want: "https://secure.proxy.tld"},
3459
3460
3461
3462 {env: "http://10.1.2.3:8080", reqmeth: "POST",
3463 want: "<nil>",
3464 wanterr: errors.New("refusing to use HTTP_PROXY value in CGI environment; see golang.org/s/cgihttpproxy")},
3465
3466 {want: "<nil>"},
3467
3468 {noenv: "example.com", req: "http://example.com/", env: "proxy", want: "<nil>"},
3469 {noenv: ".example.com", req: "http://example.com/", env: "proxy", want: "http://proxy"},
3470 {noenv: "ample.com", req: "http://example.com/", env: "proxy", want: "http://proxy"},
3471 {noenv: "example.com", req: "http://foo.example.com/", env: "proxy", want: "<nil>"},
3472 {noenv: ".foo.com", req: "http://example.com/", env: "proxy", want: "http://proxy"},
3473 }
3474
3475 func testProxyForRequest(t *testing.T, tt proxyFromEnvTest, proxyForRequest func(req *Request) (*url.URL, error)) {
3476 t.Helper()
3477 reqURL := tt.req
3478 if reqURL == "" {
3479 reqURL = "http://example.com"
3480 }
3481 req, _ := NewRequest("GET", reqURL, nil)
3482 url, err := proxyForRequest(req)
3483 if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e {
3484 t.Errorf("%v: got error = %q, want %q", tt, g, e)
3485 return
3486 }
3487 if got := fmt.Sprintf("%s", url); got != tt.want {
3488 t.Errorf("%v: got URL = %q, want %q", tt, url, tt.want)
3489 }
3490 }
3491
3492 func TestProxyFromEnvironment(t *testing.T) {
3493 ResetProxyEnv()
3494 defer ResetProxyEnv()
3495 for _, tt := range proxyFromEnvTests {
3496 testProxyForRequest(t, tt, func(req *Request) (*url.URL, error) {
3497 os.Setenv("HTTP_PROXY", tt.env)
3498 os.Setenv("HTTPS_PROXY", tt.httpsenv)
3499 os.Setenv("NO_PROXY", tt.noenv)
3500 os.Setenv("REQUEST_METHOD", tt.reqmeth)
3501 ResetCachedEnvironment()
3502 return ProxyFromEnvironment(req)
3503 })
3504 }
3505 }
3506
3507 func TestProxyFromEnvironmentLowerCase(t *testing.T) {
3508 ResetProxyEnv()
3509 defer ResetProxyEnv()
3510 for _, tt := range proxyFromEnvTests {
3511 testProxyForRequest(t, tt, func(req *Request) (*url.URL, error) {
3512 os.Setenv("http_proxy", tt.env)
3513 os.Setenv("https_proxy", tt.httpsenv)
3514 os.Setenv("no_proxy", tt.noenv)
3515 os.Setenv("REQUEST_METHOD", tt.reqmeth)
3516 ResetCachedEnvironment()
3517 return ProxyFromEnvironment(req)
3518 })
3519 }
3520 }
3521
3522
3523
3524
3525 func TestTransportClosesRequestBody(t *testing.T) {
3526 runSynctest(t, testTransportClosesRequestBody, []testMode{http1Mode})
3527 }
3528 func testTransportClosesRequestBody(t *testing.T, mode testMode) {
3529 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3530 io.Copy(io.Discard, r.Body)
3531 })).ts
3532
3533 c := ts.Client()
3534
3535 closes := 0
3536
3537 res, err := c.Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
3538 if err != nil {
3539 t.Fatal(err)
3540 }
3541 res.Body.Close()
3542 if closes != 1 {
3543 t.Errorf("closes = %d; want 1", closes)
3544 }
3545 }
3546
3547 func TestTransportTLSHandshakeTimeout(t *testing.T) {
3548 synctest.Test(t, func(t *testing.T) {
3549 tt := newHTTP1TransportTest(t)
3550 tt.tr.TLSHandshakeTimeout = 250 * time.Millisecond
3551
3552 start := time.Now()
3553 req, _ := http.NewRequest("GET", "https://dummy.tld/", nil)
3554 rt := tt.roundTrip(req)
3555 dial := tt.wantDial("tcp", "dummy.tld:443")
3556 dial.connect()
3557
3558 <-rt.donec
3559 if got, want := time.Since(start), tt.tr.TLSHandshakeTimeout; got != want {
3560 t.Errorf("Get took %v, want %v", got, want)
3561 }
3562 err := rt.err()
3563 if err == nil {
3564 t.Fatal("expected error")
3565 }
3566 ne, ok := err.(net.Error)
3567 if !ok {
3568 t.Fatalf("expected net.Error; got %#v", err)
3569 }
3570 if !ne.Timeout() {
3571 t.Fatalf("expected timeout error; got %v", err)
3572 }
3573 if !strings.Contains(err.Error(), "handshake timeout") {
3574 t.Fatalf("expected 'handshake timeout' in error; got %v", err)
3575 }
3576 })
3577 }
3578
3579
3580 func TestTLSServerClosesConnection(t *testing.T) {
3581 runSynctest(t, testTLSServerClosesConnection, []testMode{https1Mode})
3582 }
3583 func testTLSServerClosesConnection(t *testing.T, mode testMode) {
3584 closedc := make(chan bool, 1)
3585 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3586 if strings.Contains(r.URL.Path, "/keep-alive-then-die") {
3587 conn, _, _ := w.(Hijacker).Hijack()
3588 conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"))
3589 conn.Close()
3590 closedc <- true
3591 return
3592 }
3593 fmt.Fprintf(w, "hello")
3594 })).ts
3595
3596 c := ts.Client()
3597 tr := c.Transport.(*Transport)
3598
3599 var nSuccess = 0
3600 var errs []error
3601 const trials = 20
3602 for i := 0; i < trials; i++ {
3603 tr.CloseIdleConnections()
3604 res, err := c.Get(ts.URL + "/keep-alive-then-die")
3605 if err != nil {
3606 t.Fatal(err)
3607 }
3608 <-closedc
3609 slurp, err := io.ReadAll(res.Body)
3610 if err != nil {
3611 t.Fatal(err)
3612 }
3613 if string(slurp) != "foo" {
3614 t.Errorf("Got %q, want foo", slurp)
3615 }
3616
3617
3618
3619 res, err = c.Get(ts.URL + "/")
3620 if err != nil {
3621 errs = append(errs, err)
3622 continue
3623 }
3624 slurp, err = io.ReadAll(res.Body)
3625 if err != nil {
3626 errs = append(errs, err)
3627 continue
3628 }
3629 nSuccess++
3630 }
3631 if nSuccess > 0 {
3632 t.Logf("successes = %d of %d", nSuccess, trials)
3633 } else {
3634 t.Errorf("All runs failed:")
3635 }
3636 for _, err := range errs {
3637 t.Logf(" err: %v", err)
3638 }
3639 }
3640
3641
3642
3643
3644 type byteFromChanReader chan byte
3645
3646 func (c byteFromChanReader) Read(p []byte) (n int, err error) {
3647 if len(p) == 0 {
3648 return
3649 }
3650 b, ok := <-c
3651 if !ok {
3652 return 0, io.EOF
3653 }
3654 p[0] = b
3655 return 1, nil
3656 }
3657
3658
3659
3660
3661
3662
3663
3664 func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
3665 runSynctest(t, testTransportNoReuseAfterEarlyResponse, []testMode{http1Mode}, testNotParallel)
3666 }
3667 func testTransportNoReuseAfterEarlyResponse(t *testing.T, mode testMode) {
3668 defer func(d time.Duration) {
3669 *MaxWriteWaitBeforeConnReuse = d
3670 }(*MaxWriteWaitBeforeConnReuse)
3671 *MaxWriteWaitBeforeConnReuse = 10 * time.Millisecond
3672 var sconn struct {
3673 sync.Mutex
3674 c net.Conn
3675 }
3676 var getOkay bool
3677 var willCopy sync.WaitGroup
3678 closeConn := func() {
3679 sconn.Lock()
3680 defer sconn.Unlock()
3681 if sconn.c != nil {
3682 sconn.c.Close()
3683 sconn.c = nil
3684 if !getOkay {
3685 t.Logf("Closed server connection")
3686 }
3687 }
3688 }
3689 defer func() {
3690 closeConn()
3691 willCopy.Wait()
3692 }()
3693
3694 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3695 if r.Method == "GET" {
3696 io.WriteString(w, "bar")
3697 return
3698 }
3699 conn, _, _ := w.(Hijacker).Hijack()
3700 sconn.Lock()
3701 sconn.c = conn
3702 sconn.Unlock()
3703
3704 willCopy.Add(1)
3705 conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"))
3706 go func() {
3707 io.Copy(io.Discard, conn)
3708 willCopy.Done()
3709 }()
3710 })).ts
3711 c := ts.Client()
3712
3713 const bodySize = 256 << 10
3714 finalBit := make(byteFromChanReader, 1)
3715 req, _ := NewRequest("POST", ts.URL, io.MultiReader(io.LimitReader(neverEnding('x'), bodySize-1), finalBit))
3716 req.ContentLength = bodySize
3717 res, err := c.Do(req)
3718 if err := wantBody(res, err, "foo"); err != nil {
3719 t.Errorf("POST response: %v", err)
3720 }
3721
3722 res, err = c.Get(ts.URL)
3723 if err := wantBody(res, err, "bar"); err != nil {
3724 t.Errorf("GET response: %v", err)
3725 return
3726 }
3727 getOkay = true
3728 finalBit <- 'x'
3729 close(finalBit)
3730 }
3731
3732
3733
3734 func TestTransportIssue10457(t *testing.T) {
3735 runSynctest(t, testTransportIssue10457, []testMode{http1Mode})
3736 }
3737 func testTransportIssue10457(t *testing.T, mode testMode) {
3738 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3739
3740
3741
3742
3743
3744 conn, _, _ := w.(Hijacker).Hijack()
3745 conn.Write([]byte("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 0\r\n\r\n"))
3746 conn.Close()
3747 })).ts
3748 c := ts.Client()
3749
3750 res, err := c.Get(ts.URL)
3751 if err != nil {
3752 t.Fatalf("Get: %v", err)
3753 }
3754 defer res.Body.Close()
3755
3756
3757
3758
3759 if got, want := res.Header.Get("Foo"), "Bar"; got != want {
3760 t.Errorf("Foo header = %q; want %q", got, want)
3761 }
3762 }
3763
3764 type closerFunc func() error
3765
3766 func (f closerFunc) Close() error { return f() }
3767
3768 type writerFuncConn struct {
3769 net.Conn
3770 write func(p []byte) (n int, err error)
3771 }
3772
3773 func (c writerFuncConn) Write(p []byte) (n int, err error) { return c.write(p) }
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787 func TestRetryRequestsOnError(t *testing.T) {
3788 runNoSynctest(t, testRetryRequestsOnError, testNotParallel, []testMode{http1Mode})
3789 }
3790 func testRetryRequestsOnError(t *testing.T, mode testMode) {
3791 newRequest := func(method, urlStr string, body io.Reader) *Request {
3792 req, err := NewRequest(method, urlStr, body)
3793 if err != nil {
3794 t.Fatal(err)
3795 }
3796 return req
3797 }
3798
3799 testCases := []struct {
3800 name string
3801 failureN int
3802 failureErr error
3803
3804
3805
3806 req func() *Request
3807 reqString string
3808 }{
3809 {
3810 name: "IdempotentNoBodySomeWritten",
3811
3812
3813 failureN: 1,
3814
3815 failureErr: ExportErrServerClosedIdle,
3816 req: func() *Request {
3817 return newRequest("GET", "http://fake.golang", nil)
3818 },
3819 reqString: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`,
3820 },
3821 {
3822 name: "IdempotentGetBodySomeWritten",
3823
3824
3825 failureN: 1,
3826
3827 failureErr: ExportErrServerClosedIdle,
3828 req: func() *Request {
3829 return newRequest("GET", "http://fake.golang", strings.NewReader("foo\n"))
3830 },
3831 reqString: `GET / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`,
3832 },
3833 {
3834 name: "IdempotentQueryGetBodySomeWritten",
3835
3836
3837 failureN: 1,
3838 failureErr: ExportErrServerClosedIdle,
3839 req: func() *Request {
3840 return newRequest("QUERY", "http://fake.golang", strings.NewReader("foo\n"))
3841 },
3842 reqString: `QUERY / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`,
3843 },
3844 {
3845 name: "NothingWrittenNoBody",
3846
3847
3848 failureN: 0,
3849 failureErr: errors.New("second write fails"),
3850 req: func() *Request {
3851 return newRequest("DELETE", "http://fake.golang", nil)
3852 },
3853 reqString: `DELETE / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nAccept-Encoding: gzip\r\n\r\n`,
3854 },
3855 {
3856 name: "NothingWrittenGetBody",
3857
3858
3859 failureN: 0,
3860 failureErr: errors.New("second write fails"),
3861
3862
3863 req: func() *Request {
3864 return newRequest("POST", "http://fake.golang", strings.NewReader("foo\n"))
3865 },
3866 reqString: `POST / HTTP/1.1\r\nHost: fake.golang\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 4\r\nAccept-Encoding: gzip\r\n\r\nfoo\n`,
3867 },
3868 }
3869
3870 for _, tc := range testCases {
3871 t.Run(tc.name, func(t *testing.T) {
3872 var (
3873 mu sync.Mutex
3874 logbuf strings.Builder
3875 )
3876 logf := func(format string, args ...any) {
3877 mu.Lock()
3878 defer mu.Unlock()
3879 fmt.Fprintf(&logbuf, format, args...)
3880 logbuf.WriteByte('\n')
3881 }
3882
3883 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3884 logf("Handler")
3885 w.Header().Set("X-Status", "ok")
3886 }), optRealNet).ts
3887
3888 var writeNumAtomic int32
3889 c := ts.Client()
3890 c.Transport.(*Transport).Dial = func(network, addr string) (net.Conn, error) {
3891 logf("Dial")
3892 c, err := net.Dial(network, ts.Listener.Addr().String())
3893 if err != nil {
3894 logf("Dial error: %v", err)
3895 return nil, err
3896 }
3897 return &writerFuncConn{
3898 Conn: c,
3899 write: func(p []byte) (n int, err error) {
3900 if atomic.AddInt32(&writeNumAtomic, 1) == 2 {
3901 logf("intentional write failure")
3902 return tc.failureN, tc.failureErr
3903 }
3904 logf("Write(%q)", p)
3905 return c.Write(p)
3906 },
3907 }, nil
3908 }
3909
3910 SetRoundTripRetried(func() {
3911 logf("Retried.")
3912 })
3913 defer SetRoundTripRetried(nil)
3914
3915 for i := 0; i < 3; i++ {
3916 t0 := time.Now()
3917 req := tc.req()
3918 res, err := c.Do(req)
3919 if err != nil {
3920 if time.Since(t0) < *MaxWriteWaitBeforeConnReuse/2 {
3921 mu.Lock()
3922 got := logbuf.String()
3923 mu.Unlock()
3924 t.Fatalf("i=%d: Do = %v; log:\n%s", i, err, got)
3925 }
3926 t.Skipf("connection likely wasn't recycled within %d, interfering with actual test; skipping", *MaxWriteWaitBeforeConnReuse)
3927 }
3928 res.Body.Close()
3929 if res.Request != req {
3930 t.Errorf("Response.Request != original request; want identical Request")
3931 }
3932 }
3933
3934 mu.Lock()
3935 got := logbuf.String()
3936 mu.Unlock()
3937 want := fmt.Sprintf(`Dial
3938 Write("%s")
3939 Handler
3940 intentional write failure
3941 Retried.
3942 Dial
3943 Write("%s")
3944 Handler
3945 Write("%s")
3946 Handler
3947 `, tc.reqString, tc.reqString, tc.reqString)
3948 if got != want {
3949 t.Errorf("Log of events differs. Got:\n%s\nWant:\n%s", got, want)
3950 }
3951 })
3952 }
3953 }
3954
3955
3956 func TestTransportClosesBodyOnError(t *testing.T) { runSynctest(t, testTransportClosesBodyOnError) }
3957 func testTransportClosesBodyOnError(t *testing.T, mode testMode) {
3958 readBody := make(chan error, 1)
3959 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
3960 _, err := io.ReadAll(r.Body)
3961 readBody <- err
3962 })).ts
3963 c := ts.Client()
3964 fakeErr := errors.New("fake error")
3965 didClose := make(chan bool, 1)
3966 req, _ := NewRequest("POST", ts.URL, struct {
3967 io.Reader
3968 io.Closer
3969 }{
3970 io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), iotest.ErrReader(fakeErr)),
3971 closerFunc(func() error {
3972 select {
3973 case didClose <- true:
3974 default:
3975 }
3976 return nil
3977 }),
3978 })
3979
3980
3981
3982
3983
3984
3985
3986 req.Header.Set("Expect", "100-continue")
3987 res, err := c.Do(req)
3988 if res != nil {
3989 defer res.Body.Close()
3990 }
3991 if err == nil || !strings.Contains(err.Error(), fakeErr.Error()) {
3992 t.Fatalf("Do error = %v; want something containing %q", err, fakeErr.Error())
3993 }
3994 if err := <-readBody; err == nil {
3995 t.Errorf("Unexpected success reading request body from handler; want 'unexpected EOF reading trailer'")
3996 }
3997 select {
3998 case <-didClose:
3999 default:
4000 t.Errorf("didn't see Body.Close")
4001 }
4002 }
4003
4004 func TestTransportDialTLS(t *testing.T) {
4005 runNoSynctest(t, testTransportDialTLS, []testMode{https1Mode, http2Mode})
4006 }
4007 func testTransportDialTLS(t *testing.T, mode testMode) {
4008 var mu sync.Mutex
4009 var gotReq, didDial bool
4010
4011 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4012 mu.Lock()
4013 gotReq = true
4014 mu.Unlock()
4015 }), optRealNet).ts
4016 c := ts.Client()
4017 c.Transport.(*Transport).DialTLS = func(netw, addr string) (net.Conn, error) {
4018 mu.Lock()
4019 didDial = true
4020 mu.Unlock()
4021 c, err := tls.Dial(netw, addr, c.Transport.(*Transport).TLSClientConfig)
4022 if err != nil {
4023 return nil, err
4024 }
4025 return c, c.Handshake()
4026 }
4027
4028 res, err := c.Get(ts.URL)
4029 if err != nil {
4030 t.Fatal(err)
4031 }
4032 res.Body.Close()
4033 mu.Lock()
4034 if !gotReq {
4035 t.Error("didn't get request")
4036 }
4037 if !didDial {
4038 t.Error("didn't use dial hook")
4039 }
4040 }
4041
4042 func TestTransportDialContext(t *testing.T) {
4043 runNoSynctest(t, testTransportDialContext, http3SkippedMode)
4044 }
4045 func testTransportDialContext(t *testing.T, mode testMode) {
4046 ctxKey := "some-key"
4047 ctxValue := "some-value"
4048 var (
4049 mu sync.Mutex
4050 gotReq bool
4051 gotCtxValue any
4052 )
4053
4054 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4055 mu.Lock()
4056 gotReq = true
4057 mu.Unlock()
4058 }), optRealNet).ts
4059 c := ts.Client()
4060 c.Transport.(*Transport).DialContext = func(ctx context.Context, netw, addr string) (net.Conn, error) {
4061 mu.Lock()
4062 gotCtxValue = ctx.Value(ctxKey)
4063 mu.Unlock()
4064 return net.Dial(netw, addr)
4065 }
4066
4067 req, err := NewRequest("GET", ts.URL, nil)
4068 if err != nil {
4069 t.Fatal(err)
4070 }
4071 ctx := context.WithValue(context.Background(), ctxKey, ctxValue)
4072 res, err := c.Do(req.WithContext(ctx))
4073 if err != nil {
4074 t.Fatal(err)
4075 }
4076 res.Body.Close()
4077 mu.Lock()
4078 if !gotReq {
4079 t.Error("didn't get request")
4080 }
4081 if got, want := gotCtxValue, ctxValue; got != want {
4082 t.Errorf("got context with value %v, want %v", got, want)
4083 }
4084 }
4085
4086 func TestTransportDialTLSContext(t *testing.T) {
4087 runNoSynctest(t, testTransportDialTLSContext, []testMode{https1Mode, http2Mode})
4088 }
4089 func testTransportDialTLSContext(t *testing.T, mode testMode) {
4090 ctxKey := "some-key"
4091 ctxValue := "some-value"
4092 var (
4093 mu sync.Mutex
4094 gotReq bool
4095 gotCtxValue any
4096 )
4097
4098 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4099 mu.Lock()
4100 gotReq = true
4101 mu.Unlock()
4102 }), optRealNet).ts
4103 c := ts.Client()
4104 c.Transport.(*Transport).DialTLSContext = func(ctx context.Context, netw, addr string) (net.Conn, error) {
4105 mu.Lock()
4106 gotCtxValue = ctx.Value(ctxKey)
4107 mu.Unlock()
4108 c, err := tls.Dial(netw, addr, c.Transport.(*Transport).TLSClientConfig)
4109 if err != nil {
4110 return nil, err
4111 }
4112 return c, c.HandshakeContext(ctx)
4113 }
4114
4115 req, err := NewRequest("GET", ts.URL, nil)
4116 if err != nil {
4117 t.Fatal(err)
4118 }
4119 ctx := context.WithValue(context.Background(), ctxKey, ctxValue)
4120 res, err := c.Do(req.WithContext(ctx))
4121 if err != nil {
4122 t.Fatal(err)
4123 }
4124 res.Body.Close()
4125 mu.Lock()
4126 if !gotReq {
4127 t.Error("didn't get request")
4128 }
4129 if got, want := gotCtxValue, ctxValue; got != want {
4130 t.Errorf("got context with value %v, want %v", got, want)
4131 }
4132 }
4133
4134
4135
4136 func TestRoundTripReturnsProxyError(t *testing.T) {
4137 badProxy := func(*Request) (*url.URL, error) {
4138 return nil, errors.New("errorMessage")
4139 }
4140
4141 tr := &Transport{Proxy: badProxy}
4142
4143 req, _ := NewRequest("GET", "http://example.com", nil)
4144
4145 _, err := tr.RoundTrip(req)
4146
4147 if err == nil {
4148 t.Error("Expected proxy error to be returned by RoundTrip")
4149 }
4150 }
4151
4152
4153
4154
4155
4156
4157 func TestTransportIdleConnRacesRequest(t *testing.T) {
4158
4159
4160 runSynctest(t, testTransportIdleConnRacesRequest, []testMode{http1Mode, http2UnencryptedMode})
4161 }
4162 func testTransportIdleConnRacesRequest(t *testing.T, mode testMode) {
4163 timeout := 1 * time.Millisecond
4164 trFunc := func(tr *Transport) {
4165 tr.IdleConnTimeout = timeout
4166 }
4167 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4168 }), trFunc)
4169
4170 dialsBlocked := make(chan struct{})
4171 closeBlocked := make(chan struct{})
4172
4173 dialContext := cst.tr.DialContext
4174 cst.tr.DialContext = func(ctx context.Context, network, address string) (net.Conn, error) {
4175 <-dialsBlocked
4176 c, err := dialContext(ctx, network, address)
4177 if err != nil {
4178 return nil, err
4179 }
4180 return &blockCloseConn{closeBlocked, c}, nil
4181 }
4182
4183
4184
4185
4186
4187 ctx, cancel := context.WithCancel(t.Context())
4188 go func() {
4189 req, _ := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil)
4190 resp, err := cst.c.Do(req)
4191 if err == nil {
4192 t.Errorf("expected request to fail, but it succeeded")
4193 resp.Body.Close()
4194 }
4195 }()
4196
4197 synctest.Wait()
4198
4199 cancel()
4200 synctest.Wait()
4201
4202 close(dialsBlocked)
4203
4204
4205
4206
4207
4208
4209
4210
4211 synctest.Wait()
4212 synctest.Sleep(timeout)
4213
4214 go func() {
4215 resp, err := cst.c.Get(cst.ts.URL)
4216 if err != nil {
4217 t.Errorf("expected second request to succeed, but it failed: %v", err)
4218 return
4219 }
4220 resp.Body.Close()
4221 }()
4222
4223
4224 close(closeBlocked)
4225 synctest.Wait()
4226 }
4227
4228 type blockCloseConn struct {
4229 closeBlocked chan struct{}
4230 net.Conn
4231 }
4232
4233 func (c *blockCloseConn) Close() error {
4234 <-c.closeBlocked
4235 return c.Conn.Close()
4236 }
4237
4238 func TestTransportRemovesConnsAfterIdle(t *testing.T) {
4239 runSynctest(t, testTransportRemovesConnsAfterIdle, http3SkippedMode)
4240 }
4241 func testTransportRemovesConnsAfterIdle(t *testing.T, mode testMode) {
4242 timeout := 1 * time.Second
4243 trFunc := func(tr *Transport) {
4244 tr.MaxConnsPerHost = 1
4245 tr.MaxIdleConnsPerHost = 1
4246 tr.IdleConnTimeout = timeout
4247 }
4248 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4249 w.Header().Set("X-Addr", r.RemoteAddr)
4250 }), trFunc)
4251
4252
4253
4254 makeRequest := func() string {
4255 resp, err := cst.c.Get(cst.ts.URL)
4256 if err != nil {
4257 t.Fatalf("got error: %s", err)
4258 }
4259 resp.Body.Close()
4260 return resp.Header.Get("X-Addr")
4261 }
4262
4263 addr1 := makeRequest()
4264
4265 time.Sleep(timeout / 2)
4266 synctest.Wait()
4267 addr2 := makeRequest()
4268 if addr1 != addr2 {
4269 t.Fatalf("two requests made within IdleConnTimeout should have used the same conn, but used %v, %v", addr1, addr2)
4270 }
4271
4272 time.Sleep(timeout)
4273 synctest.Wait()
4274 addr3 := makeRequest()
4275 if addr1 == addr3 {
4276 t.Fatalf("two requests made more than IdleConnTimeout apart should have used different conns, but used %v, %v", addr1, addr3)
4277 }
4278 }
4279
4280 func TestTransportRemovesConnsAfterBroken(t *testing.T) {
4281 runSynctest(t, testTransportRemovesConnsAfterBroken, http3SkippedMode)
4282 }
4283 func testTransportRemovesConnsAfterBroken(t *testing.T, mode testMode) {
4284 trFunc := func(tr *Transport) {
4285 tr.MaxConnsPerHost = 1
4286 tr.MaxIdleConnsPerHost = 1
4287 }
4288 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4289 w.Header().Set("X-Addr", r.RemoteAddr)
4290 }), trFunc)
4291
4292 var conns []*nettest.Conn
4293 cst.setDialNettestHook(func(c *nettest.Conn) {
4294 conns = append(conns, c)
4295 })
4296
4297
4298
4299 makeRequest := func() string {
4300 resp, err := cst.c.Get(cst.ts.URL)
4301 if err != nil {
4302 t.Fatalf("got error: %s", err)
4303 }
4304 resp.Body.Close()
4305 return resp.Header.Get("X-Addr")
4306 }
4307
4308 addr1 := makeRequest()
4309 addr2 := makeRequest()
4310 if addr1 != addr2 {
4311 t.Fatalf("successive requests should have used the same conn, but used %v, %v", addr1, addr2)
4312 }
4313
4314
4315 synctest.Wait()
4316 conns[0].Peer().Close()
4317 synctest.Wait()
4318 addr3 := makeRequest()
4319 if addr1 == addr3 {
4320 t.Fatalf("successive requests made with conn broken between should have used different conns, but used %v, %v", addr1, addr3)
4321 }
4322 }
4323
4324
4325
4326
4327
4328 func TestTransportRangeAndGzip(t *testing.T) { runSynctest(t, testTransportRangeAndGzip) }
4329 func testTransportRangeAndGzip(t *testing.T, mode testMode) {
4330 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4331 if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
4332 t.Error("Transport advertised gzip support in the Accept header")
4333 }
4334 if r.Header.Get("Range") == "" {
4335 t.Error("no Range in request")
4336 }
4337 })).ts
4338 c := ts.Client()
4339
4340 req, _ := NewRequest("GET", ts.URL, nil)
4341 req.Header.Set("Range", "bytes=7-11")
4342 res, err := c.Do(req)
4343 if err != nil {
4344 t.Fatal(err)
4345 }
4346 res.Body.Close()
4347 }
4348
4349
4350 func TestTransportResponseCancelRace(t *testing.T) { runSynctest(t, testTransportResponseCancelRace) }
4351 func testTransportResponseCancelRace(t *testing.T, mode testMode) {
4352 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4353
4354 var b [1024]byte
4355 w.Write(b[:])
4356 })).ts
4357 tr := ts.Client().Transport.(*Transport)
4358
4359 ctx, cancel := context.WithCancel(t.Context())
4360 req, err := NewRequestWithContext(ctx, "GET", ts.URL, nil)
4361 if err != nil {
4362 t.Fatal(err)
4363 }
4364 res, err := tr.RoundTrip(req)
4365 if err != nil {
4366 t.Fatal(err)
4367 }
4368
4369
4370
4371 if _, err := io.Copy(io.Discard, res.Body); err != nil {
4372 t.Fatal(err)
4373 }
4374
4375 req2, err := NewRequest("GET", ts.URL, nil)
4376 if err != nil {
4377 t.Fatal(err)
4378 }
4379 cancel()
4380 res, err = tr.RoundTrip(req2)
4381 if err != nil {
4382 t.Fatal(err)
4383 }
4384 res.Body.Close()
4385 }
4386
4387
4388 func TestTransportContentEncodingCaseInsensitive(t *testing.T) {
4389 runNoSynctest(t, testTransportContentEncodingCaseInsensitive)
4390 }
4391 func testTransportContentEncodingCaseInsensitive(t *testing.T, mode testMode) {
4392 for _, ce := range []string{"gzip", "GZIP"} {
4393 synctest.Subtest(t, ce, func(t *testing.T) {
4394 const encodedString = "Hello Gopher"
4395 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4396 w.Header().Set("Content-Encoding", ce)
4397 gz := gzip.NewWriter(w)
4398 gz.Write([]byte(encodedString))
4399 gz.Close()
4400 })).ts
4401
4402 res, err := ts.Client().Get(ts.URL)
4403 if err != nil {
4404 t.Fatal(err)
4405 }
4406
4407 body, err := io.ReadAll(res.Body)
4408 res.Body.Close()
4409 if err != nil {
4410 t.Fatal(err)
4411 }
4412
4413 if string(body) != encodedString {
4414 t.Fatalf("Expected body %q, got: %q\n", encodedString, string(body))
4415 }
4416 })
4417 }
4418 }
4419
4420
4421 func TestConnClosedBeforeRequestIsWritten(t *testing.T) {
4422 runSynctest(t, testConnClosedBeforeRequestIsWritten, testNotParallel, []testMode{http1Mode})
4423 }
4424 func testConnClosedBeforeRequestIsWritten(t *testing.T, mode testMode) {
4425 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}),
4426 func(tr *Transport) {
4427 tr.DialContext = func(_ context.Context, network, addr string) (net.Conn, error) {
4428
4429 return &funcConn{
4430 read: func([]byte) (int, error) {
4431 return 0, errors.New("error")
4432 },
4433 write: func([]byte) (int, error) {
4434 return 0, errors.New("error")
4435 },
4436 }, nil
4437 }
4438 },
4439 ).ts
4440
4441
4442
4443
4444
4445 SetEnterRoundTripHook(func() {
4446 time.Sleep(1 * time.Millisecond)
4447 })
4448 defer SetEnterRoundTripHook(nil)
4449 var closes int
4450 _, err := ts.Client().Post(ts.URL, "text/plain", countCloseReader{&closes, strings.NewReader("hello")})
4451 if err == nil {
4452 t.Fatalf("expected request to fail, but it did not")
4453 }
4454 if closes != 1 {
4455 t.Errorf("after RoundTrip, request body was closed %v times; want 1", closes)
4456 }
4457 }
4458
4459
4460
4461
4462 type logWritesConn struct {
4463 net.Conn
4464
4465 w io.Writer
4466
4467 rch <-chan io.Reader
4468 r io.Reader
4469
4470 mu sync.Mutex
4471 writes []string
4472 }
4473
4474 func (c *logWritesConn) Write(p []byte) (n int, err error) {
4475 c.mu.Lock()
4476 defer c.mu.Unlock()
4477 c.writes = append(c.writes, string(p))
4478 return c.w.Write(p)
4479 }
4480
4481 func (c *logWritesConn) Read(p []byte) (n int, err error) {
4482 if c.r == nil {
4483 c.r = <-c.rch
4484 }
4485 return c.r.Read(p)
4486 }
4487
4488 func (c *logWritesConn) Close() error { return nil }
4489
4490
4491 func TestTransportFlushesBodyChunks(t *testing.T) {
4492 resBody := make(chan io.Reader, 1)
4493 connr, connw := io.Pipe()
4494 lw := &logWritesConn{
4495 rch: resBody,
4496 w: connw,
4497 }
4498 tr := &Transport{
4499 Dial: func(network, addr string) (net.Conn, error) {
4500 return lw, nil
4501 },
4502 }
4503 bodyr, bodyw := io.Pipe()
4504 go func() {
4505 defer bodyw.Close()
4506 for i := 0; i < 3; i++ {
4507 fmt.Fprintf(bodyw, "num%d\n", i)
4508 }
4509 }()
4510 resc := make(chan *Response)
4511 go func() {
4512 req, _ := NewRequest("POST", "http://localhost:8080", bodyr)
4513 req.Header.Set("User-Agent", "x")
4514 res, err := tr.RoundTrip(req)
4515 if err != nil {
4516 t.Errorf("RoundTrip: %v", err)
4517 close(resc)
4518 return
4519 }
4520 resc <- res
4521
4522 }()
4523
4524 req, err := ReadRequest(bufio.NewReader(connr))
4525 if err != nil {
4526 t.Fatal(err)
4527 }
4528 io.Copy(io.Discard, req.Body)
4529
4530
4531 resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
4532 res, ok := <-resc
4533 if !ok {
4534 return
4535 }
4536 defer res.Body.Close()
4537
4538 want := []string{
4539 "POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n",
4540 "5\r\nnum0\n\r\n",
4541 "5\r\nnum1\n\r\n",
4542 "5\r\nnum2\n\r\n",
4543 "0\r\n\r\n",
4544 }
4545 if !slices.Equal(lw.writes, want) {
4546 t.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw.writes, want)
4547 }
4548 }
4549
4550
4551 func TestTransportFlushesRequestHeader(t *testing.T) {
4552 runSynctest(t, testTransportFlushesRequestHeader)
4553 }
4554 func testTransportFlushesRequestHeader(t *testing.T, mode testMode) {
4555 gotReq := make(chan struct{})
4556 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4557 close(gotReq)
4558 }))
4559
4560 pr, pw := io.Pipe()
4561 req, err := NewRequest("POST", cst.ts.URL, pr)
4562 if err != nil {
4563 t.Fatal(err)
4564 }
4565 gotRes := make(chan struct{})
4566 go func() {
4567 defer close(gotRes)
4568 res, err := cst.tr.RoundTrip(req)
4569 if err != nil {
4570 t.Error(err)
4571 return
4572 }
4573 res.Body.Close()
4574 }()
4575
4576 <-gotReq
4577 pw.Close()
4578 <-gotRes
4579 }
4580
4581 type wgReadCloser struct {
4582 io.Reader
4583 wg *sync.WaitGroup
4584 closed bool
4585 }
4586
4587 func (c *wgReadCloser) Close() error {
4588 if c.closed {
4589 return net.ErrClosed
4590 }
4591 c.closed = true
4592 c.wg.Done()
4593 return nil
4594 }
4595
4596
4597 func TestTransportPrefersResponseOverWriteError(t *testing.T) {
4598 writeFailedRoundTrip := func(t *testing.T) (*testRoundTrip, *http1TestConn) {
4599 tt := newHTTP1TransportTest(t)
4600
4601 r, w := io.Pipe()
4602 sentReq, _ := http.NewRequest("POST", "http://example.tld/", r)
4603 sentReq.ContentLength = 1000
4604 rt := tt.roundTrip(sentReq)
4605 if rt.done() {
4606 t.Fatalf("RoundTrip unexpectedly returned before reading response")
4607 }
4608
4609 dial := tt.wantDial("tcp", "example.tld:80")
4610 conn := dial.connect()
4611 _ = conn.readRequest()
4612
4613
4614 conn.conn.SetReadBufferSize(5)
4615 go w.Write([]byte("hello, world"))
4616 conn.wantBytes([]byte("hello"))
4617
4618
4619 conn.conn.CloseRead()
4620 synctest.Wait()
4621
4622 return rt, conn
4623 }
4624
4625 synctest.Subtest(t, "empty body", func(t *testing.T) {
4626 rt, conn := writeFailedRoundTrip(t)
4627
4628 synctest.Sleep(1 * time.Millisecond)
4629 if rt.done() {
4630 t.Fatalf("RoundTrip unexpectedly done 1ms after write failure")
4631 }
4632
4633 conn.writeMessage(
4634 "HTTP/1.1 405 OK",
4635 "Content-Length: 0",
4636 "",
4637 )
4638 rt.wantStatus(405)
4639 })
4640
4641 synctest.Subtest(t, "response body", func(t *testing.T) {
4642 rt, conn := writeFailedRoundTrip(t)
4643
4644 synctest.Sleep(1 * time.Millisecond)
4645 if rt.done() {
4646 t.Fatalf("RoundTrip unexpectedly done 1ms after write failure")
4647 }
4648
4649 conn.writeMessage(
4650 "HTTP/1.1 405 OK",
4651 "Content-Length: 2",
4652 "",
4653 "no",
4654 )
4655 rt.wantStatus(405)
4656 rt.wantBody([]byte("no"))
4657 })
4658
4659 synctest.Subtest(t, "conn closed", func(t *testing.T) {
4660 rt, conn := writeFailedRoundTrip(t)
4661
4662 conn.conn.CloseWrite()
4663 if rt.err() == nil {
4664 t.Fatalf("RoundTrip unexpectedly succeeded after write failure")
4665 }
4666
4667 })
4668
4669 synctest.Subtest(t, "no response", func(t *testing.T) {
4670 rt, _ := writeFailedRoundTrip(t)
4671
4672 const timeout = 50 * time.Millisecond
4673 synctest.Sleep(timeout - time.Nanosecond)
4674 if rt.done() {
4675 t.Fatalf("RoundTrip unexpectedly done %v-1ns after write failure", timeout)
4676 }
4677 synctest.Sleep(time.Nanosecond)
4678 if rt.err() == nil {
4679 t.Fatalf("RoundTrip unexpectedly succeeded after write failure")
4680 }
4681 })
4682 }
4683
4684 func TestTransportAutomaticHTTP2(t *testing.T) {
4685 testTransportAutoHTTP(t, &Transport{}, true)
4686 }
4687
4688 func TestTransportAutomaticHTTP2_DialerAndTLSConfigSupportsHTTP2AndTLSConfig(t *testing.T) {
4689 testTransportAutoHTTP(t, &Transport{
4690 ForceAttemptHTTP2: true,
4691 TLSClientConfig: new(tls.Config),
4692 }, true)
4693 }
4694
4695
4696 func TestTransportAutomaticHTTP2_DefaultTransport(t *testing.T) {
4697 testTransportAutoHTTP(t, DefaultTransport.(*Transport), true)
4698 }
4699
4700 func TestTransportAutomaticHTTP2_TLSNextProto(t *testing.T) {
4701 testTransportAutoHTTP(t, &Transport{
4702 TLSNextProto: make(map[string]func(string, *tls.Conn) RoundTripper),
4703 }, false)
4704 }
4705
4706 func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) {
4707 testTransportAutoHTTP(t, &Transport{
4708 TLSClientConfig: new(tls.Config),
4709 }, false)
4710 }
4711
4712 func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) {
4713 testTransportAutoHTTP(t, &Transport{
4714 ExpectContinueTimeout: 1 * time.Second,
4715 }, true)
4716 }
4717
4718 func TestTransportAutomaticHTTP2_Dial(t *testing.T) {
4719 var d net.Dialer
4720 testTransportAutoHTTP(t, &Transport{
4721 Dial: d.Dial,
4722 }, false)
4723 }
4724
4725 func TestTransportAutomaticHTTP2_DialContext(t *testing.T) {
4726 var d net.Dialer
4727 testTransportAutoHTTP(t, &Transport{
4728 DialContext: d.DialContext,
4729 }, false)
4730 }
4731
4732 func TestTransportAutomaticHTTP2_DialTLS(t *testing.T) {
4733 testTransportAutoHTTP(t, &Transport{
4734 DialTLS: func(network, addr string) (net.Conn, error) {
4735 panic("unused")
4736 },
4737 }, false)
4738 }
4739
4740 func testTransportAutoHTTP(t *testing.T, tr *Transport, wantH2 bool) {
4741 CondSkipHTTP2(t)
4742 _, err := tr.RoundTrip(new(Request))
4743 if err == nil {
4744 t.Error("expected error from RoundTrip")
4745 }
4746 if reg := tr.TLSNextProto["h2"] != nil; reg != wantH2 {
4747 t.Errorf("HTTP/2 registered = %v; want %v", reg, wantH2)
4748 }
4749 }
4750
4751
4752
4753
4754
4755
4756
4757
4758 func TestTransportReuseConnEmptyResponseBody(t *testing.T) {
4759 runSynctest(t, testTransportReuseConnEmptyResponseBody)
4760 }
4761 func testTransportReuseConnEmptyResponseBody(t *testing.T, mode testMode) {
4762 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4763 w.Header().Set("X-Addr", r.RemoteAddr)
4764
4765 }))
4766 n := 100
4767 if testing.Short() {
4768 n = 10
4769 }
4770 var firstAddr string
4771 for i := 0; i < n; i++ {
4772 res, err := cst.c.Get(cst.ts.URL)
4773 if err != nil {
4774 log.Fatal(err)
4775 }
4776 addr := res.Header.Get("X-Addr")
4777 if i == 0 {
4778 firstAddr = addr
4779 } else if addr != firstAddr {
4780 t.Fatalf("On request %d, addr %q != original addr %q", i+1, addr, firstAddr)
4781 }
4782 res.Body.Close()
4783 }
4784 }
4785
4786
4787 func TestNoCrashReturningTransportAltConn(t *testing.T) {
4788 cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
4789 if err != nil {
4790 t.Fatal(err)
4791 }
4792 ln := newLocalListener(t)
4793 defer ln.Close()
4794
4795 var wg sync.WaitGroup
4796 SetPendingDialHooks(t, func() { wg.Add(1) }, wg.Done)
4797
4798 testDone := make(chan struct{})
4799 defer close(testDone)
4800 go func() {
4801 tln := tls.NewListener(ln, &tls.Config{
4802 NextProtos: []string{"foo"},
4803 Certificates: []tls.Certificate{cert},
4804 })
4805 sc, err := tln.Accept()
4806 if err != nil {
4807 t.Error(err)
4808 return
4809 }
4810 if err := sc.(*tls.Conn).Handshake(); err != nil {
4811 t.Error(err)
4812 return
4813 }
4814 <-testDone
4815 sc.Close()
4816 }()
4817
4818 addr := ln.Addr().String()
4819
4820 req, _ := NewRequest("GET", "https://fake.tld/", nil)
4821 cancel := make(chan struct{})
4822 req.Cancel = cancel
4823
4824 doReturned := make(chan bool, 1)
4825 madeRoundTripper := make(chan bool, 1)
4826
4827 tr := &Transport{
4828 DisableKeepAlives: true,
4829 TLSNextProto: map[string]func(string, *tls.Conn) RoundTripper{
4830 "foo": func(authority string, c *tls.Conn) RoundTripper {
4831 madeRoundTripper <- true
4832 return funcRoundTripper(func() {
4833 t.Error("foo RoundTripper should not be called")
4834 })
4835 },
4836 },
4837 Dial: func(_, _ string) (net.Conn, error) {
4838 panic("shouldn't be called")
4839 },
4840 DialTLS: func(_, _ string) (net.Conn, error) {
4841 tc, err := tls.Dial("tcp", addr, &tls.Config{
4842 InsecureSkipVerify: true,
4843 NextProtos: []string{"foo"},
4844 })
4845 if err != nil {
4846 return nil, err
4847 }
4848 if err := tc.Handshake(); err != nil {
4849 return nil, err
4850 }
4851 close(cancel)
4852 <-doReturned
4853 return tc, nil
4854 },
4855 }
4856 c := &Client{Transport: tr}
4857
4858 _, err = c.Do(req)
4859 if ue, ok := err.(*url.Error); !ok || ue.Err != ExportErrRequestCanceledConn {
4860 t.Fatalf("Do error = %v; want url.Error with errRequestCanceledConn", err)
4861 }
4862
4863 doReturned <- true
4864 <-madeRoundTripper
4865 wg.Wait()
4866 }
4867
4868 func TestTransportReuseConnection_Gzip_Chunked(t *testing.T) {
4869 runSynctest(t, func(t *testing.T, mode testMode) {
4870 testTransportReuseConnection_Gzip(t, mode, true)
4871 })
4872 }
4873
4874 func TestTransportReuseConnection_Gzip_ContentLength(t *testing.T) {
4875 runSynctest(t, func(t *testing.T, mode testMode) {
4876 testTransportReuseConnection_Gzip(t, mode, false)
4877 })
4878 }
4879
4880
4881 func testTransportReuseConnection_Gzip(t *testing.T, mode testMode, chunked bool) {
4882 addr := make(chan string, 2)
4883 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4884 addr <- r.RemoteAddr
4885 w.Header().Set("Content-Encoding", "gzip")
4886 if chunked {
4887 w.(Flusher).Flush()
4888 }
4889 w.Write(rgz)
4890 })).ts
4891 c := ts.Client()
4892
4893 trace := &httptrace.ClientTrace{
4894 GetConn: func(hostPort string) { t.Logf("GetConn(%q)", hostPort) },
4895 GotConn: func(ci httptrace.GotConnInfo) { t.Logf("GotConn(%+v)", ci) },
4896 PutIdleConn: func(err error) { t.Logf("PutIdleConn(%v)", err) },
4897 ConnectStart: func(network, addr string) { t.Logf("ConnectStart(%q, %q)", network, addr) },
4898 ConnectDone: func(network, addr string, err error) { t.Logf("ConnectDone(%q, %q, %v)", network, addr, err) },
4899 }
4900 ctx := httptrace.WithClientTrace(context.Background(), trace)
4901
4902 for i := 0; i < 2; i++ {
4903 req, _ := NewRequest("GET", ts.URL, nil)
4904 req = req.WithContext(ctx)
4905 res, err := c.Do(req)
4906 if err != nil {
4907 t.Fatal(err)
4908 }
4909 buf := make([]byte, len(rgz))
4910 if n, err := io.ReadFull(res.Body, buf); err != nil {
4911 t.Errorf("%d. ReadFull = %v, %v", i, n, err)
4912 }
4913
4914
4915
4916 }
4917 a1, a2 := <-addr, <-addr
4918 if a1 != a2 {
4919 t.Fatalf("didn't reuse connection")
4920 }
4921 }
4922
4923 func TestTransportResponseHeaderLength(t *testing.T) {
4924 runSynctest(t, testTransportResponseHeaderLength)
4925 }
4926 func testTransportResponseHeaderLength(t *testing.T, mode testMode) {
4927 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4928 if r.URL.Path == "/long" {
4929 w.Header().Set("Long", strings.Repeat("a", 1<<20))
4930 }
4931 })).ts
4932 c := ts.Client()
4933 c.Transport.(*Transport).MaxResponseHeaderBytes = 512 << 10
4934
4935 if res, err := c.Get(ts.URL); err != nil {
4936 t.Fatal(err)
4937 } else {
4938 res.Body.Close()
4939 }
4940
4941 res, err := c.Get(ts.URL + "/long")
4942 if err == nil {
4943 defer res.Body.Close()
4944 var n int64
4945 for k, vv := range res.Header {
4946 for _, v := range vv {
4947 n += int64(len(k)) + int64(len(v))
4948 }
4949 }
4950 t.Fatalf("Unexpected success. Got %v and %d bytes of response headers", res.Status, n)
4951 }
4952 }
4953
4954 func TestTransportEventTrace(t *testing.T) {
4955 runNoSynctest(t, func(t *testing.T, mode testMode) {
4956 testTransportEventTrace(t, mode, false)
4957 }, testNotParallel, http3SkippedMode)
4958 }
4959
4960
4961 func TestTransportEventTrace_NoHooks(t *testing.T) {
4962 runNoSynctest(t, func(t *testing.T, mode testMode) {
4963 testTransportEventTrace(t, mode, true)
4964 }, testNotParallel, http3SkippedMode)
4965 }
4966
4967 func testTransportEventTrace(t *testing.T, mode testMode, noHooks bool) {
4968 const resBody = "some body"
4969 gotWroteReqEvent := make(chan struct{}, 500)
4970 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
4971 if r.Method == "GET" {
4972
4973 return
4974 }
4975 if _, err := io.ReadAll(r.Body); err != nil {
4976 t.Error(err)
4977 }
4978 if !noHooks {
4979 <-gotWroteReqEvent
4980 }
4981 io.WriteString(w, resBody)
4982 }), func(tr *Transport) {
4983 if tr.TLSClientConfig != nil {
4984 tr.TLSClientConfig.InsecureSkipVerify = true
4985 }
4986 }, optRealNet)
4987 defer cst.close()
4988
4989 cst.tr.ExpectContinueTimeout = 1 * time.Second
4990
4991 var mu sync.Mutex
4992 var buf strings.Builder
4993 logf := func(format string, args ...any) {
4994 mu.Lock()
4995 defer mu.Unlock()
4996 fmt.Fprintf(&buf, format, args...)
4997 buf.WriteByte('\n')
4998 }
4999
5000 addrStr := cst.ts.Listener.Addr().String()
5001 ip, port, err := net.SplitHostPort(addrStr)
5002 if err != nil {
5003 t.Fatal(err)
5004 }
5005
5006
5007 ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, network, host string) ([]net.IPAddr, error) {
5008 if host != "dns-is-faked.golang" {
5009 t.Errorf("unexpected DNS host lookup for %q/%q", network, host)
5010 return nil, nil
5011 }
5012 return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
5013 })
5014
5015 body := "some body"
5016 req, _ := NewRequest("POST", cst.scheme()+"://dns-is-faked.golang:"+port, strings.NewReader(body))
5017 req.Header["X-Foo-Multiple-Vals"] = []string{"bar", "baz"}
5018 trace := &httptrace.ClientTrace{
5019 GetConn: func(hostPort string) { logf("Getting conn for %v ...", hostPort) },
5020 GotConn: func(ci httptrace.GotConnInfo) { logf("got conn: %+v", ci) },
5021 GotFirstResponseByte: func() { logf("first response byte") },
5022 PutIdleConn: func(err error) { logf("PutIdleConn = %v", err) },
5023 DNSStart: func(e httptrace.DNSStartInfo) { logf("DNS start: %+v", e) },
5024 DNSDone: func(e httptrace.DNSDoneInfo) { logf("DNS done: %+v", e) },
5025 ConnectStart: func(network, addr string) { logf("ConnectStart: Connecting to %s %s ...", network, addr) },
5026 ConnectDone: func(network, addr string, err error) {
5027 if err != nil {
5028 t.Errorf("ConnectDone: %v", err)
5029 }
5030 logf("ConnectDone: connected to %s %s = %v", network, addr, err)
5031 },
5032 WroteHeaderField: func(key string, value []string) {
5033 logf("WroteHeaderField: %s: %v", key, value)
5034 },
5035 WroteHeaders: func() {
5036 logf("WroteHeaders")
5037 },
5038 Wait100Continue: func() { logf("Wait100Continue") },
5039 Got100Continue: func() { logf("Got100Continue") },
5040 WroteRequest: func(e httptrace.WroteRequestInfo) {
5041 logf("WroteRequest: %+v", e)
5042 gotWroteReqEvent <- struct{}{}
5043 },
5044 }
5045 if mode == http2Mode {
5046 trace.TLSHandshakeStart = func() { logf("tls handshake start") }
5047 trace.TLSHandshakeDone = func(s tls.ConnectionState, err error) {
5048 logf("tls handshake done. ConnectionState = %v \n err = %v", s, err)
5049 }
5050 }
5051 if noHooks {
5052
5053 *trace = httptrace.ClientTrace{}
5054 }
5055 req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
5056
5057 req.Header.Set("Expect", "100-continue")
5058 res, err := cst.c.Do(req)
5059 if err != nil {
5060 t.Fatal(err)
5061 }
5062 logf("got roundtrip.response")
5063 slurp, err := io.ReadAll(res.Body)
5064 if err != nil {
5065 t.Fatal(err)
5066 }
5067 logf("consumed body")
5068 if string(slurp) != resBody || res.StatusCode != 200 {
5069 t.Fatalf("Got %q, %v; want %q, 200 OK", slurp, res.Status, resBody)
5070 }
5071 res.Body.Close()
5072
5073 if noHooks {
5074
5075
5076
5077 return
5078 }
5079
5080 mu.Lock()
5081 got := buf.String()
5082 mu.Unlock()
5083
5084 wantOnce := func(sub string) {
5085 if strings.Count(got, sub) != 1 {
5086 t.Errorf("expected substring %q exactly once in output.", sub)
5087 }
5088 }
5089 wantOnceOrMore := func(sub string) {
5090 if strings.Count(got, sub) == 0 {
5091 t.Errorf("expected substring %q at least once in output.", sub)
5092 }
5093 }
5094 wantOnce("Getting conn for dns-is-faked.golang:" + port)
5095 wantOnce("DNS start: {Host:dns-is-faked.golang}")
5096 wantOnce("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err:<nil> Coalesced:false}")
5097 wantOnce("got conn: {")
5098 wantOnceOrMore("Connecting to tcp " + addrStr)
5099 wantOnceOrMore("connected to tcp " + addrStr + " = <nil>")
5100 wantOnce("Reused:false WasIdle:false IdleTime:0s")
5101 wantOnce("first response byte")
5102 if mode == http2Mode {
5103 wantOnce("tls handshake start")
5104 wantOnce("tls handshake done")
5105 } else {
5106 wantOnce("PutIdleConn = <nil>")
5107 wantOnce("WroteHeaderField: User-Agent: [Go-http-client/1.1]")
5108
5109
5110 wantOnce(fmt.Sprintf("WroteHeaderField: Host: [dns-is-faked.golang:%s]", port))
5111 wantOnce(fmt.Sprintf("WroteHeaderField: Content-Length: [%d]", len(body)))
5112 wantOnce("WroteHeaderField: X-Foo-Multiple-Vals: [bar baz]")
5113 wantOnce("WroteHeaderField: Accept-Encoding: [gzip]")
5114 }
5115 wantOnce("WroteHeaders")
5116 wantOnce("Wait100Continue")
5117 wantOnce("Got100Continue")
5118 wantOnce("WroteRequest: {Err:<nil>}")
5119 if strings.Contains(got, " to udp ") {
5120 t.Errorf("should not see UDP (DNS) connections")
5121 }
5122 if t.Failed() {
5123 t.Errorf("Output:\n%s", got)
5124 }
5125
5126
5127 req, _ = NewRequest("GET", cst.scheme()+"://dns-is-faked.golang:"+port, nil)
5128 req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
5129 res, err = cst.c.Do(req)
5130 if err != nil {
5131 t.Fatal(err)
5132 }
5133 if res.StatusCode != 200 {
5134 t.Fatal(res.Status)
5135 }
5136 res.Body.Close()
5137
5138 mu.Lock()
5139 got = buf.String()
5140 mu.Unlock()
5141
5142 sub := "Getting conn for dns-is-faked.golang:"
5143 if gotn, want := strings.Count(got, sub), 2; gotn != want {
5144 t.Errorf("substring %q appeared %d times; want %d. Log:\n%s", sub, gotn, want, got)
5145 }
5146
5147 }
5148
5149 func TestTransportEventTraceTLSVerify(t *testing.T) {
5150 runNoSynctest(t, testTransportEventTraceTLSVerify, []testMode{https1Mode, http2Mode})
5151 }
5152 func testTransportEventTraceTLSVerify(t *testing.T, mode testMode) {
5153 var mu sync.Mutex
5154 var buf strings.Builder
5155 logf := func(format string, args ...any) {
5156 mu.Lock()
5157 defer mu.Unlock()
5158 fmt.Fprintf(&buf, format, args...)
5159 buf.WriteByte('\n')
5160 }
5161
5162 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5163 t.Error("Unexpected request")
5164 }), func(ts *httptest.Server) {
5165 ts.Config.ErrorLog = log.New(funcWriter(func(p []byte) (int, error) {
5166 logf("%s", p)
5167 return len(p), nil
5168 }), "", 0)
5169 }, optRealNet).ts
5170
5171 certpool := x509.NewCertPool()
5172 certpool.AddCert(ts.Certificate())
5173
5174 c := &Client{Transport: &Transport{
5175 TLSClientConfig: &tls.Config{
5176 ServerName: "dns-is-faked.golang",
5177 RootCAs: certpool,
5178 },
5179 }}
5180
5181 trace := &httptrace.ClientTrace{
5182 TLSHandshakeStart: func() { logf("TLSHandshakeStart") },
5183 TLSHandshakeDone: func(s tls.ConnectionState, err error) {
5184 logf("TLSHandshakeDone: ConnectionState = %v \n err = %v", s, err)
5185 },
5186 }
5187
5188 req, _ := NewRequest("GET", ts.URL, nil)
5189 req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace))
5190 _, err := c.Do(req)
5191 if err == nil {
5192 t.Error("Expected request to fail TLS verification")
5193 }
5194
5195 mu.Lock()
5196 got := buf.String()
5197 mu.Unlock()
5198
5199 wantOnce := func(sub string) {
5200 if strings.Count(got, sub) != 1 {
5201 t.Errorf("expected substring %q exactly once in output.", sub)
5202 }
5203 }
5204
5205 wantOnce("TLSHandshakeStart")
5206 wantOnce("TLSHandshakeDone")
5207 wantOnce("err = tls: failed to verify certificate: x509: certificate is valid for example.com")
5208
5209 if t.Failed() {
5210 t.Errorf("Output:\n%s", got)
5211 }
5212 }
5213
5214 var isDNSHijacked = sync.OnceValue(func() bool {
5215 addrs, _ := net.LookupHost("dns-should-not-resolve.golang")
5216 return len(addrs) != 0
5217 })
5218
5219 func skipIfDNSHijacked(t *testing.T) {
5220
5221
5222
5223 if isDNSHijacked() {
5224 t.Skip("skipping; test requires non-hijacking DNS server")
5225 }
5226 }
5227
5228 func TestTransportEventTraceRealDNS(t *testing.T) {
5229 skipIfDNSHijacked(t)
5230 tr := &Transport{}
5231 defer tr.CloseIdleConnections()
5232 c := &Client{Transport: tr}
5233
5234 var mu sync.Mutex
5235 var buf strings.Builder
5236 logf := func(format string, args ...any) {
5237 mu.Lock()
5238 defer mu.Unlock()
5239 fmt.Fprintf(&buf, format, args...)
5240 buf.WriteByte('\n')
5241 }
5242
5243 req, _ := NewRequest("GET", "http://dns-should-not-resolve.golang:80", nil)
5244 trace := &httptrace.ClientTrace{
5245 DNSStart: func(e httptrace.DNSStartInfo) { logf("DNSStart: %+v", e) },
5246 DNSDone: func(e httptrace.DNSDoneInfo) { logf("DNSDone: %+v", e) },
5247 ConnectStart: func(network, addr string) { logf("ConnectStart: %s %s", network, addr) },
5248 ConnectDone: func(network, addr string, err error) { logf("ConnectDone: %s %s %v", network, addr, err) },
5249 }
5250 req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace))
5251
5252 resp, err := c.Do(req)
5253 if err == nil {
5254 resp.Body.Close()
5255 t.Fatal("expected error during DNS lookup")
5256 }
5257
5258 mu.Lock()
5259 got := buf.String()
5260 mu.Unlock()
5261
5262 wantSub := func(sub string) {
5263 if !strings.Contains(got, sub) {
5264 t.Errorf("expected substring %q in output.", sub)
5265 }
5266 }
5267 wantSub("DNSStart: {Host:dns-should-not-resolve.golang}")
5268 wantSub("DNSDone: {Addrs:[] Err:")
5269 if strings.Contains(got, "ConnectStart") || strings.Contains(got, "ConnectDone") {
5270 t.Errorf("should not see Connect events")
5271 }
5272 if t.Failed() {
5273 t.Errorf("Output:\n%s", got)
5274 }
5275 }
5276
5277
5278 func TestTransportRejectsAlphaPort(t *testing.T) {
5279 res, err := Get("http://dummy.tld:123foo/bar")
5280 if err == nil {
5281 res.Body.Close()
5282 t.Fatal("unexpected success")
5283 }
5284 ue, ok := err.(*url.Error)
5285 if !ok {
5286 t.Fatalf("got %#v; want *url.Error", err)
5287 }
5288 got := ue.Err.Error()
5289 want := `invalid port ":123foo" after host`
5290 if got != want {
5291 t.Errorf("got error %q; want %q", got, want)
5292 }
5293 }
5294
5295
5296
5297 func TestTLSHandshakeTrace(t *testing.T) {
5298 runNoSynctest(t, testTLSHandshakeTrace, []testMode{https1Mode, http2Mode})
5299 }
5300 func testTLSHandshakeTrace(t *testing.T, mode testMode) {
5301 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}), optRealNet).ts
5302
5303 var mu sync.Mutex
5304 var start, done bool
5305 trace := &httptrace.ClientTrace{
5306 TLSHandshakeStart: func() {
5307 mu.Lock()
5308 defer mu.Unlock()
5309 start = true
5310 },
5311 TLSHandshakeDone: func(s tls.ConnectionState, err error) {
5312 mu.Lock()
5313 defer mu.Unlock()
5314 done = true
5315 if err != nil {
5316 t.Fatal("Expected error to be nil but was:", err)
5317 }
5318 },
5319 }
5320
5321 c := ts.Client()
5322 req, err := NewRequest("GET", ts.URL, nil)
5323 if err != nil {
5324 t.Fatal("Unable to construct test request:", err)
5325 }
5326 req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
5327
5328 r, err := c.Do(req)
5329 if err != nil {
5330 t.Fatal("Unexpected error making request:", err)
5331 }
5332 r.Body.Close()
5333 mu.Lock()
5334 defer mu.Unlock()
5335 if !start {
5336 t.Fatal("Expected TLSHandshakeStart to be called, but wasn't")
5337 }
5338 if !done {
5339 t.Fatal("Expected TLSHandshakeDone to be called, but wasn't")
5340 }
5341 }
5342
5343 func TestTransportIdleConnTimeout(t *testing.T) {
5344 runSynctest(t, testTransportIdleConnTimeout, http3SkippedMode)
5345 }
5346 func testTransportIdleConnTimeout(t *testing.T, mode testMode) {
5347 timeout := 1 * time.Millisecond
5348 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5349
5350 }))
5351 tr := cst.tr
5352 tr.IdleConnTimeout = timeout
5353 defer tr.CloseIdleConnections()
5354 c := &Client{Transport: tr}
5355
5356 idleConns := func() []string {
5357 return tr.IdleConnStrsForTesting()
5358 }
5359
5360 var conn string
5361 doReq := func(n int) (timeoutOk bool) {
5362 req, _ := NewRequest("GET", cst.ts.URL, nil)
5363 req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
5364 PutIdleConn: func(err error) {
5365 if err != nil {
5366 t.Errorf("failed to keep idle conn: %v", err)
5367 }
5368 },
5369 }))
5370 res, err := c.Do(req)
5371 if err != nil {
5372 if strings.Contains(err.Error(), "use of closed network connection") {
5373 t.Logf("req %v: connection closed prematurely", n)
5374 return false
5375 }
5376 }
5377 if err == nil {
5378 res.Body.Close()
5379 }
5380 conns := idleConns()
5381 if len(conns) != 1 {
5382 if len(conns) == 0 {
5383 t.Logf("req %v: no idle conns", n)
5384 return false
5385 }
5386 t.Fatalf("req %v: unexpected number of idle conns: %q", n, conns)
5387 }
5388 if conn == "" {
5389 conn = conns[0]
5390 }
5391 if conn != conns[0] {
5392 t.Logf("req %v: cached connection changed; expected the same one throughout the test", n)
5393 return false
5394 }
5395 return true
5396 }
5397 for i := 0; i < 3; i++ {
5398 if !doReq(i) {
5399 t.Fatalf("request %v failed", i)
5400 }
5401 time.Sleep(timeout / 2)
5402 }
5403
5404 waitCondition(t, timeout/2, func(d time.Duration) bool {
5405 if got := idleConns(); len(got) != 0 {
5406 if d >= timeout*3/2 {
5407 t.Logf("after %v, idle conns = %q", d, got)
5408 }
5409 return false
5410 }
5411 return true
5412 })
5413 }
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426 func TestIdleConnH2Crash(t *testing.T) { runNoSynctest(t, testIdleConnH2Crash, []testMode{http2Mode}) }
5427 func testIdleConnH2Crash(t *testing.T, mode testMode) {
5428 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5429
5430 }), optRealNet)
5431
5432 ctx, cancel := context.WithCancel(context.Background())
5433 defer cancel()
5434
5435 sawDoErr := make(chan bool, 1)
5436 testDone := make(chan struct{})
5437 defer close(testDone)
5438
5439 cst.tr.IdleConnTimeout = 5 * time.Millisecond
5440 cst.tr.DialTLS = func(network, addr string) (net.Conn, error) {
5441 c, err := tls.Dial(network, addr, &tls.Config{
5442 InsecureSkipVerify: true,
5443 NextProtos: []string{"h2"},
5444 })
5445 if err != nil {
5446 t.Error(err)
5447 return nil, err
5448 }
5449 if cs := c.ConnectionState(); cs.NegotiatedProtocol != "h2" {
5450 t.Errorf("protocol = %q; want %q", cs.NegotiatedProtocol, "h2")
5451 c.Close()
5452 return nil, errors.New("bogus")
5453 }
5454
5455 cancel()
5456
5457 select {
5458 case <-sawDoErr:
5459 case <-testDone:
5460 }
5461 return c, nil
5462 }
5463
5464 req, _ := NewRequest("GET", cst.ts.URL, nil)
5465 req = req.WithContext(ctx)
5466 res, err := cst.c.Do(req)
5467 if err == nil {
5468 res.Body.Close()
5469 t.Fatal("unexpected success")
5470 }
5471 sawDoErr <- true
5472
5473
5474 time.Sleep(cst.tr.IdleConnTimeout * 10)
5475 }
5476
5477 type funcConn struct {
5478 net.Conn
5479 read func([]byte) (int, error)
5480 write func([]byte) (int, error)
5481 }
5482
5483 func (c funcConn) Read(p []byte) (int, error) { return c.read(p) }
5484 func (c funcConn) Write(p []byte) (int, error) { return c.write(p) }
5485 func (c funcConn) Close() error { return nil }
5486
5487
5488
5489 func TestTransportReturnsPeekError(t *testing.T) {
5490 errValue := errors.New("specific error value")
5491
5492 wrote := make(chan struct{})
5493 wroteOnce := sync.OnceFunc(func() { close(wrote) })
5494
5495 tr := &Transport{
5496 Dial: func(network, addr string) (net.Conn, error) {
5497 c := funcConn{
5498 read: func([]byte) (int, error) {
5499 <-wrote
5500 return 0, errValue
5501 },
5502 write: func(p []byte) (int, error) {
5503 wroteOnce()
5504 return len(p), nil
5505 },
5506 }
5507 return c, nil
5508 },
5509 }
5510 _, err := tr.RoundTrip(httptest.NewRequest("GET", "http://fake.tld/", nil))
5511 if err != errValue {
5512 t.Errorf("error = %#v; want %v", err, errValue)
5513 }
5514 }
5515
5516
5517 func TestTransportIDNA(t *testing.T) { runNoSynctest(t, testTransportIDNA, http3SkippedMode) }
5518 func testTransportIDNA(t *testing.T, mode testMode) {
5519 const uniDomain = "гофер.го"
5520 const punyDomain = "xn--c1ae0ajs.xn--c1aw"
5521
5522 var port string
5523 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5524 want := punyDomain + ":" + port
5525 if r.Host != want {
5526 t.Errorf("Host header = %q; want %q", r.Host, want)
5527 }
5528 if mode == http2Mode {
5529 if r.TLS == nil {
5530 t.Errorf("r.TLS == nil")
5531 } else if r.TLS.ServerName != punyDomain {
5532 t.Errorf("TLS.ServerName = %q; want %q", r.TLS.ServerName, punyDomain)
5533 }
5534 }
5535 w.Header().Set("Hit-Handler", "1")
5536 }), func(tr *Transport) {
5537 if tr.TLSClientConfig != nil {
5538 tr.TLSClientConfig.InsecureSkipVerify = true
5539 }
5540 }, optRealNet)
5541
5542 ip, port, err := net.SplitHostPort(cst.ts.Listener.Addr().String())
5543 if err != nil {
5544 t.Fatal(err)
5545 }
5546
5547
5548 ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, network, host string) ([]net.IPAddr, error) {
5549 if host != punyDomain {
5550 t.Errorf("got DNS host lookup for %q/%q; want %q", network, host, punyDomain)
5551 return nil, nil
5552 }
5553 return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
5554 })
5555
5556 req, _ := NewRequest("GET", cst.scheme()+"://"+uniDomain+":"+port, nil)
5557 trace := &httptrace.ClientTrace{
5558 GetConn: func(hostPort string) {
5559 want := net.JoinHostPort(punyDomain, port)
5560 if hostPort != want {
5561 t.Errorf("getting conn for %q; want %q", hostPort, want)
5562 }
5563 },
5564 DNSStart: func(e httptrace.DNSStartInfo) {
5565 if e.Host != punyDomain {
5566 t.Errorf("DNSStart Host = %q; want %q", e.Host, punyDomain)
5567 }
5568 },
5569 }
5570 req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
5571
5572 res, err := cst.tr.RoundTrip(req)
5573 if err != nil {
5574 t.Fatal(err)
5575 }
5576 defer res.Body.Close()
5577 if res.Header.Get("Hit-Handler") != "1" {
5578 out, err := httputil.DumpResponse(res, true)
5579 if err != nil {
5580 t.Fatal(err)
5581 }
5582 t.Errorf("Response body wasn't from Handler. Got:\n%s\n", out)
5583 }
5584 }
5585
5586
5587 func TestTransportProxyConnectHeader(t *testing.T) {
5588 runSynctest(t, testTransportProxyConnectHeader, []testMode{http1Mode})
5589 }
5590 func testTransportProxyConnectHeader(t *testing.T, mode testMode) {
5591 reqc := make(chan *Request, 1)
5592 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5593 if r.Method != "CONNECT" {
5594 t.Errorf("method = %q; want CONNECT", r.Method)
5595 }
5596 reqc <- r
5597 c, _, err := w.(Hijacker).Hijack()
5598 if err != nil {
5599 t.Errorf("Hijack: %v", err)
5600 return
5601 }
5602 c.Close()
5603 })).ts
5604
5605 c := ts.Client()
5606 c.Transport.(*Transport).Proxy = func(r *Request) (*url.URL, error) {
5607 return url.Parse(ts.URL)
5608 }
5609 c.Transport.(*Transport).ProxyConnectHeader = Header{
5610 "User-Agent": {"foo"},
5611 "Other": {"bar"},
5612 }
5613
5614 res, err := c.Get("https://dummy.tld/")
5615 if err == nil {
5616 res.Body.Close()
5617 t.Errorf("unexpected success")
5618 }
5619
5620 r := <-reqc
5621 if got, want := r.Header.Get("User-Agent"), "foo"; got != want {
5622 t.Errorf("CONNECT request User-Agent = %q; want %q", got, want)
5623 }
5624 if got, want := r.Header.Get("Other"), "bar"; got != want {
5625 t.Errorf("CONNECT request Other = %q; want %q", got, want)
5626 }
5627 }
5628
5629 func TestTransportProxyGetConnectHeader(t *testing.T) {
5630 runSynctest(t, testTransportProxyGetConnectHeader, []testMode{http1Mode})
5631 }
5632 func testTransportProxyGetConnectHeader(t *testing.T, mode testMode) {
5633 reqc := make(chan *Request, 1)
5634 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5635 if r.Method != "CONNECT" {
5636 t.Errorf("method = %q; want CONNECT", r.Method)
5637 }
5638 reqc <- r
5639 c, _, err := w.(Hijacker).Hijack()
5640 if err != nil {
5641 t.Errorf("Hijack: %v", err)
5642 return
5643 }
5644 c.Close()
5645 })).ts
5646
5647 c := ts.Client()
5648 c.Transport.(*Transport).Proxy = func(r *Request) (*url.URL, error) {
5649 return url.Parse(ts.URL)
5650 }
5651
5652 c.Transport.(*Transport).ProxyConnectHeader = Header{
5653 "User-Agent": {"foo"},
5654 "Other": {"bar"},
5655 }
5656 c.Transport.(*Transport).GetProxyConnectHeader = func(ctx context.Context, proxyURL *url.URL, target string) (Header, error) {
5657 return Header{
5658 "User-Agent": {"foo2"},
5659 "Other": {"bar2"},
5660 }, nil
5661 }
5662
5663 res, err := c.Get("https://dummy.tld/")
5664 if err == nil {
5665 res.Body.Close()
5666 t.Errorf("unexpected success")
5667 }
5668
5669 r := <-reqc
5670 if got, want := r.Header.Get("User-Agent"), "foo2"; got != want {
5671 t.Errorf("CONNECT request User-Agent = %q; want %q", got, want)
5672 }
5673 if got, want := r.Header.Get("Other"), "bar2"; got != want {
5674 t.Errorf("CONNECT request Other = %q; want %q", got, want)
5675 }
5676 }
5677
5678 var errFakeRoundTrip = errors.New("fake roundtrip")
5679
5680 type funcRoundTripper func()
5681
5682 func (fn funcRoundTripper) RoundTrip(*Request) (*Response, error) {
5683 fn()
5684 return nil, errFakeRoundTrip
5685 }
5686
5687 func wantBody(res *Response, err error, want string) error {
5688 if err != nil {
5689 return err
5690 }
5691 slurp, err := io.ReadAll(res.Body)
5692 if err != nil {
5693 return fmt.Errorf("error reading body: %v", err)
5694 }
5695 if string(slurp) != want {
5696 return fmt.Errorf("body = %q; want %q", slurp, want)
5697 }
5698 if err := res.Body.Close(); err != nil {
5699 return fmt.Errorf("body Close = %v", err)
5700 }
5701 return nil
5702 }
5703
5704 func newLocalListener(t *testing.T) net.Listener {
5705 ln, err := net.Listen("tcp", "127.0.0.1:0")
5706 if err != nil {
5707 ln, err = net.Listen("tcp6", "[::1]:0")
5708 }
5709 if err != nil {
5710 t.Fatal(err)
5711 }
5712 return ln
5713 }
5714
5715 type countCloseReader struct {
5716 n *int
5717 io.Reader
5718 }
5719
5720 func (cr countCloseReader) Close() error {
5721 (*cr.n)++
5722 return nil
5723 }
5724
5725
5726 var rgz = []byte{
5727 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
5728 0x00, 0x00, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73,
5729 0x69, 0x76, 0x65, 0x00, 0x92, 0xef, 0xe6, 0xe0,
5730 0x60, 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2,
5731 0xe2, 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17,
5732 0x00, 0xe8, 0xff, 0x92, 0xef, 0xe6, 0xe0, 0x60,
5733 0x00, 0x83, 0xa2, 0xd4, 0xe4, 0xd2, 0xa2, 0xe2,
5734 0xcc, 0xb2, 0x54, 0x06, 0x00, 0x00, 0x17, 0x00,
5735 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16, 0x06, 0x00,
5736 0x05, 0x00, 0xfa, 0xff, 0x42, 0x12, 0x46, 0x16,
5737 0x06, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00, 0x05,
5738 0x00, 0xfa, 0xff, 0x00, 0x14, 0x00, 0xeb, 0xff,
5739 0x42, 0x12, 0x46, 0x16, 0x06, 0x00, 0x05, 0x00,
5740 0xfa, 0xff, 0x00, 0x05, 0x00, 0xfa, 0xff, 0x00,
5741 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
5742 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88,
5743 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00, 0xeb, 0xff,
5744 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x14, 0x00,
5745 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00,
5746 0x14, 0x00, 0xeb, 0xff, 0x42, 0x88, 0x21, 0xc4,
5747 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
5748 0x00, 0xff, 0xff, 0x00, 0x17, 0x00, 0xe8, 0xff,
5749 0x42, 0x88, 0x21, 0xc4, 0x00, 0x00, 0x00, 0x00,
5750 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
5751 0x17, 0x00, 0xe8, 0xff, 0x42, 0x12, 0x46, 0x16,
5752 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08,
5753 0x00, 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa,
5754 0x00, 0x00, 0x00, 0x42, 0x12, 0x46, 0x16, 0x06,
5755 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x08, 0x00,
5756 0xf7, 0xff, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
5757 0x00, 0x00, 0x3d, 0xb1, 0x20, 0x85, 0xfa, 0x00,
5758 0x00, 0x00,
5759 }
5760
5761
5762
5763 func TestMissingStatusNoPanic(t *testing.T) {
5764 t.Parallel()
5765
5766 const want = "unknown status code"
5767
5768 ln := newLocalListener(t)
5769 addr := ln.Addr().String()
5770 done := make(chan bool)
5771 fullAddrURL := fmt.Sprintf("http://%s", addr)
5772 raw := "HTTP/1.1 400\r\n" +
5773 "Date: Wed, 30 Aug 2017 19:09:27 GMT\r\n" +
5774 "Content-Type: text/html; charset=utf-8\r\n" +
5775 "Content-Length: 10\r\n" +
5776 "Last-Modified: Wed, 30 Aug 2017 19:02:02 GMT\r\n" +
5777 "Vary: Accept-Encoding\r\n\r\n" +
5778 "Aloha Olaa"
5779
5780 go func() {
5781 defer close(done)
5782
5783 conn, _ := ln.Accept()
5784 if conn != nil {
5785 io.WriteString(conn, raw)
5786 io.ReadAll(conn)
5787 conn.Close()
5788 }
5789 }()
5790
5791 proxyURL, err := url.Parse(fullAddrURL)
5792 if err != nil {
5793 t.Fatalf("proxyURL: %v", err)
5794 }
5795
5796 tr := &Transport{Proxy: ProxyURL(proxyURL)}
5797
5798 req, _ := NewRequest("GET", "https://golang.org/", nil)
5799 res, err, panicked := doFetchCheckPanic(tr, req)
5800 if panicked {
5801 t.Error("panicked, expecting an error")
5802 }
5803 if res != nil && res.Body != nil {
5804 io.Copy(io.Discard, res.Body)
5805 res.Body.Close()
5806 }
5807
5808 if err == nil || !strings.Contains(err.Error(), want) {
5809 t.Errorf("got=%v want=%q", err, want)
5810 }
5811
5812 ln.Close()
5813 <-done
5814 }
5815
5816 func doFetchCheckPanic(tr *Transport, req *Request) (res *Response, err error, panicked bool) {
5817 defer func() {
5818 if r := recover(); r != nil {
5819 panicked = true
5820 }
5821 }()
5822 res, err = tr.RoundTrip(req)
5823 return
5824 }
5825
5826
5827
5828 func TestNoBodyOnChunked304Response(t *testing.T) {
5829 runSynctest(t, testNoBodyOnChunked304Response, []testMode{http1Mode})
5830 }
5831 func testNoBodyOnChunked304Response(t *testing.T, mode testMode) {
5832 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5833 conn, buf, _ := w.(Hijacker).Hijack()
5834 buf.Write([]byte("HTTP/1.1 304 NOT MODIFIED\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n"))
5835 buf.Flush()
5836 conn.Close()
5837 }))
5838
5839
5840
5841
5842
5843 cst.tr.DisableKeepAlives = true
5844
5845 res, err := cst.c.Get(cst.ts.URL)
5846 if err != nil {
5847 t.Fatal(err)
5848 }
5849
5850 if res.Body != NoBody {
5851 t.Errorf("Unexpected body on 304 response")
5852 }
5853 }
5854
5855 type funcWriter func([]byte) (int, error)
5856
5857 func (f funcWriter) Write(p []byte) (int, error) { return f(p) }
5858
5859 type doneContext struct {
5860 context.Context
5861 err error
5862 }
5863
5864 func (doneContext) Done() <-chan struct{} {
5865 c := make(chan struct{})
5866 close(c)
5867 return c
5868 }
5869
5870 func (d doneContext) Err() error { return d.err }
5871
5872
5873 func TestTransportCheckContextDoneEarly(t *testing.T) {
5874 tr := &Transport{}
5875 req, _ := NewRequest("GET", "http://fake.example/", nil)
5876 wantErr := errors.New("some error")
5877 req = req.WithContext(doneContext{context.Background(), wantErr})
5878 _, err := tr.RoundTrip(req)
5879 if err != wantErr {
5880 t.Errorf("error = %v; want %v", err, wantErr)
5881 }
5882 }
5883
5884
5885
5886
5887
5888
5889 func TestClientTimeoutKillsConn_BeforeHeaders(t *testing.T) {
5890 runSynctest(t, testClientTimeoutKillsConn_BeforeHeaders, []testMode{http1Mode})
5891 }
5892 func testClientTimeoutKillsConn_BeforeHeaders(t *testing.T, mode testMode) {
5893 timeout := 1 * time.Millisecond
5894 for {
5895 inHandler := make(chan bool)
5896 cancelHandler := make(chan struct{})
5897 handlerDone := make(chan bool)
5898 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5899 <-r.Context().Done()
5900
5901 select {
5902 case <-cancelHandler:
5903 return
5904 case inHandler <- true:
5905 }
5906 defer func() { handlerDone <- true }()
5907
5908
5909 conn, _, err := w.(Hijacker).Hijack()
5910 if err != nil {
5911 t.Error(err)
5912 return
5913 }
5914 n, err := conn.Read([]byte{0})
5915 if n != 0 || err != io.EOF {
5916 t.Errorf("unexpected Read result: %v, %v", n, err)
5917 }
5918 conn.Close()
5919 }))
5920
5921 cst.c.Timeout = timeout
5922
5923 _, err := cst.c.Get(cst.ts.URL)
5924 if err == nil {
5925 close(cancelHandler)
5926 t.Fatal("unexpected Get success")
5927 }
5928
5929 tooSlow := time.NewTimer(timeout * 10)
5930 select {
5931 case <-tooSlow.C:
5932
5933
5934
5935 t.Logf("no handler seen in %v; retrying with longer timeout", timeout)
5936 close(cancelHandler)
5937 cst.close()
5938 timeout *= 2
5939 continue
5940 case <-inHandler:
5941 tooSlow.Stop()
5942 <-handlerDone
5943 }
5944 break
5945 }
5946 }
5947
5948
5949
5950
5951
5952
5953 func TestClientTimeoutKillsConn_AfterHeaders(t *testing.T) {
5954 runSynctest(t, testClientTimeoutKillsConn_AfterHeaders, []testMode{http1Mode})
5955 }
5956 func testClientTimeoutKillsConn_AfterHeaders(t *testing.T, mode testMode) {
5957 inHandler := make(chan bool)
5958 cancelHandler := make(chan struct{})
5959 handlerDone := make(chan bool)
5960 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
5961 w.Header().Set("Content-Length", "100")
5962 w.(Flusher).Flush()
5963
5964 select {
5965 case <-cancelHandler:
5966 return
5967 case inHandler <- true:
5968 }
5969 defer func() { handlerDone <- true }()
5970
5971 conn, _, err := w.(Hijacker).Hijack()
5972 if err != nil {
5973 t.Error(err)
5974 return
5975 }
5976 conn.Write([]byte("foo"))
5977
5978 n, err := conn.Read([]byte{0})
5979
5980
5981
5982
5983
5984 if n != 0 || err == nil {
5985 t.Errorf("unexpected Read result: %v, %v", n, err)
5986 }
5987 conn.Close()
5988 }))
5989
5990
5991
5992
5993
5994 cst.c.Timeout = 24 * time.Hour
5995 req, _ := NewRequest("GET", cst.ts.URL, nil)
5996 cancelReq := make(chan struct{})
5997 req.Cancel = cancelReq
5998
5999 res, err := cst.c.Do(req)
6000 if err != nil {
6001 close(cancelHandler)
6002 t.Fatalf("Get error: %v", err)
6003 }
6004
6005
6006
6007
6008 close(cancelReq)
6009 got, err := io.ReadAll(res.Body)
6010 if err == nil {
6011 t.Errorf("unexpected success; read %q, nil", got)
6012 }
6013
6014
6015 <-inHandler
6016 <-handlerDone
6017 }
6018
6019 func TestTransportResponseBodyWritableOnProtocolSwitch(t *testing.T) {
6020 runSynctest(t, testTransportResponseBodyWritableOnProtocolSwitch, []testMode{http1Mode})
6021 }
6022 func testTransportResponseBodyWritableOnProtocolSwitch(t *testing.T, mode testMode) {
6023 done := make(chan struct{})
6024 defer close(done)
6025 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6026 conn, _, err := w.(Hijacker).Hijack()
6027 if err != nil {
6028 t.Error(err)
6029 return
6030 }
6031 defer conn.Close()
6032 io.WriteString(conn, "HTTP/1.1 101 Switching Protocols Hi\r\nConnection: upgRADe\r\nUpgrade: foo\r\n\r\nSome buffered data\n")
6033 bs := bufio.NewScanner(conn)
6034 bs.Scan()
6035 fmt.Fprintf(conn, "%s\n", strings.ToUpper(bs.Text()))
6036 <-done
6037 }))
6038
6039 req, _ := NewRequest("GET", cst.ts.URL, nil)
6040 req.Header.Set("Upgrade", "foo")
6041 req.Header.Set("Connection", "upgrade")
6042 res, err := cst.c.Do(req)
6043 if err != nil {
6044 t.Fatal(err)
6045 }
6046 if res.StatusCode != 101 {
6047 t.Fatalf("expected 101 switching protocols; got %v, %v", res.Status, res.Header)
6048 }
6049 rwc, ok := res.Body.(io.ReadWriteCloser)
6050 if !ok {
6051 t.Fatalf("expected a ReadWriteCloser; got a %T", res.Body)
6052 }
6053 defer rwc.Close()
6054 bs := bufio.NewScanner(rwc)
6055 if !bs.Scan() {
6056 t.Fatalf("expected readable input")
6057 }
6058 if got, want := bs.Text(), "Some buffered data"; got != want {
6059 t.Errorf("read %q; want %q", got, want)
6060 }
6061 io.WriteString(rwc, "echo\n")
6062 if !bs.Scan() {
6063 t.Fatalf("expected another line")
6064 }
6065 if got, want := bs.Text(), "ECHO"; got != want {
6066 t.Errorf("read %q; want %q", got, want)
6067 }
6068 }
6069
6070 func TestTransportCONNECTBidi(t *testing.T) {
6071 runSynctest(t, testTransportCONNECTBidi, []testMode{http1Mode})
6072 }
6073 func testTransportCONNECTBidi(t *testing.T, mode testMode) {
6074 const target = "backend:443"
6075 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6076 if r.Method != "CONNECT" {
6077 t.Errorf("unexpected method %q", r.Method)
6078 w.WriteHeader(500)
6079 return
6080 }
6081 if r.RequestURI != target {
6082 t.Errorf("unexpected CONNECT target %q", r.RequestURI)
6083 w.WriteHeader(500)
6084 return
6085 }
6086 nc, brw, err := w.(Hijacker).Hijack()
6087 if err != nil {
6088 t.Error(err)
6089 return
6090 }
6091 defer nc.Close()
6092 nc.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
6093
6094 for {
6095 line, err := brw.ReadString('\n')
6096 if err != nil {
6097 if err != io.EOF {
6098 t.Error(err)
6099 }
6100 return
6101 }
6102 io.WriteString(brw, strings.ToUpper(line))
6103 brw.Flush()
6104 }
6105 }))
6106 pr, pw := io.Pipe()
6107 defer pw.Close()
6108 req, err := NewRequest("CONNECT", cst.ts.URL, pr)
6109 if err != nil {
6110 t.Fatal(err)
6111 }
6112 req.URL.Opaque = target
6113 res, err := cst.c.Do(req)
6114 if err != nil {
6115 t.Fatal(err)
6116 }
6117 defer res.Body.Close()
6118 if res.StatusCode != 200 {
6119 t.Fatalf("status code = %d; want 200", res.StatusCode)
6120 }
6121 br := bufio.NewReader(res.Body)
6122 for _, str := range []string{"foo", "bar", "baz"} {
6123 fmt.Fprintf(pw, "%s\n", str)
6124 got, err := br.ReadString('\n')
6125 if err != nil {
6126 t.Fatal(err)
6127 }
6128 got = strings.TrimSpace(got)
6129 want := strings.ToUpper(str)
6130 if got != want {
6131 t.Fatalf("got %q; want %q", got, want)
6132 }
6133 }
6134 }
6135
6136 func TestTransportCONNECTRejected(t *testing.T) {
6137 runSynctest(t, testTransportCONNECTRejected, []testMode{http1Mode})
6138 }
6139 func testTransportCONNECTRejected(t *testing.T, mode testMode) {
6140 tt := newHTTP1TransportTest(t)
6141
6142 sentReq := &Request{
6143 Method: "CONNECT",
6144 URL: &url.URL{
6145 Scheme: "http",
6146 Opaque: "backend.example.tld:80",
6147 Host: "proxy.example.tld",
6148 },
6149 Host: "proxy.example.tld",
6150 Header: make(Header),
6151 }
6152 rt := tt.roundTrip(sentReq)
6153
6154 dial := tt.wantDial("tcp", "proxy.example.tld:80")
6155 conn := dial.connect()
6156 recvReq := conn.readRequest()
6157 if got, want := recvReq.URL.Path, sentReq.URL.Path; got != want {
6158 t.Fatalf("read request path %q, want %q", got, want)
6159 }
6160
6161 conn.writeMessage(
6162 "HTTP/1.1 405 We Have No Connections Today",
6163 "Content-Length: 0",
6164 "",
6165 )
6166 rt.wantStatus(405)
6167 conn.wantClosed()
6168 }
6169
6170 func TestTransportCONNECTContentLengthZeroResponse(t *testing.T) {
6171 synctest.Test(t, func(t *testing.T) {
6172 tt := newHTTP1TransportTest(t)
6173 tt.tr.DisableCompression = true
6174
6175 sentReq, _ := http.NewRequest("CONNECT", "http://example.tld:80", nil)
6176 sentReq.Host = "connect.tld:80"
6177 sentReq.Header["User-Agent"] = nil
6178 rt := tt.roundTrip(sentReq)
6179
6180 dial := tt.wantDial("tcp", "example.tld:80")
6181 conn := dial.connect()
6182 conn.wantBytes([]byte(joinCRLF(
6183 "CONNECT connect.tld:80 HTTP/1.1",
6184 "Host: connect.tld:80",
6185 "",
6186 "",
6187 )))
6188
6189 conn.writeMessage(
6190 "HTTP/1.1 200 Have A Happy Tunnel",
6191 "Content-Length: 0",
6192 "",
6193 )
6194
6195 rt.wantStatus(200)
6196 if got, want := rt.response().Header.Get("Content-Length"), "0"; got != want {
6197 t.Errorf("got Content-Length header %q, want %q", got, want)
6198 }
6199 rt.wantBody(nil)
6200 })
6201 }
6202
6203 func TestTransportRequestReplayable(t *testing.T) {
6204 someBody := io.NopCloser(strings.NewReader(""))
6205 tests := []struct {
6206 name string
6207 req *Request
6208 want bool
6209 }{
6210 {
6211 name: "GET",
6212 req: &Request{Method: "GET"},
6213 want: true,
6214 },
6215 {
6216 name: "GET_http.NoBody",
6217 req: &Request{Method: "GET", Body: NoBody},
6218 want: true,
6219 },
6220 {
6221 name: "GET_body",
6222 req: &Request{Method: "GET", Body: someBody},
6223 want: false,
6224 },
6225 {
6226 name: "POST",
6227 req: &Request{Method: "POST"},
6228 want: false,
6229 },
6230 {
6231 name: "QUERY",
6232 req: &Request{Method: "QUERY"},
6233 want: true,
6234 },
6235 {
6236 name: "QUERY_body",
6237 req: &Request{Method: "QUERY", Body: someBody},
6238 want: false,
6239 },
6240 {
6241 name: "QUERY_body_GetBody",
6242 req: &Request{Method: "QUERY", Body: someBody, GetBody: func() (io.ReadCloser, error) { return someBody, nil }},
6243 want: true,
6244 },
6245 {
6246 name: "POST_idempotency-key",
6247 req: &Request{Method: "POST", Header: Header{"Idempotency-Key": {"x"}}},
6248 want: true,
6249 },
6250 {
6251 name: "POST_x-idempotency-key",
6252 req: &Request{Method: "POST", Header: Header{"X-Idempotency-Key": {"x"}}},
6253 want: true,
6254 },
6255 {
6256 name: "POST_body",
6257 req: &Request{Method: "POST", Header: Header{"Idempotency-Key": {"x"}}, Body: someBody},
6258 want: false,
6259 },
6260 }
6261 for _, tt := range tests {
6262 t.Run(tt.name, func(t *testing.T) {
6263 got := tt.req.ExportIsReplayable()
6264 if got != tt.want {
6265 t.Errorf("replyable = %v; want %v", got, tt.want)
6266 }
6267 })
6268 }
6269 }
6270
6271
6272
6273 type testMockTCPConn struct {
6274 *nettest.Conn
6275
6276 ReadFromCalled bool
6277 }
6278
6279 func (c *testMockTCPConn) ReadFrom(r io.Reader) (int64, error) {
6280 c.ReadFromCalled = true
6281 return io.Copy(c.Conn, r)
6282 }
6283
6284 func TestTransportRequestWriteUsesReadFrom(t *testing.T) {
6285 const nBytes = 1 << 10
6286 content := make([]byte, nBytes)
6287 rand.Read(content[:])
6288 fname := filepath.Join(t.TempDir(), "tempfile")
6289 if err := os.WriteFile(fname, content, 0600); err != nil {
6290 t.Fatal(err)
6291 }
6292 newFileFunc := func(t *testing.T) io.Reader {
6293 f, err := os.Open(fname)
6294 if err != nil {
6295 t.Fatal(err)
6296 }
6297 t.Cleanup(func() {
6298 f.Close()
6299 })
6300 return f
6301 }
6302 newBufferFunc := func(t *testing.T) io.Reader {
6303 return bytes.NewBuffer(content)
6304 }
6305
6306 cases := []struct {
6307 name string
6308 readerFunc func(*testing.T) io.Reader
6309 contentLength int64
6310 expectedReadFrom bool
6311 }{
6312 {
6313 name: "file, length",
6314 readerFunc: newFileFunc,
6315 contentLength: nBytes,
6316 expectedReadFrom: true,
6317 },
6318 {
6319 name: "file, no length",
6320 readerFunc: newFileFunc,
6321 },
6322 {
6323 name: "file, negative length",
6324 readerFunc: newFileFunc,
6325 contentLength: -1,
6326 },
6327 {
6328 name: "buffer",
6329 contentLength: nBytes,
6330 readerFunc: newBufferFunc,
6331 },
6332 {
6333 name: "buffer, no length",
6334 readerFunc: newBufferFunc,
6335 },
6336 {
6337 name: "buffer, length -1",
6338 contentLength: -1,
6339 readerFunc: newBufferFunc,
6340 },
6341 }
6342
6343 for _, tc := range cases {
6344 synctest.Subtest(t, tc.name, func(t *testing.T) {
6345 tt := newHTTP1TransportTest(t)
6346
6347 req, err := NewRequest("PUT", "http://example.tld/", tc.readerFunc(t))
6348 if err != nil {
6349 t.Fatal(err)
6350 }
6351 req.ContentLength = tc.contentLength
6352 req.Header.Set("Content-Type", "application/octet-stream")
6353 _ = tt.roundTrip(req)
6354
6355 dial := tt.wantDial("tcp", "example.tld:80")
6356
6357 tConn := &testMockTCPConn{}
6358 conn := dial.connectConfig(func(nc *nettest.Conn) net.Conn {
6359 tConn.Conn = nc
6360 return tConn
6361 })
6362
6363 _ = conn.readRequest()
6364 io.Copy(io.Discard, conn.conn)
6365
6366 expectedReadFrom := tc.expectedReadFrom
6367 if !tConn.ReadFromCalled && expectedReadFrom {
6368 t.Fatalf("did not call ReadFrom")
6369 }
6370
6371 if tConn.ReadFromCalled && !expectedReadFrom {
6372 t.Fatalf("ReadFrom was unexpectedly invoked")
6373 }
6374 })
6375 }
6376 }
6377
6378 func TestTransportClone(t *testing.T) {
6379 tr := &Transport{
6380 Proxy: func(*Request) (*url.URL, error) { panic("") },
6381 OnProxyConnectResponse: func(ctx context.Context, proxyURL *url.URL, connectReq *Request, connectRes *Response) error {
6382 return nil
6383 },
6384 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { panic("") },
6385 Dial: func(network, addr string) (net.Conn, error) { panic("") },
6386 DialTLS: func(network, addr string) (net.Conn, error) { panic("") },
6387 DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { panic("") },
6388 TLSClientConfig: new(tls.Config),
6389 TLSHandshakeTimeout: time.Second,
6390 DisableKeepAlives: true,
6391 DisableCompression: true,
6392 MaxIdleConns: 1,
6393 MaxIdleConnsPerHost: 1,
6394 MaxConnsPerHost: 1,
6395 IdleConnTimeout: time.Second,
6396 ResponseHeaderTimeout: time.Second,
6397 ExpectContinueTimeout: time.Second,
6398 ProxyConnectHeader: Header{},
6399 GetProxyConnectHeader: func(context.Context, *url.URL, string) (Header, error) { return nil, nil },
6400 MaxResponseHeaderBytes: 1,
6401 ForceAttemptHTTP2: true,
6402 HTTP2: &HTTP2Config{MaxConcurrentStreams: 1},
6403 Protocols: &Protocols{},
6404 TLSNextProto: map[string]func(authority string, c *tls.Conn) RoundTripper{
6405 "foo": func(authority string, c *tls.Conn) RoundTripper { panic("") },
6406 },
6407 ReadBufferSize: 1,
6408 WriteBufferSize: 1,
6409 }
6410 tr.Protocols.SetHTTP1(true)
6411 tr.Protocols.SetHTTP2(true)
6412 tr2 := tr.Clone()
6413 rv := reflect.ValueOf(tr2).Elem()
6414 rt := rv.Type()
6415 for i := 0; i < rt.NumField(); i++ {
6416 sf := rt.Field(i)
6417 if !token.IsExported(sf.Name) {
6418 continue
6419 }
6420 if rv.Field(i).IsZero() {
6421 t.Errorf("cloned field t2.%s is zero", sf.Name)
6422 }
6423 }
6424
6425 if _, ok := tr2.TLSNextProto["foo"]; !ok {
6426 t.Errorf("cloned Transport lacked TLSNextProto 'foo' key")
6427 }
6428
6429
6430 tr = new(Transport)
6431 tr2 = tr.Clone()
6432 if tr2.TLSNextProto != nil {
6433 t.Errorf("Transport.TLSNextProto unexpected non-nil")
6434 }
6435 }
6436
6437 func TestIs408(t *testing.T) {
6438 tests := []struct {
6439 in string
6440 want bool
6441 }{
6442 {"HTTP/1.0 408", true},
6443 {"HTTP/1.1 408", true},
6444 {"HTTP/1.8 408", true},
6445 {"HTTP/2.0 408", false},
6446 {"HTTP/1.1 408 ", true},
6447 {"HTTP/1.1 40", false},
6448 {"http/1.0 408", false},
6449 {"HTTP/1-1 408", false},
6450 }
6451 for _, tt := range tests {
6452 if got := Export_is408Message([]byte(tt.in)); got != tt.want {
6453 t.Errorf("is408Message(%q) = %v; want %v", tt.in, got, tt.want)
6454 }
6455 }
6456 }
6457
6458 func TestTransportIgnores408(t *testing.T) {
6459 runSynctest(t, testTransportIgnores408, []testMode{http1Mode}, testNotParallel)
6460 }
6461 func testTransportIgnores408(t *testing.T, mode testMode) {
6462
6463 defer log.SetOutput(log.Writer())
6464
6465 var logout strings.Builder
6466 log.SetOutput(&logout)
6467
6468 const target = "backend:443"
6469
6470 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6471 nc, _, err := w.(Hijacker).Hijack()
6472 if err != nil {
6473 t.Error(err)
6474 return
6475 }
6476 defer nc.Close()
6477 nc.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nok"))
6478 nc.Write([]byte("HTTP/1.1 408 bye\r\n"))
6479 }))
6480 req, err := NewRequest("GET", cst.ts.URL, nil)
6481 if err != nil {
6482 t.Fatal(err)
6483 }
6484 res, err := cst.c.Do(req)
6485 if err != nil {
6486 t.Fatal(err)
6487 }
6488 slurp, err := io.ReadAll(res.Body)
6489 if err != nil {
6490 t.Fatal(err)
6491 }
6492 if err != nil {
6493 t.Fatal(err)
6494 }
6495 if string(slurp) != "ok" {
6496 t.Fatalf("got %q; want ok", slurp)
6497 }
6498
6499 waitCondition(t, 1*time.Millisecond, func(d time.Duration) bool {
6500 if n := cst.tr.IdleConnKeyCountForTesting(); n != 0 {
6501 if d > 0 {
6502 t.Logf("%v idle conns still present after %v", n, d)
6503 }
6504 return false
6505 }
6506 return true
6507 })
6508 if got := logout.String(); got != "" {
6509 t.Fatalf("expected no log output; got: %s", got)
6510 }
6511 }
6512
6513 func TestInvalidHeaderResponse(t *testing.T) {
6514 runSynctest(t, testInvalidHeaderResponse, []testMode{http1Mode})
6515 }
6516 func testInvalidHeaderResponse(t *testing.T, mode testMode) {
6517 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6518 conn, buf, _ := w.(Hijacker).Hijack()
6519 buf.Write([]byte("HTTP/1.1 200 OK\r\n" +
6520 "Date: Wed, 30 Aug 2017 19:09:27 GMT\r\n" +
6521 "Content-Type: text/html; charset=utf-8\r\n" +
6522 "Content-Length: 0\r\n" +
6523 "Foo : bar\r\n\r\n"))
6524 buf.Flush()
6525 conn.Close()
6526 }))
6527 res, err := cst.c.Get(cst.ts.URL)
6528 if err != nil {
6529 t.Fatal(err)
6530 }
6531 defer res.Body.Close()
6532 if v := res.Header.Get("Foo"); v != "" {
6533 t.Errorf(`unexpected "Foo" header: %q`, v)
6534 }
6535 if v := res.Header.Get("Foo "); v != "bar" {
6536 t.Errorf(`bad "Foo " header value: %q, want %q`, v, "bar")
6537 }
6538 }
6539
6540 type bodyCloser bool
6541
6542 func (bc *bodyCloser) Close() error {
6543 *bc = true
6544 return nil
6545 }
6546 func (bc *bodyCloser) Read(b []byte) (n int, err error) {
6547 return 0, io.EOF
6548 }
6549
6550
6551
6552 func TestTransportClosesBodyOnInvalidRequests(t *testing.T) {
6553 runNoSynctest(t, testTransportClosesBodyOnInvalidRequests)
6554 }
6555 func testTransportClosesBodyOnInvalidRequests(t *testing.T, mode testMode) {
6556 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6557 t.Errorf("Should not have been invoked")
6558 })).ts
6559
6560 u, _ := url.Parse(cst.URL)
6561
6562 tests := []struct {
6563 name string
6564 req *Request
6565 wantErr string
6566 }{
6567 {
6568 name: "invalid method",
6569 req: &Request{
6570 Method: " ",
6571 URL: u,
6572 },
6573 wantErr: `invalid method " "`,
6574 },
6575 {
6576 name: "nil URL",
6577 req: &Request{
6578 Method: "GET",
6579 },
6580 wantErr: `nil Request.URL`,
6581 },
6582 {
6583 name: "invalid header key",
6584 req: &Request{
6585 Method: "GET",
6586 Header: Header{"💡": {"emoji"}},
6587 URL: u,
6588 },
6589 wantErr: `invalid header field name "💡"`,
6590 },
6591 {
6592 name: "invalid header value",
6593 req: &Request{
6594 Method: "POST",
6595 Header: Header{"key": {"\x19"}},
6596 URL: u,
6597 },
6598 wantErr: `invalid header field value for "key"`,
6599 },
6600 {
6601 name: "non HTTP(s) scheme",
6602 req: &Request{
6603 Method: "POST",
6604 URL: &url.URL{Scheme: "faux"},
6605 },
6606 wantErr: `unsupported protocol scheme "faux"`,
6607 },
6608 {
6609 name: "no Host in URL",
6610 req: &Request{
6611 Method: "POST",
6612 URL: &url.URL{Scheme: "http"},
6613 },
6614 wantErr: `no Host in request URL`,
6615 },
6616 }
6617
6618 for _, tt := range tests {
6619 synctest.Subtest(t, tt.name, func(t *testing.T) {
6620 var bc bodyCloser
6621 req := tt.req
6622 req.Body = &bc
6623 _, err := cst.Client().Do(tt.req)
6624 if err == nil {
6625 t.Fatal("Expected an error")
6626 }
6627 if !bc {
6628 t.Fatal("Expected body to have been closed")
6629 }
6630 if g, w := err.Error(), tt.wantErr; !strings.HasSuffix(g, w) {
6631 t.Fatalf("Error mismatch: %q does not end with %q", g, w)
6632 }
6633 })
6634 }
6635 }
6636
6637
6638
6639 type breakableConn struct {
6640 net.Conn
6641 *brokenState
6642 }
6643
6644 type brokenState struct {
6645 sync.Mutex
6646 broken bool
6647 }
6648
6649 func (w *breakableConn) Write(b []byte) (n int, err error) {
6650 w.Lock()
6651 defer w.Unlock()
6652 if w.broken {
6653 return 0, errors.New("some write error")
6654 }
6655 return w.Conn.Write(b)
6656 }
6657
6658
6659 func TestDontCacheBrokenHTTP2Conn(t *testing.T) {
6660 runNoSynctest(t, testDontCacheBrokenHTTP2Conn, []testMode{http2Mode})
6661 }
6662 func testDontCacheBrokenHTTP2Conn(t *testing.T, mode testMode) {
6663 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}), optQuietLog, optRealNet)
6664
6665 var brokenState brokenState
6666
6667 const numReqs = 5
6668 var numDials, gotConns uint32
6669
6670 cst.tr.Dial = func(netw, addr string) (net.Conn, error) {
6671 atomic.AddUint32(&numDials, 1)
6672 c, err := net.Dial(netw, addr)
6673 if err != nil {
6674 t.Errorf("unexpected Dial error: %v", err)
6675 return nil, err
6676 }
6677 return &breakableConn{c, &brokenState}, err
6678 }
6679
6680 for i := 1; i <= numReqs; i++ {
6681 brokenState.Lock()
6682 brokenState.broken = false
6683 brokenState.Unlock()
6684
6685
6686
6687
6688 doBreak := i != numReqs
6689
6690 ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
6691 GotConn: func(info httptrace.GotConnInfo) {
6692 t.Logf("got conn: %v, reused=%v, wasIdle=%v, idleTime=%v", info.Conn.LocalAddr(), info.Reused, info.WasIdle, info.IdleTime)
6693 atomic.AddUint32(&gotConns, 1)
6694 },
6695 TLSHandshakeDone: func(cfg tls.ConnectionState, err error) {
6696 brokenState.Lock()
6697 defer brokenState.Unlock()
6698 if doBreak {
6699 brokenState.broken = true
6700 }
6701 },
6702 })
6703 req, err := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil)
6704 if err != nil {
6705 t.Fatal(err)
6706 }
6707 _, err = cst.c.Do(req)
6708 if doBreak != (err != nil) {
6709 t.Errorf("for iteration %d, doBreak=%v; unexpected error %v", i, doBreak, err)
6710 }
6711 }
6712 if got, want := atomic.LoadUint32(&gotConns), 1; int(got) != want {
6713 t.Errorf("GotConn calls = %v; want %v", got, want)
6714 }
6715 if got, want := atomic.LoadUint32(&numDials), numReqs; int(got) != want {
6716 t.Errorf("Dials = %v; want %v", got, want)
6717 }
6718 }
6719
6720
6721
6722
6723
6724 func TestTransportDecrementConnWhenIdleConnRemoved(t *testing.T) {
6725 runSynctest(t, testTransportDecrementConnWhenIdleConnRemoved, []testMode{http2Mode})
6726 }
6727 func testTransportDecrementConnWhenIdleConnRemoved(t *testing.T, mode testMode) {
6728 CondSkipHTTP2(t)
6729
6730 h := HandlerFunc(func(w ResponseWriter, r *Request) {
6731 _, err := w.Write([]byte("foo"))
6732 if err != nil {
6733 t.Fatalf("Write: %v", err)
6734 }
6735 })
6736
6737 ts := newClientServerTest(t, mode, h).ts
6738
6739 c := ts.Client()
6740 tr := c.Transport.(*Transport)
6741 tr.MaxConnsPerHost = 1
6742
6743 errCh := make(chan error, 300)
6744 doReq := func() {
6745 resp, err := c.Get(ts.URL)
6746 if err != nil {
6747 errCh <- fmt.Errorf("request failed: %v", err)
6748 return
6749 }
6750 defer resp.Body.Close()
6751 _, err = io.ReadAll(resp.Body)
6752 if err != nil {
6753 errCh <- fmt.Errorf("read body failed: %v", err)
6754 }
6755 }
6756
6757 var wg sync.WaitGroup
6758 for i := 0; i < 300; i++ {
6759 wg.Add(1)
6760 go func() {
6761 defer wg.Done()
6762 doReq()
6763 }()
6764 }
6765 wg.Wait()
6766 close(errCh)
6767
6768 for err := range errCh {
6769 t.Errorf("error occurred: %v", err)
6770 }
6771 }
6772
6773
6774
6775
6776 func TestAltProtoCancellation(t *testing.T) {
6777 tr := &Transport{}
6778 c := &Client{
6779 Transport: tr,
6780 Timeout: time.Millisecond,
6781 }
6782 tr.RegisterProtocol("cancel", cancelProto{})
6783 _, err := c.Get("cancel://bar.com/path")
6784 if err == nil {
6785 t.Error("request unexpectedly succeeded")
6786 } else if !strings.Contains(err.Error(), errCancelProto.Error()) {
6787 t.Errorf("got error %q, does not contain expected string %q", err, errCancelProto)
6788 }
6789 }
6790
6791 var errCancelProto = errors.New("canceled as expected")
6792
6793 type cancelProto struct{}
6794
6795 func (cancelProto) RoundTrip(req *Request) (*Response, error) {
6796 <-req.Cancel
6797 return nil, errCancelProto
6798 }
6799
6800 type roundTripFunc func(r *Request) (*Response, error)
6801
6802 func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) { return f(r) }
6803
6804
6805 func TestIssue32441(t *testing.T) { runSynctest(t, testIssue32441, []testMode{http1Mode}) }
6806 func testIssue32441(t *testing.T, mode testMode) {
6807 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6808 if n, _ := io.Copy(io.Discard, r.Body); n == 0 {
6809 t.Error("body length is zero")
6810 }
6811 })).ts
6812 c := ts.Client()
6813 c.Transport.(*Transport).RegisterProtocol("http", roundTripFunc(func(r *Request) (*Response, error) {
6814
6815 if n, _ := io.Copy(io.Discard, r.Body); n == 0 {
6816 t.Error("body length is zero during round trip")
6817 }
6818 return nil, ErrSkipAltProtocol
6819 }))
6820 if _, err := c.Post(ts.URL, "application/octet-stream", bytes.NewBufferString("data")); err != nil {
6821 t.Error(err)
6822 }
6823 }
6824
6825
6826
6827 func TestTransportRejectsSignInContentLength(t *testing.T) {
6828 runSynctest(t, testTransportRejectsSignInContentLength, []testMode{http1Mode})
6829 }
6830 func testTransportRejectsSignInContentLength(t *testing.T, mode testMode) {
6831 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
6832 w.Header().Set("Content-Length", "+3")
6833 w.Write([]byte("abc"))
6834 })).ts
6835
6836 c := cst.Client()
6837 res, err := c.Get(cst.URL)
6838 if err == nil || res != nil {
6839 t.Fatal("Expected a non-nil error and a nil http.Response")
6840 }
6841 if got, want := err.Error(), `bad Content-Length "+3"`; !strings.Contains(got, want) {
6842 t.Fatalf("Error mismatch\nGot: %q\nWanted substring: %q", got, want)
6843 }
6844 }
6845
6846
6847 type dumpConn struct {
6848 io.Writer
6849 io.Reader
6850 }
6851
6852 func (c *dumpConn) Close() error { return nil }
6853 func (c *dumpConn) LocalAddr() net.Addr { return nil }
6854 func (c *dumpConn) RemoteAddr() net.Addr { return nil }
6855 func (c *dumpConn) SetDeadline(t time.Time) error { return nil }
6856 func (c *dumpConn) SetReadDeadline(t time.Time) error { return nil }
6857 func (c *dumpConn) SetWriteDeadline(t time.Time) error { return nil }
6858
6859
6860
6861 type delegateReader struct {
6862 c chan io.Reader
6863 r io.Reader
6864 }
6865
6866 func (r *delegateReader) Read(p []byte) (int, error) {
6867 if r.r == nil {
6868 var ok bool
6869 if r.r, ok = <-r.c; !ok {
6870 return 0, errors.New("delegate closed")
6871 }
6872 }
6873 return r.r.Read(p)
6874 }
6875
6876 func testTransportRace(req *Request) {
6877 save := req.Body
6878 pr, pw := io.Pipe()
6879 defer pr.Close()
6880 defer pw.Close()
6881 dr := &delegateReader{c: make(chan io.Reader)}
6882
6883 t := &Transport{
6884 Dial: func(net, addr string) (net.Conn, error) {
6885 return &dumpConn{pw, dr}, nil
6886 },
6887 }
6888 defer t.CloseIdleConnections()
6889
6890 quitReadCh := make(chan struct{})
6891
6892 go func() {
6893 defer close(quitReadCh)
6894
6895 req, err := ReadRequest(bufio.NewReader(pr))
6896 if err == nil {
6897
6898
6899 io.Copy(io.Discard, req.Body)
6900 req.Body.Close()
6901 }
6902 select {
6903 case dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n"):
6904 case quitReadCh <- struct{}{}:
6905
6906 close(dr.c)
6907 }
6908 }()
6909
6910 t.RoundTrip(req)
6911
6912
6913
6914 pw.Close()
6915 <-quitReadCh
6916
6917 req.Body = save
6918 }
6919
6920
6921
6922
6923
6924 func TestErrorWriteLoopRace(t *testing.T) {
6925 if testing.Short() {
6926 return
6927 }
6928 t.Parallel()
6929 for i := 0; i < 1000; i++ {
6930 delay := time.Duration(mrand.Intn(5)) * time.Millisecond
6931 ctx, cancel := context.WithTimeout(context.Background(), delay)
6932 defer cancel()
6933
6934 r := bytes.NewBuffer(make([]byte, 10000))
6935 req, err := NewRequestWithContext(ctx, MethodPost, "http://example.com", r)
6936 if err != nil {
6937 t.Fatal(err)
6938 }
6939
6940 testTransportRace(req)
6941 }
6942 }
6943
6944
6945
6946
6947 func TestCancelRequestWhenSharingConnection(t *testing.T) {
6948 runSynctest(t, testCancelRequestWhenSharingConnection, []testMode{http1Mode})
6949 }
6950 func testCancelRequestWhenSharingConnection(t *testing.T, mode testMode) {
6951 reqc := make(chan chan struct{}, 2)
6952 ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, req *Request) {
6953 ch := make(chan struct{}, 1)
6954 reqc <- ch
6955 <-ch
6956 w.Header().Add("Content-Length", "0")
6957 })).ts
6958
6959 client := ts.Client()
6960 transport := client.Transport.(*Transport)
6961 transport.MaxIdleConns = 1
6962 transport.MaxConnsPerHost = 1
6963
6964 var wg sync.WaitGroup
6965
6966 wg.Add(1)
6967 putidlec := make(chan chan struct{}, 1)
6968 reqerrc := make(chan error, 1)
6969 go func() {
6970 defer wg.Done()
6971 ctx := httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
6972 PutIdleConn: func(error) {
6973
6974
6975 ch := make(chan struct{})
6976 putidlec <- ch
6977 close(putidlec)
6978 <-ch
6979 },
6980 })
6981 req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil)
6982 res, err := client.Do(req)
6983 if err != nil {
6984 reqerrc <- err
6985 } else {
6986 res.Body.Close()
6987 }
6988 }()
6989
6990
6991
6992 select {
6993 case err := <-reqerrc:
6994 t.Fatalf("request 1: got err %v, want nil", err)
6995 case r1c := <-reqc:
6996 close(r1c)
6997 }
6998 var idlec chan struct{}
6999 select {
7000 case err := <-reqerrc:
7001 t.Fatalf("request 1: got err %v, want nil", err)
7002 case idlec = <-putidlec:
7003 }
7004
7005 wg.Add(1)
7006 cancelctx, cancel := context.WithCancel(context.Background())
7007 go func() {
7008 defer wg.Done()
7009 req, _ := NewRequestWithContext(cancelctx, "GET", ts.URL, nil)
7010 res, err := client.Do(req)
7011 if err == nil {
7012 res.Body.Close()
7013 }
7014 if !errors.Is(err, context.Canceled) {
7015 t.Errorf("request 2: got err %v, want Canceled", err)
7016 }
7017
7018
7019 close(idlec)
7020 }()
7021
7022
7023
7024 r2c := <-reqc
7025 cancel()
7026
7027 <-idlec
7028
7029 close(r2c)
7030 wg.Wait()
7031 }
7032
7033 func TestHandlerAbortRacesBodyRead(t *testing.T) {
7034 runSynctest(t, testHandlerAbortRacesBodyRead, http3SkippedMode)
7035 }
7036 func testHandlerAbortRacesBodyRead(t *testing.T, mode testMode) {
7037 ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
7038 go io.Copy(io.Discard, req.Body)
7039 panic(ErrAbortHandler)
7040 })).ts
7041
7042 var wg sync.WaitGroup
7043 for i := 0; i < 2; i++ {
7044 wg.Add(1)
7045 go func() {
7046 defer wg.Done()
7047 for j := 0; j < 10; j++ {
7048 const reqLen = 6 * 1024 * 1024
7049 req, _ := NewRequest("POST", ts.URL, &io.LimitedReader{R: neverEnding('x'), N: reqLen})
7050 req.ContentLength = reqLen
7051 resp, _ := ts.Client().Transport.RoundTrip(req)
7052 if resp != nil {
7053 resp.Body.Close()
7054 }
7055 }
7056 }()
7057 }
7058 wg.Wait()
7059 }
7060
7061 func TestRequestSanitization(t *testing.T) { runSynctest(t, testRequestSanitization) }
7062 func testRequestSanitization(t *testing.T, mode testMode) {
7063 if mode == http2Mode {
7064
7065 t.Skip("https://go.dev/issue/60374 test fails when run with HTTP/2")
7066 }
7067 ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
7068 if h, ok := req.Header["X-Evil"]; ok {
7069 t.Errorf("request has X-Evil header: %q", h)
7070 }
7071 })).ts
7072 req, _ := NewRequest("GET", ts.URL, nil)
7073 req.Host = "go.dev\r\nX-Evil:evil"
7074 resp, _ := ts.Client().Do(req)
7075 if resp != nil {
7076 resp.Body.Close()
7077 }
7078 }
7079
7080 func TestProxyAuthHeader(t *testing.T) {
7081
7082 runSynctest(t, testProxyAuthHeader, []testMode{http1Mode}, testNotParallel)
7083 }
7084 func testProxyAuthHeader(t *testing.T, mode testMode) {
7085 const username = "u"
7086 const password = "@/?!"
7087 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
7088
7089
7090 var r2 Request
7091 r2.Header = Header{
7092 "Authorization": req.Header["Proxy-Authorization"],
7093 }
7094 gotuser, gotpass, ok := r2.BasicAuth()
7095 if !ok || gotuser != username || gotpass != password {
7096 t.Errorf("req.BasicAuth() = %q, %q, %v; want %q, %q, true", gotuser, gotpass, ok, username, password)
7097 }
7098 }))
7099 u, err := url.Parse(cst.ts.URL)
7100 if err != nil {
7101 t.Fatal(err)
7102 }
7103 u.User = url.UserPassword(username, password)
7104 t.Setenv("HTTP_PROXY", u.String())
7105 cst.tr.Proxy = ProxyURL(u)
7106 resp, err := cst.c.Get("http://_/")
7107 if err != nil {
7108 t.Fatal(err)
7109 }
7110 resp.Body.Close()
7111 }
7112
7113
7114 func TestTransportReqCancelerCleanupOnRequestBodyWriteError(t *testing.T) {
7115 synctest.Test(t, func(t *testing.T) {
7116 tt := newHTTP1TransportTest(t)
7117
7118 clientConn, netConn := tt.newClientConn("http", "example.tld:80")
7119
7120
7121
7122 bodyr, bodyw := io.Pipe()
7123 t.Cleanup(func() {
7124 bodyr.Close()
7125 bodyw.Close()
7126 })
7127
7128
7129 sentReq, _ := NewRequest("POST", "http://example.tld/", bodyr)
7130 sentReq.ContentLength = 1000
7131 sentReq.Header.Set("Content-Type", "text/plain")
7132 rt := newTestRoundTrip(t, clientConn, sentReq)
7133 _ = netConn.readRequest()
7134
7135
7136 body1 := []byte("1234")
7137 go bodyw.Write(body1)
7138 synctest.Wait()
7139 netConn.wantBytes(body1)
7140 if got, want := clientConn.InFlight(), 1; got != want {
7141 t.Fatalf("with body being written: InFlight = %v, want %v", got, want)
7142 }
7143
7144
7145 netConn.conn.Peer().SetWriteError(errors.New("write error"))
7146 go bodyw.Write([]byte("write fails with an error"))
7147
7148
7149 synctest.Sleep(51 * time.Millisecond)
7150 if got, want := clientConn.InFlight(), 0; got != want {
7151 t.Fatalf("after body write error: InFlight = %v, want %v", got, want)
7152 }
7153 if err := rt.err(); err == nil {
7154 t.Fatalf("after body write error: RoundTrip = %v, want error", err)
7155 }
7156 })
7157 }
7158
7159 func TestTransportResponseBodyDrainReadAndClose(t *testing.T) {
7160 tests := []struct {
7161 name string
7162 read bool
7163 closeEarly bool
7164 closeAfterRead bool
7165 serverTruncate bool
7166 wantReadErr error
7167 wantCloseErr error
7168 wantReuse bool
7169 }{
7170
7171 {
7172 name: "concurrent early close and read to eof",
7173 read: true,
7174 closeEarly: true,
7175 wantReadErr: io.EOF,
7176 wantReuse: true,
7177 },
7178 {
7179 name: "concurrent early close and unexpected read error",
7180 read: true,
7181 closeEarly: true,
7182 serverTruncate: true,
7183 wantReadErr: io.ErrUnexpectedEOF,
7184 wantReuse: false,
7185 },
7186 {
7187 name: "unexpected read error without any close",
7188 read: true,
7189 serverTruncate: true,
7190 wantReadErr: io.ErrUnexpectedEOF,
7191 wantReuse: false,
7192 },
7193 {
7194 name: "unexpected read error followed by close",
7195 read: true,
7196 closeAfterRead: true,
7197 serverTruncate: true,
7198 wantReadErr: io.ErrUnexpectedEOF,
7199
7200 wantCloseErr: nil,
7201 wantReuse: false,
7202 },
7203 {
7204 name: "early close without any read",
7205 read: false,
7206 closeEarly: true,
7207 wantReuse: true,
7208 },
7209 {
7210 name: "read all then close",
7211 read: true,
7212 closeAfterRead: true,
7213 wantReadErr: io.EOF,
7214 wantReuse: true,
7215 },
7216 }
7217
7218 for _, tc := range tests {
7219 synctest.Subtest(t, tc.name, func(t *testing.T) {
7220 tt := newHTTP1TransportTest(t)
7221 req, _ := NewRequest("GET", "http://example.tld/", nil)
7222 rt := tt.roundTrip(req)
7223 conn := tt.wantDial("tcp", "example.tld:80").connect()
7224 conn.readRequest()
7225 conn.writeMessage(
7226 "HTTP/1.1 200 OK",
7227 "Transfer-Encoding: chunked",
7228 "",
7229 )
7230 res := rt.response()
7231
7232 readErr := make(chan error, 1)
7233 if tc.read {
7234 go func() {
7235 var buf [1]byte
7236 _, err := res.Body.Read(buf[:])
7237 readErr <- err
7238 }()
7239
7240 synctest.Wait()
7241 }
7242
7243 if tc.closeEarly {
7244 if err := res.Body.Close(); !errors.Is(err, tc.wantCloseErr) {
7245 t.Fatalf("Close = %v, want %v", err, tc.wantCloseErr)
7246 }
7247 }
7248
7249 if tc.serverTruncate {
7250 conn.conn.CloseWrite()
7251 } else {
7252 conn.writeMessage(
7253 "0",
7254 "",
7255 )
7256 }
7257
7258 if tc.read {
7259 synctest.Wait()
7260 if err := <-readErr; !errors.Is(err, tc.wantReadErr) {
7261 t.Fatalf("Read = %v, want %v", err, tc.wantReadErr)
7262 }
7263 }
7264
7265 if tc.closeAfterRead {
7266 if err := res.Body.Close(); !errors.Is(err, tc.wantCloseErr) {
7267 t.Fatalf("Close = %v, want %v", err, tc.wantCloseErr)
7268 }
7269 }
7270
7271 if !tc.wantReuse {
7272 conn.wantClosed()
7273 } else {
7274 synctest.Wait()
7275 req, _ = NewRequest("GET", "http://example.tld/next", nil)
7276 rt = tt.roundTrip(req)
7277 if got := conn.readRequest().URL.Path; got != "/next" {
7278 t.Fatalf("request path = %q, want /next", got)
7279 }
7280 conn.writeMessage(
7281 "HTTP/1.1 200 OK",
7282 "Content-Length: 0",
7283 "",
7284 )
7285 rt.wantStatus(200)
7286 }
7287 })
7288 }
7289 }
7290
7291
7292
7293
7294
7295 func TestTransportResponseBodyDrainDropsTrailers(t *testing.T) {
7296 synctest.Test(t, func(t *testing.T) {
7297 tt := newHTTP1TransportTest(t)
7298 req, _ := NewRequest("GET", "http://example.tld/", nil)
7299 rt := tt.roundTrip(req)
7300 conn := tt.wantDial("tcp", "example.tld:80").connect()
7301 conn.readRequest()
7302 conn.writeMessage(
7303 "HTTP/1.1 200 OK",
7304 "Transfer-Encoding: chunked",
7305 "Trailer: X-Test",
7306 "",
7307 "5",
7308 "hello",
7309 )
7310 res := rt.response()
7311
7312 if err := res.Body.Close(); err != nil {
7313 t.Fatalf("Close = %v, want nil", err)
7314 }
7315 conn.writeMessage(
7316 "0",
7317 "X-Test: v",
7318 "",
7319 )
7320 synctest.Wait()
7321
7322
7323
7324
7325 if got := res.Trailer.Get("X-Test"); got != "" {
7326 t.Error("drained response body unexpectedly has populated trailers")
7327 }
7328
7329
7330
7331 req, _ = NewRequest("GET", "http://example.tld/next", nil)
7332 rt = tt.roundTrip(req)
7333 if got := conn.readRequest().URL.Path; got != "/next" {
7334 t.Fatalf("request path = %q, want /next", got)
7335 }
7336 conn.writeMessage(
7337 "HTTP/1.1 200 OK",
7338 "Content-Length: 0",
7339 "",
7340 )
7341 rt.wantStatus(200)
7342 })
7343 }
7344
7345
7346
7347 func TestTransportResponseBodyNoDrainWithoutKeepAlives(t *testing.T) {
7348 tests := []struct {
7349 name string
7350 configure func(*Transport)
7351 }{{
7352 name: "DisableKeepAlives",
7353 configure: func(tr *Transport) { tr.DisableKeepAlives = true },
7354 }, {
7355 name: "negative MaxIdleConnsPerHost",
7356 configure: func(tr *Transport) { tr.MaxIdleConnsPerHost = -1 },
7357 }}
7358 for _, tc := range tests {
7359 synctest.Subtest(t, tc.name, func(t *testing.T) {
7360 tt := newHTTP1TransportTest(t)
7361 tc.configure(tt.tr)
7362 req, _ := NewRequest("GET", "http://example.tld/", nil)
7363 rt := tt.roundTrip(req)
7364 conn := tt.wantDial("tcp", "example.tld:80").connect()
7365 conn.readRequest()
7366
7367
7368
7369
7370 conn.writeMessage(
7371 "HTTP/1.1 200 OK",
7372 "Transfer-Encoding: chunked",
7373 "",
7374 "5",
7375 "hello",
7376 )
7377 res := rt.response()
7378
7379
7380
7381
7382 if err := res.Body.Close(); err != nil {
7383 t.Fatalf("Close = %v, want nil", err)
7384 }
7385 conn.wantClosed()
7386 })
7387 }
7388 }
7389
7390 func TestValidateClientRequestTrailers(t *testing.T) {
7391 runNoSynctest(t, testValidateClientRequestTrailers)
7392 }
7393
7394 func testValidateClientRequestTrailers(t *testing.T, mode testMode) {
7395 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
7396 rw.Write([]byte("Hello"))
7397 })).ts
7398
7399 cases := []struct {
7400 trailer Header
7401 wantErr string
7402 }{
7403 {Header{"Trx": {"x\r\nX-Another-One"}}, `invalid trailer field value for "Trx"`},
7404 {Header{"\r\nTrx": {"X-Another-One"}}, `invalid trailer field name "\r\nTrx"`},
7405 }
7406
7407 for i, tt := range cases {
7408 testName := fmt.Sprintf("%s%d", mode, i)
7409 synctest.Subtest(t, testName, func(t *testing.T) {
7410 req, err := NewRequest("GET", cst.URL, nil)
7411 if err != nil {
7412 t.Fatal(err)
7413 }
7414 req.Trailer = tt.trailer
7415 res, err := cst.Client().Do(req)
7416 if err == nil {
7417 t.Fatal("Expected an error")
7418 }
7419 if g, w := err.Error(), tt.wantErr; !strings.Contains(g, w) {
7420 t.Fatalf("Mismatched error\n\t%q\ndoes not contain\n\t%q", g, w)
7421 }
7422 if res != nil {
7423 t.Fatal("Unexpected non-nil response")
7424 }
7425 })
7426 }
7427 }
7428
7429 func TestTransportServerProtocols(t *testing.T) {
7430 CondSkipHTTP2(t)
7431 DefaultTransport.(*Transport).CloseIdleConnections()
7432
7433 cert, err := tls.X509KeyPair(testcert.LocalhostCert, testcert.LocalhostKey)
7434 if err != nil {
7435 t.Fatal(err)
7436 }
7437 leafCert, err := x509.ParseCertificate(cert.Certificate[0])
7438 if err != nil {
7439 t.Fatal(err)
7440 }
7441 certpool := x509.NewCertPool()
7442 certpool.AddCert(leafCert)
7443
7444 for _, test := range []struct {
7445 name string
7446 scheme string
7447 setup func(t *testing.T)
7448 transport func(*Transport)
7449 server func(*Server)
7450 want string
7451 }{{
7452 name: "http default",
7453 scheme: "http",
7454 want: "HTTP/1.1",
7455 }, {
7456 name: "https default",
7457 scheme: "https",
7458 transport: func(tr *Transport) {
7459
7460 },
7461 want: "HTTP/1.1",
7462 }, {
7463 name: "https transport protocols include HTTP2",
7464 scheme: "https",
7465 transport: func(tr *Transport) {
7466
7467
7468 tr.Protocols = &Protocols{}
7469 tr.Protocols.SetHTTP1(true)
7470 tr.Protocols.SetHTTP2(true)
7471 },
7472 want: "HTTP/2.0",
7473 }, {
7474 name: "https transport protocols only include HTTP1",
7475 scheme: "https",
7476 transport: func(tr *Transport) {
7477
7478 tr.Protocols = &Protocols{}
7479 tr.Protocols.SetHTTP1(true)
7480 },
7481 want: "HTTP/1.1",
7482 }, {
7483 name: "https transport ForceAttemptHTTP2",
7484 scheme: "https",
7485 transport: func(tr *Transport) {
7486
7487 tr.ForceAttemptHTTP2 = true
7488 },
7489 want: "HTTP/2.0",
7490 }, {
7491 name: "https transport protocols override TLSNextProto",
7492 scheme: "https",
7493 transport: func(tr *Transport) {
7494
7495
7496
7497 tr.Protocols = &Protocols{}
7498 tr.Protocols.SetHTTP1(true)
7499 tr.Protocols.SetHTTP2(true)
7500 tr.TLSNextProto = map[string]func(string, *tls.Conn) RoundTripper{}
7501 },
7502 want: "HTTP/2.0",
7503 }, {
7504 name: "https server disables HTTP2 with TLSNextProto",
7505 scheme: "https",
7506 server: func(srv *Server) {
7507
7508
7509 srv.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
7510 },
7511 want: "HTTP/1.1",
7512 }, {
7513 name: "https server Protocols overrides empty TLSNextProto",
7514 scheme: "https",
7515 server: func(srv *Server) {
7516
7517
7518 srv.Protocols = &Protocols{}
7519 srv.Protocols.SetHTTP1(true)
7520 srv.Protocols.SetHTTP2(true)
7521 srv.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
7522 },
7523 want: "HTTP/2.0",
7524 }, {
7525 name: "https server protocols only include HTTP1",
7526 scheme: "https",
7527 server: func(srv *Server) {
7528 srv.Protocols = &Protocols{}
7529 srv.Protocols.SetHTTP1(true)
7530 },
7531 want: "HTTP/1.1",
7532 }, {
7533 name: "https server protocols include HTTP2",
7534 scheme: "https",
7535 server: func(srv *Server) {
7536 srv.Protocols = &Protocols{}
7537 srv.Protocols.SetHTTP1(true)
7538 srv.Protocols.SetHTTP2(true)
7539 },
7540 want: "HTTP/2.0",
7541 }, {
7542 name: "GODEBUG disables HTTP2 client",
7543 scheme: "https",
7544 setup: func(t *testing.T) {
7545 t.Setenv("GODEBUG", "http2client=0")
7546 },
7547 transport: func(tr *Transport) {
7548
7549
7550 tr.Protocols = &Protocols{}
7551 tr.Protocols.SetHTTP1(true)
7552 tr.Protocols.SetHTTP2(true)
7553 },
7554 want: "HTTP/1.1",
7555 }, {
7556 name: "GODEBUG disables HTTP2 server",
7557 scheme: "https",
7558 setup: func(t *testing.T) {
7559 t.Setenv("GODEBUG", "http2server=0")
7560 },
7561 transport: func(tr *Transport) {
7562
7563
7564 tr.Protocols = &Protocols{}
7565 tr.Protocols.SetHTTP1(true)
7566 tr.Protocols.SetHTTP2(true)
7567 },
7568 want: "HTTP/1.1",
7569 }, {
7570 name: "unencrypted HTTP2 with prior knowledge",
7571 scheme: "http",
7572 transport: func(tr *Transport) {
7573 tr.Protocols = &Protocols{}
7574 tr.Protocols.SetUnencryptedHTTP2(true)
7575 },
7576 server: func(srv *Server) {
7577 srv.Protocols = &Protocols{}
7578 srv.Protocols.SetHTTP1(true)
7579 srv.Protocols.SetUnencryptedHTTP2(true)
7580 },
7581 want: "HTTP/2.0",
7582 }, {
7583 name: "unencrypted HTTP2 only on server",
7584 scheme: "http",
7585 transport: func(tr *Transport) {
7586 tr.Protocols = &Protocols{}
7587 tr.Protocols.SetUnencryptedHTTP2(true)
7588 },
7589 server: func(srv *Server) {
7590 srv.Protocols = &Protocols{}
7591 srv.Protocols.SetUnencryptedHTTP2(true)
7592 },
7593 want: "HTTP/2.0",
7594 }, {
7595 name: "unencrypted HTTP2 with no server support",
7596 scheme: "http",
7597 transport: func(tr *Transport) {
7598 tr.Protocols = &Protocols{}
7599 tr.Protocols.SetUnencryptedHTTP2(true)
7600 },
7601 server: func(srv *Server) {
7602 srv.Protocols = &Protocols{}
7603 srv.Protocols.SetHTTP1(true)
7604 },
7605 want: "error",
7606 }, {
7607 name: "HTTP1 with no server support",
7608 scheme: "http",
7609 transport: func(tr *Transport) {
7610 tr.Protocols = &Protocols{}
7611 tr.Protocols.SetHTTP1(true)
7612 },
7613 server: func(srv *Server) {
7614 srv.Protocols = &Protocols{}
7615 srv.Protocols.SetUnencryptedHTTP2(true)
7616 },
7617 want: "error",
7618 }, {
7619 name: "HTTPS1 with no server support",
7620 scheme: "https",
7621 transport: func(tr *Transport) {
7622 tr.Protocols = &Protocols{}
7623 tr.Protocols.SetHTTP1(true)
7624 },
7625 server: func(srv *Server) {
7626 srv.Protocols = &Protocols{}
7627 srv.Protocols.SetHTTP2(true)
7628 },
7629 want: "error",
7630 }, {
7631
7632 name: "ConfigureServer updates TLSNextProto",
7633 scheme: "https",
7634 transport: func(tr *Transport) {
7635 tr.Protocols = &Protocols{}
7636 tr.Protocols.SetHTTP2(true)
7637 },
7638 server: func(srv *Server) {
7639 srv.TLSNextProto = map[string]func(*http.Server, *tls.Conn, http.Handler){}
7640 testHTTP2ConfigureServer(srv)
7641 },
7642 want: "HTTP/2.0",
7643 }} {
7644 t.Run(test.name, func(t *testing.T) {
7645
7646
7647 srv := &Server{
7648 TLSConfig: &tls.Config{
7649 Certificates: []tls.Certificate{cert},
7650 },
7651 Handler: HandlerFunc(func(w ResponseWriter, req *Request) {
7652 w.Header().Set("X-Proto", req.Proto)
7653 }),
7654 }
7655 tr := &Transport{
7656 TLSClientConfig: &tls.Config{
7657 RootCAs: certpool,
7658 },
7659 }
7660
7661 if test.setup != nil {
7662 test.setup(t)
7663 }
7664 if test.server != nil {
7665 test.server(srv)
7666 }
7667 if test.transport != nil {
7668 test.transport(tr)
7669 } else {
7670 tr.Protocols = &Protocols{}
7671 tr.Protocols.SetHTTP1(true)
7672 tr.Protocols.SetHTTP2(true)
7673 }
7674
7675 listener := newLocalListener(t)
7676 srvc := make(chan error, 1)
7677 go func() {
7678 switch test.scheme {
7679 case "http":
7680 srvc <- srv.Serve(listener)
7681 case "https":
7682 srvc <- srv.ServeTLS(listener, "", "")
7683 }
7684 }()
7685 t.Cleanup(func() {
7686 srv.Close()
7687 <-srvc
7688 })
7689
7690 client := &Client{Transport: tr}
7691 resp, err := client.Get(test.scheme + "://" + listener.Addr().String())
7692 if err != nil {
7693 if test.want == "error" {
7694 return
7695 }
7696 t.Fatal(err)
7697 }
7698 if got := resp.Header.Get("X-Proto"); got != test.want {
7699 t.Fatalf("request proto %q, want %q", got, test.want)
7700 }
7701 })
7702 }
7703 }
7704
7705
7706 func testHTTP2ConfigureServer(s *Server) {
7707 s.Serve(testHTTP2ServerConfig{})
7708 }
7709
7710 type testHTTP2ServerConfig struct {
7711 net.Listener
7712 }
7713
7714 func (testHTTP2ServerConfig) HTTP2Config() HTTP2Config {
7715 return HTTP2Config{}
7716 }
7717 func (testHTTP2ServerConfig) IdleTimeout() time.Duration {
7718 return 0
7719 }
7720 func (testHTTP2ServerConfig) ServeConnFunc(func(ctx context.Context, nc net.Conn, h Handler, sawClientPreface bool, upgradeReq *Request, settings []byte)) {
7721 }
7722
7723 func TestIssue61474(t *testing.T) {
7724 runSynctest(t, testIssue61474, []testMode{http2Mode})
7725 }
7726 func testIssue61474(t *testing.T, mode testMode) {
7727 if testing.Short() {
7728 return
7729 }
7730
7731
7732
7733
7734 t.Skip("test is too large")
7735
7736 cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
7737 }), func(tr *Transport) {
7738 tr.MaxConnsPerHost = 1
7739 })
7740 var wg sync.WaitGroup
7741 defer wg.Wait()
7742 for range 100000 {
7743 wg.Go(func() {
7744 ctx, cancel := context.WithTimeout(t.Context(), 1*time.Millisecond)
7745 defer cancel()
7746 req, _ := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil)
7747 resp, err := cst.c.Do(req)
7748 if err == nil {
7749 resp.Body.Close()
7750 }
7751 })
7752 }
7753 }
7754
7755
7756
7757 func TestTransportResponseWriteAfterEarlyClose(t *testing.T) {
7758 runSynctest(t, testTransportResponseWriteAfterEarlyClose, []testMode{http1Mode})
7759 }
7760 func testTransportResponseWriteAfterEarlyClose(t *testing.T, mode testMode) {
7761 cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
7762 io.WriteString(w, "hello")
7763 }))
7764 res, err := cst.c.Get(cst.ts.URL)
7765 if err != nil {
7766 t.Fatal(err)
7767 }
7768 if err := res.Body.Close(); err != nil {
7769 t.Fatal(err)
7770 }
7771 res.ContentLength = 0
7772 }
7773
View as plain text