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