Source file
src/net/http/transport.go
1
2
3
4
5
6
7
8
9
10 package http
11
12 import (
13 "bufio"
14 "compress/gzip"
15 "container/list"
16 "context"
17 "crypto/tls"
18 "errors"
19 "fmt"
20 "internal/godebug"
21 "io"
22 "log"
23 "net"
24 "net/http/httptrace"
25 "net/http/internal/ascii"
26 "net/textproto"
27 "net/url"
28 "reflect"
29 "strings"
30 "sync"
31 "sync/atomic"
32 "time"
33
34 "golang.org/x/net/http/httpguts"
35 "golang.org/x/net/http/httpproxy"
36 )
37
38
39
40
41
42
43 var DefaultTransport RoundTripper = &Transport{
44 Proxy: ProxyFromEnvironment,
45 DialContext: defaultTransportDialContext(&net.Dialer{
46 Timeout: 30 * time.Second,
47 KeepAlive: 30 * time.Second,
48 }),
49 ForceAttemptHTTP2: true,
50 MaxIdleConns: 100,
51 IdleConnTimeout: 90 * time.Second,
52 TLSHandshakeTimeout: 10 * time.Second,
53 ExpectContinueTimeout: 1 * time.Second,
54 }
55
56
57
58 const DefaultMaxIdleConnsPerHost = 2
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 type Transport struct {
96 idleMu sync.Mutex
97 closeIdle bool
98 idleConn map[connectMethodKey][]*persistConn
99 idleConnWait map[connectMethodKey]wantConnQueue
100 idleLRU connLRU
101
102 reqMu sync.Mutex
103 reqCanceler map[cancelKey]func(error)
104
105 altMu sync.Mutex
106 altProto atomic.Value
107
108 connsPerHostMu sync.Mutex
109 connsPerHost map[connectMethodKey]int
110 connsPerHostWait map[connectMethodKey]wantConnQueue
111
112
113
114
115
116
117
118
119
120
121 Proxy func(*Request) (*url.URL, error)
122
123
124
125
126 OnProxyConnectResponse func(ctx context.Context, proxyURL *url.URL, connectReq *Request, connectRes *Response) error
127
128
129
130
131
132
133
134
135
136 DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
137
138
139
140
141
142
143
144
145
146
147
148 Dial func(network, addr string) (net.Conn, error)
149
150
151
152
153
154
155
156
157
158
159
160 DialTLSContext func(ctx context.Context, network, addr string) (net.Conn, error)
161
162
163
164
165
166
167
168 DialTLS func(network, addr string) (net.Conn, error)
169
170
171
172
173
174 TLSClientConfig *tls.Config
175
176
177
178 TLSHandshakeTimeout time.Duration
179
180
181
182
183
184
185 DisableKeepAlives bool
186
187
188
189
190
191
192
193
194
195 DisableCompression bool
196
197
198
199 MaxIdleConns int
200
201
202
203
204 MaxIdleConnsPerHost int
205
206
207
208
209
210
211 MaxConnsPerHost int
212
213
214
215
216
217 IdleConnTimeout time.Duration
218
219
220
221
222
223 ResponseHeaderTimeout time.Duration
224
225
226
227
228
229
230
231
232 ExpectContinueTimeout time.Duration
233
234
235
236
237
238
239
240
241
242
243
244 TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
245
246
247
248
249 ProxyConnectHeader Header
250
251
252
253
254
255
256
257
258 GetProxyConnectHeader func(ctx context.Context, proxyURL *url.URL, target string) (Header, error)
259
260
261
262
263
264
265 MaxResponseHeaderBytes int64
266
267
268
269
270 WriteBufferSize int
271
272
273
274
275 ReadBufferSize int
276
277
278
279 nextProtoOnce sync.Once
280 h2transport h2Transport
281 tlsNextProtoWasNil bool
282
283
284
285
286
287
288 ForceAttemptHTTP2 bool
289 }
290
291
292
293
294 type cancelKey struct {
295 req *Request
296 }
297
298 func (t *Transport) writeBufferSize() int {
299 if t.WriteBufferSize > 0 {
300 return t.WriteBufferSize
301 }
302 return 4 << 10
303 }
304
305 func (t *Transport) readBufferSize() int {
306 if t.ReadBufferSize > 0 {
307 return t.ReadBufferSize
308 }
309 return 4 << 10
310 }
311
312
313 func (t *Transport) Clone() *Transport {
314 t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
315 t2 := &Transport{
316 Proxy: t.Proxy,
317 OnProxyConnectResponse: t.OnProxyConnectResponse,
318 DialContext: t.DialContext,
319 Dial: t.Dial,
320 DialTLS: t.DialTLS,
321 DialTLSContext: t.DialTLSContext,
322 TLSHandshakeTimeout: t.TLSHandshakeTimeout,
323 DisableKeepAlives: t.DisableKeepAlives,
324 DisableCompression: t.DisableCompression,
325 MaxIdleConns: t.MaxIdleConns,
326 MaxIdleConnsPerHost: t.MaxIdleConnsPerHost,
327 MaxConnsPerHost: t.MaxConnsPerHost,
328 IdleConnTimeout: t.IdleConnTimeout,
329 ResponseHeaderTimeout: t.ResponseHeaderTimeout,
330 ExpectContinueTimeout: t.ExpectContinueTimeout,
331 ProxyConnectHeader: t.ProxyConnectHeader.Clone(),
332 GetProxyConnectHeader: t.GetProxyConnectHeader,
333 MaxResponseHeaderBytes: t.MaxResponseHeaderBytes,
334 ForceAttemptHTTP2: t.ForceAttemptHTTP2,
335 WriteBufferSize: t.WriteBufferSize,
336 ReadBufferSize: t.ReadBufferSize,
337 }
338 if t.TLSClientConfig != nil {
339 t2.TLSClientConfig = t.TLSClientConfig.Clone()
340 }
341 if !t.tlsNextProtoWasNil {
342 npm := map[string]func(authority string, c *tls.Conn) RoundTripper{}
343 for k, v := range t.TLSNextProto {
344 npm[k] = v
345 }
346 t2.TLSNextProto = npm
347 }
348 return t2
349 }
350
351
352
353
354
355
356
357 type h2Transport interface {
358 CloseIdleConnections()
359 }
360
361 func (t *Transport) hasCustomTLSDialer() bool {
362 return t.DialTLS != nil || t.DialTLSContext != nil
363 }
364
365 var http2client = godebug.New("http2client")
366
367
368
369 func (t *Transport) onceSetNextProtoDefaults() {
370 t.tlsNextProtoWasNil = (t.TLSNextProto == nil)
371 if http2client.Value() == "0" {
372 return
373 }
374
375
376
377
378
379
380 altProto, _ := t.altProto.Load().(map[string]RoundTripper)
381 if rv := reflect.ValueOf(altProto["https"]); rv.IsValid() && rv.Type().Kind() == reflect.Struct && rv.Type().NumField() == 1 {
382 if v := rv.Field(0); v.CanInterface() {
383 if h2i, ok := v.Interface().(h2Transport); ok {
384 t.h2transport = h2i
385 return
386 }
387 }
388 }
389
390 if t.TLSNextProto != nil {
391
392
393 return
394 }
395 if !t.ForceAttemptHTTP2 && (t.TLSClientConfig != nil || t.Dial != nil || t.DialContext != nil || t.hasCustomTLSDialer()) {
396
397
398
399
400
401
402 return
403 }
404 if omitBundledHTTP2 {
405 return
406 }
407 t2, err := http2configureTransports(t)
408 if err != nil {
409 log.Printf("Error enabling Transport HTTP/2 support: %v", err)
410 return
411 }
412 t.h2transport = t2
413
414
415
416
417
418
419
420 if limit1 := t.MaxResponseHeaderBytes; limit1 != 0 && t2.MaxHeaderListSize == 0 {
421 const h2max = 1<<32 - 1
422 if limit1 >= h2max {
423 t2.MaxHeaderListSize = h2max
424 } else {
425 t2.MaxHeaderListSize = uint32(limit1)
426 }
427 }
428 }
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447 func ProxyFromEnvironment(req *Request) (*url.URL, error) {
448 return envProxyFunc()(req.URL)
449 }
450
451
452
453 func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
454 return func(*Request) (*url.URL, error) {
455 return fixedURL, nil
456 }
457 }
458
459
460
461
462 type transportRequest struct {
463 *Request
464 extra Header
465 trace *httptrace.ClientTrace
466 cancelKey cancelKey
467
468 mu sync.Mutex
469 err error
470 }
471
472 func (tr *transportRequest) extraHeaders() Header {
473 if tr.extra == nil {
474 tr.extra = make(Header)
475 }
476 return tr.extra
477 }
478
479 func (tr *transportRequest) setError(err error) {
480 tr.mu.Lock()
481 if tr.err == nil {
482 tr.err = err
483 }
484 tr.mu.Unlock()
485 }
486
487
488
489 func (t *Transport) useRegisteredProtocol(req *Request) bool {
490 if req.URL.Scheme == "https" && req.requiresHTTP1() {
491
492
493
494
495 return false
496 }
497 return true
498 }
499
500
501
502
503 func (t *Transport) alternateRoundTripper(req *Request) RoundTripper {
504 if !t.useRegisteredProtocol(req) {
505 return nil
506 }
507 altProto, _ := t.altProto.Load().(map[string]RoundTripper)
508 return altProto[req.URL.Scheme]
509 }
510
511
512 func (t *Transport) roundTrip(req *Request) (*Response, error) {
513 t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
514 ctx := req.Context()
515 trace := httptrace.ContextClientTrace(ctx)
516
517 if req.URL == nil {
518 req.closeBody()
519 return nil, errors.New("http: nil Request.URL")
520 }
521 if req.Header == nil {
522 req.closeBody()
523 return nil, errors.New("http: nil Request.Header")
524 }
525 scheme := req.URL.Scheme
526 isHTTP := scheme == "http" || scheme == "https"
527 if isHTTP {
528 for k, vv := range req.Header {
529 if !httpguts.ValidHeaderFieldName(k) {
530 req.closeBody()
531 return nil, fmt.Errorf("net/http: invalid header field name %q", k)
532 }
533 for _, v := range vv {
534 if !httpguts.ValidHeaderFieldValue(v) {
535 req.closeBody()
536
537 return nil, fmt.Errorf("net/http: invalid header field value for %q", k)
538 }
539 }
540 }
541 }
542
543 origReq := req
544 cancelKey := cancelKey{origReq}
545 req = setupRewindBody(req)
546
547 if altRT := t.alternateRoundTripper(req); altRT != nil {
548 if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
549 return resp, err
550 }
551 var err error
552 req, err = rewindBody(req)
553 if err != nil {
554 return nil, err
555 }
556 }
557 if !isHTTP {
558 req.closeBody()
559 return nil, badStringError("unsupported protocol scheme", scheme)
560 }
561 if req.Method != "" && !validMethod(req.Method) {
562 req.closeBody()
563 return nil, fmt.Errorf("net/http: invalid method %q", req.Method)
564 }
565 if req.URL.Host == "" {
566 req.closeBody()
567 return nil, errors.New("http: no Host in request URL")
568 }
569
570 for {
571 select {
572 case <-ctx.Done():
573 req.closeBody()
574 return nil, ctx.Err()
575 default:
576 }
577
578
579 treq := &transportRequest{Request: req, trace: trace, cancelKey: cancelKey}
580 cm, err := t.connectMethodForRequest(treq)
581 if err != nil {
582 req.closeBody()
583 return nil, err
584 }
585
586
587
588
589
590 pconn, err := t.getConn(treq, cm)
591 if err != nil {
592 t.setReqCanceler(cancelKey, nil)
593 req.closeBody()
594 return nil, err
595 }
596
597 var resp *Response
598 if pconn.alt != nil {
599
600 t.setReqCanceler(cancelKey, nil)
601 resp, err = pconn.alt.RoundTrip(req)
602 } else {
603 resp, err = pconn.roundTrip(treq)
604 }
605 if err == nil {
606 resp.Request = origReq
607 return resp, nil
608 }
609
610
611 if http2isNoCachedConnError(err) {
612 if t.removeIdleConn(pconn) {
613 t.decConnsPerHost(pconn.cacheKey)
614 }
615 } else if !pconn.shouldRetryRequest(req, err) {
616
617
618 if e, ok := err.(nothingWrittenError); ok {
619 err = e.error
620 }
621 if e, ok := err.(transportReadFromServerError); ok {
622 err = e.err
623 }
624 return nil, err
625 }
626 testHookRoundTripRetried()
627
628
629 req, err = rewindBody(req)
630 if err != nil {
631 return nil, err
632 }
633 }
634 }
635
636 var errCannotRewind = errors.New("net/http: cannot rewind body after connection loss")
637
638 type readTrackingBody struct {
639 io.ReadCloser
640 didRead bool
641 didClose bool
642 }
643
644 func (r *readTrackingBody) Read(data []byte) (int, error) {
645 r.didRead = true
646 return r.ReadCloser.Read(data)
647 }
648
649 func (r *readTrackingBody) Close() error {
650 r.didClose = true
651 return r.ReadCloser.Close()
652 }
653
654
655
656
657
658 func setupRewindBody(req *Request) *Request {
659 if req.Body == nil || req.Body == NoBody {
660 return req
661 }
662 newReq := *req
663 newReq.Body = &readTrackingBody{ReadCloser: req.Body}
664 return &newReq
665 }
666
667
668
669
670
671 func rewindBody(req *Request) (rewound *Request, err error) {
672 if req.Body == nil || req.Body == NoBody || (!req.Body.(*readTrackingBody).didRead && !req.Body.(*readTrackingBody).didClose) {
673 return req, nil
674 }
675 if !req.Body.(*readTrackingBody).didClose {
676 req.closeBody()
677 }
678 if req.GetBody == nil {
679 return nil, errCannotRewind
680 }
681 body, err := req.GetBody()
682 if err != nil {
683 return nil, err
684 }
685 newReq := *req
686 newReq.Body = &readTrackingBody{ReadCloser: body}
687 return &newReq, nil
688 }
689
690
691
692
693 func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
694 if http2isNoCachedConnError(err) {
695
696
697
698
699
700
701 return true
702 }
703 if err == errMissingHost {
704
705 return false
706 }
707 if !pc.isReused() {
708
709
710
711
712
713
714
715 return false
716 }
717 if _, ok := err.(nothingWrittenError); ok {
718
719
720 return req.outgoingLength() == 0 || req.GetBody != nil
721 }
722 if !req.isReplayable() {
723
724 return false
725 }
726 if _, ok := err.(transportReadFromServerError); ok {
727
728
729 return true
730 }
731 if err == errServerClosedIdle {
732
733
734
735 return true
736 }
737 return false
738 }
739
740
741 var ErrSkipAltProtocol = errors.New("net/http: skip alternate protocol")
742
743
744
745
746
747
748
749
750
751
752
753 func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
754 t.altMu.Lock()
755 defer t.altMu.Unlock()
756 oldMap, _ := t.altProto.Load().(map[string]RoundTripper)
757 if _, exists := oldMap[scheme]; exists {
758 panic("protocol " + scheme + " already registered")
759 }
760 newMap := make(map[string]RoundTripper)
761 for k, v := range oldMap {
762 newMap[k] = v
763 }
764 newMap[scheme] = rt
765 t.altProto.Store(newMap)
766 }
767
768
769
770
771
772 func (t *Transport) CloseIdleConnections() {
773 t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
774 t.idleMu.Lock()
775 m := t.idleConn
776 t.idleConn = nil
777 t.closeIdle = true
778 t.idleLRU = connLRU{}
779 t.idleMu.Unlock()
780 for _, conns := range m {
781 for _, pconn := range conns {
782 pconn.close(errCloseIdleConns)
783 }
784 }
785 if t2 := t.h2transport; t2 != nil {
786 t2.CloseIdleConnections()
787 }
788 }
789
790
791
792
793
794
795
796 func (t *Transport) CancelRequest(req *Request) {
797 t.cancelRequest(cancelKey{req}, errRequestCanceled)
798 }
799
800
801
802 func (t *Transport) cancelRequest(key cancelKey, err error) bool {
803
804
805 t.reqMu.Lock()
806 defer t.reqMu.Unlock()
807 cancel := t.reqCanceler[key]
808 delete(t.reqCanceler, key)
809 if cancel != nil {
810 cancel(err)
811 }
812
813 return cancel != nil
814 }
815
816
817
818
819
820 var (
821 envProxyOnce sync.Once
822 envProxyFuncValue func(*url.URL) (*url.URL, error)
823 )
824
825
826
827 func envProxyFunc() func(*url.URL) (*url.URL, error) {
828 envProxyOnce.Do(func() {
829 envProxyFuncValue = httpproxy.FromEnvironment().ProxyFunc()
830 })
831 return envProxyFuncValue
832 }
833
834
835 func resetProxyConfig() {
836 envProxyOnce = sync.Once{}
837 envProxyFuncValue = nil
838 }
839
840 func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
841 cm.targetScheme = treq.URL.Scheme
842 cm.targetAddr = canonicalAddr(treq.URL)
843 if t.Proxy != nil {
844 cm.proxyURL, err = t.Proxy(treq.Request)
845 }
846 cm.onlyH1 = treq.requiresHTTP1()
847 return cm, err
848 }
849
850
851
852 func (cm *connectMethod) proxyAuth() string {
853 if cm.proxyURL == nil {
854 return ""
855 }
856 if u := cm.proxyURL.User; u != nil {
857 username := u.Username()
858 password, _ := u.Password()
859 return "Basic " + basicAuth(username, password)
860 }
861 return ""
862 }
863
864
865 var (
866 errKeepAlivesDisabled = errors.New("http: putIdleConn: keep alives disabled")
867 errConnBroken = errors.New("http: putIdleConn: connection is in bad state")
868 errCloseIdle = errors.New("http: putIdleConn: CloseIdleConnections was called")
869 errTooManyIdle = errors.New("http: putIdleConn: too many idle connections")
870 errTooManyIdleHost = errors.New("http: putIdleConn: too many idle connections for host")
871 errCloseIdleConns = errors.New("http: CloseIdleConnections called")
872 errReadLoopExiting = errors.New("http: persistConn.readLoop exiting")
873 errIdleConnTimeout = errors.New("http: idle connection timeout")
874
875
876
877
878
879 errServerClosedIdle = errors.New("http: server closed idle connection")
880 )
881
882
883
884
885
886
887
888
889
890 type transportReadFromServerError struct {
891 err error
892 }
893
894 func (e transportReadFromServerError) Unwrap() error { return e.err }
895
896 func (e transportReadFromServerError) Error() string {
897 return fmt.Sprintf("net/http: Transport failed to read from server: %v", e.err)
898 }
899
900 func (t *Transport) putOrCloseIdleConn(pconn *persistConn) {
901 if err := t.tryPutIdleConn(pconn); err != nil {
902 pconn.close(err)
903 }
904 }
905
906 func (t *Transport) maxIdleConnsPerHost() int {
907 if v := t.MaxIdleConnsPerHost; v != 0 {
908 return v
909 }
910 return DefaultMaxIdleConnsPerHost
911 }
912
913
914
915
916
917
918 func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
919 if t.DisableKeepAlives || t.MaxIdleConnsPerHost < 0 {
920 return errKeepAlivesDisabled
921 }
922 if pconn.isBroken() {
923 return errConnBroken
924 }
925 pconn.markReused()
926
927 t.idleMu.Lock()
928 defer t.idleMu.Unlock()
929
930
931
932
933 if pconn.alt != nil && t.idleLRU.m[pconn] != nil {
934 return nil
935 }
936
937
938
939
940
941 key := pconn.cacheKey
942 if q, ok := t.idleConnWait[key]; ok {
943 done := false
944 if pconn.alt == nil {
945
946
947 for q.len() > 0 {
948 w := q.popFront()
949 if w.tryDeliver(pconn, nil) {
950 done = true
951 break
952 }
953 }
954 } else {
955
956
957
958
959 for q.len() > 0 {
960 w := q.popFront()
961 w.tryDeliver(pconn, nil)
962 }
963 }
964 if q.len() == 0 {
965 delete(t.idleConnWait, key)
966 } else {
967 t.idleConnWait[key] = q
968 }
969 if done {
970 return nil
971 }
972 }
973
974 if t.closeIdle {
975 return errCloseIdle
976 }
977 if t.idleConn == nil {
978 t.idleConn = make(map[connectMethodKey][]*persistConn)
979 }
980 idles := t.idleConn[key]
981 if len(idles) >= t.maxIdleConnsPerHost() {
982 return errTooManyIdleHost
983 }
984 for _, exist := range idles {
985 if exist == pconn {
986 log.Fatalf("dup idle pconn %p in freelist", pconn)
987 }
988 }
989 t.idleConn[key] = append(idles, pconn)
990 t.idleLRU.add(pconn)
991 if t.MaxIdleConns != 0 && t.idleLRU.len() > t.MaxIdleConns {
992 oldest := t.idleLRU.removeOldest()
993 oldest.close(errTooManyIdle)
994 t.removeIdleConnLocked(oldest)
995 }
996
997
998
999
1000 if t.IdleConnTimeout > 0 && pconn.alt == nil {
1001 if pconn.idleTimer != nil {
1002 pconn.idleTimer.Reset(t.IdleConnTimeout)
1003 } else {
1004 pconn.idleTimer = time.AfterFunc(t.IdleConnTimeout, pconn.closeConnIfStillIdle)
1005 }
1006 }
1007 pconn.idleAt = time.Now()
1008 return nil
1009 }
1010
1011
1012
1013
1014 func (t *Transport) queueForIdleConn(w *wantConn) (delivered bool) {
1015 if t.DisableKeepAlives {
1016 return false
1017 }
1018
1019 t.idleMu.Lock()
1020 defer t.idleMu.Unlock()
1021
1022
1023
1024 t.closeIdle = false
1025
1026 if w == nil {
1027
1028 return false
1029 }
1030
1031
1032
1033
1034 var oldTime time.Time
1035 if t.IdleConnTimeout > 0 {
1036 oldTime = time.Now().Add(-t.IdleConnTimeout)
1037 }
1038
1039
1040 if list, ok := t.idleConn[w.key]; ok {
1041 stop := false
1042 delivered := false
1043 for len(list) > 0 && !stop {
1044 pconn := list[len(list)-1]
1045
1046
1047
1048
1049 tooOld := !oldTime.IsZero() && pconn.idleAt.Round(0).Before(oldTime)
1050 if tooOld {
1051
1052
1053
1054 go pconn.closeConnIfStillIdle()
1055 }
1056 if pconn.isBroken() || tooOld {
1057
1058
1059
1060
1061
1062 list = list[:len(list)-1]
1063 continue
1064 }
1065 delivered = w.tryDeliver(pconn, nil)
1066 if delivered {
1067 if pconn.alt != nil {
1068
1069
1070 } else {
1071
1072
1073 t.idleLRU.remove(pconn)
1074 list = list[:len(list)-1]
1075 }
1076 }
1077 stop = true
1078 }
1079 if len(list) > 0 {
1080 t.idleConn[w.key] = list
1081 } else {
1082 delete(t.idleConn, w.key)
1083 }
1084 if stop {
1085 return delivered
1086 }
1087 }
1088
1089
1090 if t.idleConnWait == nil {
1091 t.idleConnWait = make(map[connectMethodKey]wantConnQueue)
1092 }
1093 q := t.idleConnWait[w.key]
1094 q.cleanFront()
1095 q.pushBack(w)
1096 t.idleConnWait[w.key] = q
1097 return false
1098 }
1099
1100
1101 func (t *Transport) removeIdleConn(pconn *persistConn) bool {
1102 t.idleMu.Lock()
1103 defer t.idleMu.Unlock()
1104 return t.removeIdleConnLocked(pconn)
1105 }
1106
1107
1108 func (t *Transport) removeIdleConnLocked(pconn *persistConn) bool {
1109 if pconn.idleTimer != nil {
1110 pconn.idleTimer.Stop()
1111 }
1112 t.idleLRU.remove(pconn)
1113 key := pconn.cacheKey
1114 pconns := t.idleConn[key]
1115 var removed bool
1116 switch len(pconns) {
1117 case 0:
1118
1119 case 1:
1120 if pconns[0] == pconn {
1121 delete(t.idleConn, key)
1122 removed = true
1123 }
1124 default:
1125 for i, v := range pconns {
1126 if v != pconn {
1127 continue
1128 }
1129
1130
1131 copy(pconns[i:], pconns[i+1:])
1132 t.idleConn[key] = pconns[:len(pconns)-1]
1133 removed = true
1134 break
1135 }
1136 }
1137 return removed
1138 }
1139
1140 func (t *Transport) setReqCanceler(key cancelKey, fn func(error)) {
1141 t.reqMu.Lock()
1142 defer t.reqMu.Unlock()
1143 if t.reqCanceler == nil {
1144 t.reqCanceler = make(map[cancelKey]func(error))
1145 }
1146 if fn != nil {
1147 t.reqCanceler[key] = fn
1148 } else {
1149 delete(t.reqCanceler, key)
1150 }
1151 }
1152
1153
1154
1155
1156
1157 func (t *Transport) replaceReqCanceler(key cancelKey, fn func(error)) bool {
1158 t.reqMu.Lock()
1159 defer t.reqMu.Unlock()
1160 _, ok := t.reqCanceler[key]
1161 if !ok {
1162 return false
1163 }
1164 if fn != nil {
1165 t.reqCanceler[key] = fn
1166 } else {
1167 delete(t.reqCanceler, key)
1168 }
1169 return true
1170 }
1171
1172 var zeroDialer net.Dialer
1173
1174 func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, error) {
1175 if t.DialContext != nil {
1176 return t.DialContext(ctx, network, addr)
1177 }
1178 if t.Dial != nil {
1179 c, err := t.Dial(network, addr)
1180 if c == nil && err == nil {
1181 err = errors.New("net/http: Transport.Dial hook returned (nil, nil)")
1182 }
1183 return c, err
1184 }
1185 return zeroDialer.DialContext(ctx, network, addr)
1186 }
1187
1188
1189
1190
1191
1192
1193
1194 type wantConn struct {
1195 cm connectMethod
1196 key connectMethodKey
1197 ctx context.Context
1198 ready chan struct{}
1199
1200
1201
1202
1203 beforeDial func()
1204 afterDial func()
1205
1206 mu sync.Mutex
1207 pc *persistConn
1208 err error
1209 }
1210
1211
1212 func (w *wantConn) waiting() bool {
1213 select {
1214 case <-w.ready:
1215 return false
1216 default:
1217 return true
1218 }
1219 }
1220
1221
1222 func (w *wantConn) tryDeliver(pc *persistConn, err error) bool {
1223 w.mu.Lock()
1224 defer w.mu.Unlock()
1225
1226 if w.pc != nil || w.err != nil {
1227 return false
1228 }
1229
1230 w.pc = pc
1231 w.err = err
1232 if w.pc == nil && w.err == nil {
1233 panic("net/http: internal error: misuse of tryDeliver")
1234 }
1235 close(w.ready)
1236 return true
1237 }
1238
1239
1240
1241 func (w *wantConn) cancel(t *Transport, err error) {
1242 w.mu.Lock()
1243 if w.pc == nil && w.err == nil {
1244 close(w.ready)
1245 }
1246 pc := w.pc
1247 w.pc = nil
1248 w.err = err
1249 w.mu.Unlock()
1250
1251 if pc != nil {
1252 t.putOrCloseIdleConn(pc)
1253 }
1254 }
1255
1256
1257 type wantConnQueue struct {
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268 head []*wantConn
1269 headPos int
1270 tail []*wantConn
1271 }
1272
1273
1274 func (q *wantConnQueue) len() int {
1275 return len(q.head) - q.headPos + len(q.tail)
1276 }
1277
1278
1279 func (q *wantConnQueue) pushBack(w *wantConn) {
1280 q.tail = append(q.tail, w)
1281 }
1282
1283
1284 func (q *wantConnQueue) popFront() *wantConn {
1285 if q.headPos >= len(q.head) {
1286 if len(q.tail) == 0 {
1287 return nil
1288 }
1289
1290 q.head, q.headPos, q.tail = q.tail, 0, q.head[:0]
1291 }
1292 w := q.head[q.headPos]
1293 q.head[q.headPos] = nil
1294 q.headPos++
1295 return w
1296 }
1297
1298
1299 func (q *wantConnQueue) peekFront() *wantConn {
1300 if q.headPos < len(q.head) {
1301 return q.head[q.headPos]
1302 }
1303 if len(q.tail) > 0 {
1304 return q.tail[0]
1305 }
1306 return nil
1307 }
1308
1309
1310
1311 func (q *wantConnQueue) cleanFront() (cleaned bool) {
1312 for {
1313 w := q.peekFront()
1314 if w == nil || w.waiting() {
1315 return cleaned
1316 }
1317 q.popFront()
1318 cleaned = true
1319 }
1320 }
1321
1322 func (t *Transport) customDialTLS(ctx context.Context, network, addr string) (conn net.Conn, err error) {
1323 if t.DialTLSContext != nil {
1324 conn, err = t.DialTLSContext(ctx, network, addr)
1325 } else {
1326 conn, err = t.DialTLS(network, addr)
1327 }
1328 if conn == nil && err == nil {
1329 err = errors.New("net/http: Transport.DialTLS or DialTLSContext returned (nil, nil)")
1330 }
1331 return
1332 }
1333
1334
1335
1336
1337
1338 func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persistConn, err error) {
1339 req := treq.Request
1340 trace := treq.trace
1341 ctx := req.Context()
1342 if trace != nil && trace.GetConn != nil {
1343 trace.GetConn(cm.addr())
1344 }
1345
1346 w := &wantConn{
1347 cm: cm,
1348 key: cm.key(),
1349 ctx: ctx,
1350 ready: make(chan struct{}, 1),
1351 beforeDial: testHookPrePendingDial,
1352 afterDial: testHookPostPendingDial,
1353 }
1354 defer func() {
1355 if err != nil {
1356 w.cancel(t, err)
1357 }
1358 }()
1359
1360
1361 if delivered := t.queueForIdleConn(w); delivered {
1362 pc := w.pc
1363
1364
1365 if pc.alt == nil && trace != nil && trace.GotConn != nil {
1366 trace.GotConn(pc.gotIdleConnTrace(pc.idleAt))
1367 }
1368
1369
1370
1371 t.setReqCanceler(treq.cancelKey, func(error) {})
1372 return pc, nil
1373 }
1374
1375 cancelc := make(chan error, 1)
1376 t.setReqCanceler(treq.cancelKey, func(err error) { cancelc <- err })
1377
1378
1379 t.queueForDial(w)
1380
1381
1382 select {
1383 case <-w.ready:
1384
1385
1386 if w.pc != nil && w.pc.alt == nil && trace != nil && trace.GotConn != nil {
1387 trace.GotConn(httptrace.GotConnInfo{Conn: w.pc.conn, Reused: w.pc.isReused()})
1388 }
1389 if w.err != nil {
1390
1391
1392
1393 select {
1394 case <-req.Cancel:
1395 return nil, errRequestCanceledConn
1396 case <-req.Context().Done():
1397 return nil, req.Context().Err()
1398 case err := <-cancelc:
1399 if err == errRequestCanceled {
1400 err = errRequestCanceledConn
1401 }
1402 return nil, err
1403 default:
1404
1405 }
1406 }
1407 return w.pc, w.err
1408 case <-req.Cancel:
1409 return nil, errRequestCanceledConn
1410 case <-req.Context().Done():
1411 return nil, req.Context().Err()
1412 case err := <-cancelc:
1413 if err == errRequestCanceled {
1414 err = errRequestCanceledConn
1415 }
1416 return nil, err
1417 }
1418 }
1419
1420
1421
1422 func (t *Transport) queueForDial(w *wantConn) {
1423 w.beforeDial()
1424 if t.MaxConnsPerHost <= 0 {
1425 go t.dialConnFor(w)
1426 return
1427 }
1428
1429 t.connsPerHostMu.Lock()
1430 defer t.connsPerHostMu.Unlock()
1431
1432 if n := t.connsPerHost[w.key]; n < t.MaxConnsPerHost {
1433 if t.connsPerHost == nil {
1434 t.connsPerHost = make(map[connectMethodKey]int)
1435 }
1436 t.connsPerHost[w.key] = n + 1
1437 go t.dialConnFor(w)
1438 return
1439 }
1440
1441 if t.connsPerHostWait == nil {
1442 t.connsPerHostWait = make(map[connectMethodKey]wantConnQueue)
1443 }
1444 q := t.connsPerHostWait[w.key]
1445 q.cleanFront()
1446 q.pushBack(w)
1447 t.connsPerHostWait[w.key] = q
1448 }
1449
1450
1451
1452
1453 func (t *Transport) dialConnFor(w *wantConn) {
1454 defer w.afterDial()
1455
1456 pc, err := t.dialConn(w.ctx, w.cm)
1457 delivered := w.tryDeliver(pc, err)
1458 if err == nil && (!delivered || pc.alt != nil) {
1459
1460
1461
1462 t.putOrCloseIdleConn(pc)
1463 }
1464 if err != nil {
1465 t.decConnsPerHost(w.key)
1466 }
1467 }
1468
1469
1470
1471 func (t *Transport) decConnsPerHost(key connectMethodKey) {
1472 if t.MaxConnsPerHost <= 0 {
1473 return
1474 }
1475
1476 t.connsPerHostMu.Lock()
1477 defer t.connsPerHostMu.Unlock()
1478 n := t.connsPerHost[key]
1479 if n == 0 {
1480
1481
1482 panic("net/http: internal error: connCount underflow")
1483 }
1484
1485
1486
1487
1488
1489 if q := t.connsPerHostWait[key]; q.len() > 0 {
1490 done := false
1491 for q.len() > 0 {
1492 w := q.popFront()
1493 if w.waiting() {
1494 go t.dialConnFor(w)
1495 done = true
1496 break
1497 }
1498 }
1499 if q.len() == 0 {
1500 delete(t.connsPerHostWait, key)
1501 } else {
1502
1503
1504 t.connsPerHostWait[key] = q
1505 }
1506 if done {
1507 return
1508 }
1509 }
1510
1511
1512 if n--; n == 0 {
1513 delete(t.connsPerHost, key)
1514 } else {
1515 t.connsPerHost[key] = n
1516 }
1517 }
1518
1519
1520
1521
1522 func (pconn *persistConn) addTLS(ctx context.Context, name string, trace *httptrace.ClientTrace) error {
1523
1524 cfg := cloneTLSConfig(pconn.t.TLSClientConfig)
1525 if cfg.ServerName == "" {
1526 cfg.ServerName = name
1527 }
1528 if pconn.cacheKey.onlyH1 {
1529 cfg.NextProtos = nil
1530 }
1531 plainConn := pconn.conn
1532 tlsConn := tls.Client(plainConn, cfg)
1533 errc := make(chan error, 2)
1534 var timer *time.Timer
1535 if d := pconn.t.TLSHandshakeTimeout; d != 0 {
1536 timer = time.AfterFunc(d, func() {
1537 errc <- tlsHandshakeTimeoutError{}
1538 })
1539 }
1540 go func() {
1541 if trace != nil && trace.TLSHandshakeStart != nil {
1542 trace.TLSHandshakeStart()
1543 }
1544 err := tlsConn.HandshakeContext(ctx)
1545 if timer != nil {
1546 timer.Stop()
1547 }
1548 errc <- err
1549 }()
1550 if err := <-errc; err != nil {
1551 plainConn.Close()
1552 if trace != nil && trace.TLSHandshakeDone != nil {
1553 trace.TLSHandshakeDone(tls.ConnectionState{}, err)
1554 }
1555 return err
1556 }
1557 cs := tlsConn.ConnectionState()
1558 if trace != nil && trace.TLSHandshakeDone != nil {
1559 trace.TLSHandshakeDone(cs, nil)
1560 }
1561 pconn.tlsState = &cs
1562 pconn.conn = tlsConn
1563 return nil
1564 }
1565
1566 type erringRoundTripper interface {
1567 RoundTripErr() error
1568 }
1569
1570 func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) {
1571 pconn = &persistConn{
1572 t: t,
1573 cacheKey: cm.key(),
1574 reqch: make(chan requestAndChan, 1),
1575 writech: make(chan writeRequest, 1),
1576 closech: make(chan struct{}),
1577 writeErrCh: make(chan error, 1),
1578 writeLoopDone: make(chan struct{}),
1579 }
1580 trace := httptrace.ContextClientTrace(ctx)
1581 wrapErr := func(err error) error {
1582 if cm.proxyURL != nil {
1583
1584 return &net.OpError{Op: "proxyconnect", Net: "tcp", Err: err}
1585 }
1586 return err
1587 }
1588 if cm.scheme() == "https" && t.hasCustomTLSDialer() {
1589 var err error
1590 pconn.conn, err = t.customDialTLS(ctx, "tcp", cm.addr())
1591 if err != nil {
1592 return nil, wrapErr(err)
1593 }
1594 if tc, ok := pconn.conn.(*tls.Conn); ok {
1595
1596
1597 if trace != nil && trace.TLSHandshakeStart != nil {
1598 trace.TLSHandshakeStart()
1599 }
1600 if err := tc.HandshakeContext(ctx); err != nil {
1601 go pconn.conn.Close()
1602 if trace != nil && trace.TLSHandshakeDone != nil {
1603 trace.TLSHandshakeDone(tls.ConnectionState{}, err)
1604 }
1605 return nil, err
1606 }
1607 cs := tc.ConnectionState()
1608 if trace != nil && trace.TLSHandshakeDone != nil {
1609 trace.TLSHandshakeDone(cs, nil)
1610 }
1611 pconn.tlsState = &cs
1612 }
1613 } else {
1614 conn, err := t.dial(ctx, "tcp", cm.addr())
1615 if err != nil {
1616 return nil, wrapErr(err)
1617 }
1618 pconn.conn = conn
1619 if cm.scheme() == "https" {
1620 var firstTLSHost string
1621 if firstTLSHost, _, err = net.SplitHostPort(cm.addr()); err != nil {
1622 return nil, wrapErr(err)
1623 }
1624 if err = pconn.addTLS(ctx, firstTLSHost, trace); err != nil {
1625 return nil, wrapErr(err)
1626 }
1627 }
1628 }
1629
1630
1631 switch {
1632 case cm.proxyURL == nil:
1633
1634 case cm.proxyURL.Scheme == "socks5":
1635 conn := pconn.conn
1636 d := socksNewDialer("tcp", conn.RemoteAddr().String())
1637 if u := cm.proxyURL.User; u != nil {
1638 auth := &socksUsernamePassword{
1639 Username: u.Username(),
1640 }
1641 auth.Password, _ = u.Password()
1642 d.AuthMethods = []socksAuthMethod{
1643 socksAuthMethodNotRequired,
1644 socksAuthMethodUsernamePassword,
1645 }
1646 d.Authenticate = auth.Authenticate
1647 }
1648 if _, err := d.DialWithConn(ctx, conn, "tcp", cm.targetAddr); err != nil {
1649 conn.Close()
1650 return nil, err
1651 }
1652 case cm.targetScheme == "http":
1653 pconn.isProxy = true
1654 if pa := cm.proxyAuth(); pa != "" {
1655 pconn.mutateHeaderFunc = func(h Header) {
1656 h.Set("Proxy-Authorization", pa)
1657 }
1658 }
1659 case cm.targetScheme == "https":
1660 conn := pconn.conn
1661 var hdr Header
1662 if t.GetProxyConnectHeader != nil {
1663 var err error
1664 hdr, err = t.GetProxyConnectHeader(ctx, cm.proxyURL, cm.targetAddr)
1665 if err != nil {
1666 conn.Close()
1667 return nil, err
1668 }
1669 } else {
1670 hdr = t.ProxyConnectHeader
1671 }
1672 if hdr == nil {
1673 hdr = make(Header)
1674 }
1675 if pa := cm.proxyAuth(); pa != "" {
1676 hdr = hdr.Clone()
1677 hdr.Set("Proxy-Authorization", pa)
1678 }
1679 connectReq := &Request{
1680 Method: "CONNECT",
1681 URL: &url.URL{Opaque: cm.targetAddr},
1682 Host: cm.targetAddr,
1683 Header: hdr,
1684 }
1685
1686
1687
1688
1689
1690
1691 connectCtx := ctx
1692 if ctx.Done() == nil {
1693 newCtx, cancel := context.WithTimeout(ctx, 1*time.Minute)
1694 defer cancel()
1695 connectCtx = newCtx
1696 }
1697
1698 didReadResponse := make(chan struct{})
1699 var (
1700 resp *Response
1701 err error
1702 )
1703
1704 go func() {
1705 defer close(didReadResponse)
1706 err = connectReq.Write(conn)
1707 if err != nil {
1708 return
1709 }
1710
1711
1712 br := bufio.NewReader(conn)
1713 resp, err = ReadResponse(br, connectReq)
1714 }()
1715 select {
1716 case <-connectCtx.Done():
1717 conn.Close()
1718 <-didReadResponse
1719 return nil, connectCtx.Err()
1720 case <-didReadResponse:
1721
1722 }
1723 if err != nil {
1724 conn.Close()
1725 return nil, err
1726 }
1727
1728 if t.OnProxyConnectResponse != nil {
1729 err = t.OnProxyConnectResponse(ctx, cm.proxyURL, connectReq, resp)
1730 if err != nil {
1731 return nil, err
1732 }
1733 }
1734
1735 if resp.StatusCode != 200 {
1736 _, text, ok := strings.Cut(resp.Status, " ")
1737 conn.Close()
1738 if !ok {
1739 return nil, errors.New("unknown status code")
1740 }
1741 return nil, errors.New(text)
1742 }
1743 }
1744
1745 if cm.proxyURL != nil && cm.targetScheme == "https" {
1746 if err := pconn.addTLS(ctx, cm.tlsHost(), trace); err != nil {
1747 return nil, err
1748 }
1749 }
1750
1751 if s := pconn.tlsState; s != nil && s.NegotiatedProtocolIsMutual && s.NegotiatedProtocol != "" {
1752 if next, ok := t.TLSNextProto[s.NegotiatedProtocol]; ok {
1753 alt := next(cm.targetAddr, pconn.conn.(*tls.Conn))
1754 if e, ok := alt.(erringRoundTripper); ok {
1755
1756 return nil, e.RoundTripErr()
1757 }
1758 return &persistConn{t: t, cacheKey: pconn.cacheKey, alt: alt}, nil
1759 }
1760 }
1761
1762 pconn.br = bufio.NewReaderSize(pconn, t.readBufferSize())
1763 pconn.bw = bufio.NewWriterSize(persistConnWriter{pconn}, t.writeBufferSize())
1764
1765 go pconn.readLoop()
1766 go pconn.writeLoop()
1767 return pconn, nil
1768 }
1769
1770
1771
1772
1773
1774
1775
1776 type persistConnWriter struct {
1777 pc *persistConn
1778 }
1779
1780 func (w persistConnWriter) Write(p []byte) (n int, err error) {
1781 n, err = w.pc.conn.Write(p)
1782 w.pc.nwrite += int64(n)
1783 return
1784 }
1785
1786
1787
1788
1789 func (w persistConnWriter) ReadFrom(r io.Reader) (n int64, err error) {
1790 n, err = io.Copy(w.pc.conn, r)
1791 w.pc.nwrite += n
1792 return
1793 }
1794
1795 var _ io.ReaderFrom = (*persistConnWriter)(nil)
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813 type connectMethod struct {
1814 _ incomparable
1815 proxyURL *url.URL
1816 targetScheme string
1817
1818
1819
1820 targetAddr string
1821 onlyH1 bool
1822 }
1823
1824 func (cm *connectMethod) key() connectMethodKey {
1825 proxyStr := ""
1826 targetAddr := cm.targetAddr
1827 if cm.proxyURL != nil {
1828 proxyStr = cm.proxyURL.String()
1829 if (cm.proxyURL.Scheme == "http" || cm.proxyURL.Scheme == "https") && cm.targetScheme == "http" {
1830 targetAddr = ""
1831 }
1832 }
1833 return connectMethodKey{
1834 proxy: proxyStr,
1835 scheme: cm.targetScheme,
1836 addr: targetAddr,
1837 onlyH1: cm.onlyH1,
1838 }
1839 }
1840
1841
1842 func (cm *connectMethod) scheme() string {
1843 if cm.proxyURL != nil {
1844 return cm.proxyURL.Scheme
1845 }
1846 return cm.targetScheme
1847 }
1848
1849
1850 func (cm *connectMethod) addr() string {
1851 if cm.proxyURL != nil {
1852 return canonicalAddr(cm.proxyURL)
1853 }
1854 return cm.targetAddr
1855 }
1856
1857
1858
1859 func (cm *connectMethod) tlsHost() string {
1860 h := cm.targetAddr
1861 if hasPort(h) {
1862 h = h[:strings.LastIndex(h, ":")]
1863 }
1864 return h
1865 }
1866
1867
1868
1869
1870 type connectMethodKey struct {
1871 proxy, scheme, addr string
1872 onlyH1 bool
1873 }
1874
1875 func (k connectMethodKey) String() string {
1876
1877 var h1 string
1878 if k.onlyH1 {
1879 h1 = ",h1"
1880 }
1881 return fmt.Sprintf("%s|%s%s|%s", k.proxy, k.scheme, h1, k.addr)
1882 }
1883
1884
1885
1886 type persistConn struct {
1887
1888
1889
1890 alt RoundTripper
1891
1892 t *Transport
1893 cacheKey connectMethodKey
1894 conn net.Conn
1895 tlsState *tls.ConnectionState
1896 br *bufio.Reader
1897 bw *bufio.Writer
1898 nwrite int64
1899 reqch chan requestAndChan
1900 writech chan writeRequest
1901 closech chan struct{}
1902 isProxy bool
1903 sawEOF bool
1904 readLimit int64
1905
1906
1907
1908
1909 writeErrCh chan error
1910
1911 writeLoopDone chan struct{}
1912
1913
1914 idleAt time.Time
1915 idleTimer *time.Timer
1916
1917 mu sync.Mutex
1918 numExpectedResponses int
1919 closed error
1920 canceledErr error
1921 broken bool
1922 reused bool
1923
1924
1925
1926 mutateHeaderFunc func(Header)
1927 }
1928
1929 func (pc *persistConn) maxHeaderResponseSize() int64 {
1930 if v := pc.t.MaxResponseHeaderBytes; v != 0 {
1931 return v
1932 }
1933 return 10 << 20
1934 }
1935
1936 func (pc *persistConn) Read(p []byte) (n int, err error) {
1937 if pc.readLimit <= 0 {
1938 return 0, fmt.Errorf("read limit of %d bytes exhausted", pc.maxHeaderResponseSize())
1939 }
1940 if int64(len(p)) > pc.readLimit {
1941 p = p[:pc.readLimit]
1942 }
1943 n, err = pc.conn.Read(p)
1944 if err == io.EOF {
1945 pc.sawEOF = true
1946 }
1947 pc.readLimit -= int64(n)
1948 return
1949 }
1950
1951
1952 func (pc *persistConn) isBroken() bool {
1953 pc.mu.Lock()
1954 b := pc.closed != nil
1955 pc.mu.Unlock()
1956 return b
1957 }
1958
1959
1960
1961 func (pc *persistConn) canceled() error {
1962 pc.mu.Lock()
1963 defer pc.mu.Unlock()
1964 return pc.canceledErr
1965 }
1966
1967
1968 func (pc *persistConn) isReused() bool {
1969 pc.mu.Lock()
1970 r := pc.reused
1971 pc.mu.Unlock()
1972 return r
1973 }
1974
1975 func (pc *persistConn) gotIdleConnTrace(idleAt time.Time) (t httptrace.GotConnInfo) {
1976 pc.mu.Lock()
1977 defer pc.mu.Unlock()
1978 t.Reused = pc.reused
1979 t.Conn = pc.conn
1980 t.WasIdle = true
1981 if !idleAt.IsZero() {
1982 t.IdleTime = time.Since(idleAt)
1983 }
1984 return
1985 }
1986
1987 func (pc *persistConn) cancelRequest(err error) {
1988 pc.mu.Lock()
1989 defer pc.mu.Unlock()
1990 pc.canceledErr = err
1991 pc.closeLocked(errRequestCanceled)
1992 }
1993
1994
1995
1996
1997 func (pc *persistConn) closeConnIfStillIdle() {
1998 t := pc.t
1999 t.idleMu.Lock()
2000 defer t.idleMu.Unlock()
2001 if _, ok := t.idleLRU.m[pc]; !ok {
2002
2003 return
2004 }
2005 t.removeIdleConnLocked(pc)
2006 pc.close(errIdleConnTimeout)
2007 }
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017 func (pc *persistConn) mapRoundTripError(req *transportRequest, startBytesWritten int64, err error) error {
2018 if err == nil {
2019 return nil
2020 }
2021
2022
2023
2024
2025
2026
2027
2028
2029 <-pc.writeLoopDone
2030
2031
2032
2033
2034 if cerr := pc.canceled(); cerr != nil {
2035 return cerr
2036 }
2037
2038
2039 req.mu.Lock()
2040 reqErr := req.err
2041 req.mu.Unlock()
2042 if reqErr != nil {
2043 return reqErr
2044 }
2045
2046 if err == errServerClosedIdle {
2047
2048 return err
2049 }
2050
2051 if _, ok := err.(transportReadFromServerError); ok {
2052 if pc.nwrite == startBytesWritten {
2053 return nothingWrittenError{err}
2054 }
2055
2056 return err
2057 }
2058 if pc.isBroken() {
2059 if pc.nwrite == startBytesWritten {
2060 return nothingWrittenError{err}
2061 }
2062 return fmt.Errorf("net/http: HTTP/1.x transport connection broken: %w", err)
2063 }
2064 return err
2065 }
2066
2067
2068
2069
2070 var errCallerOwnsConn = errors.New("read loop ending; caller owns writable underlying conn")
2071
2072 func (pc *persistConn) readLoop() {
2073 closeErr := errReadLoopExiting
2074 defer func() {
2075 pc.close(closeErr)
2076 pc.t.removeIdleConn(pc)
2077 }()
2078
2079 tryPutIdleConn := func(trace *httptrace.ClientTrace) bool {
2080 if err := pc.t.tryPutIdleConn(pc); err != nil {
2081 closeErr = err
2082 if trace != nil && trace.PutIdleConn != nil && err != errKeepAlivesDisabled {
2083 trace.PutIdleConn(err)
2084 }
2085 return false
2086 }
2087 if trace != nil && trace.PutIdleConn != nil {
2088 trace.PutIdleConn(nil)
2089 }
2090 return true
2091 }
2092
2093
2094
2095
2096 eofc := make(chan struct{})
2097 defer close(eofc)
2098
2099
2100 testHookMu.Lock()
2101 testHookReadLoopBeforeNextRead := testHookReadLoopBeforeNextRead
2102 testHookMu.Unlock()
2103
2104 alive := true
2105 for alive {
2106 pc.readLimit = pc.maxHeaderResponseSize()
2107 _, err := pc.br.Peek(1)
2108
2109 pc.mu.Lock()
2110 if pc.numExpectedResponses == 0 {
2111 pc.readLoopPeekFailLocked(err)
2112 pc.mu.Unlock()
2113 return
2114 }
2115 pc.mu.Unlock()
2116
2117 rc := <-pc.reqch
2118 trace := httptrace.ContextClientTrace(rc.req.Context())
2119
2120 var resp *Response
2121 if err == nil {
2122 resp, err = pc.readResponse(rc, trace)
2123 } else {
2124 err = transportReadFromServerError{err}
2125 closeErr = err
2126 }
2127
2128 if err != nil {
2129 if pc.readLimit <= 0 {
2130 err = fmt.Errorf("net/http: server response headers exceeded %d bytes; aborted", pc.maxHeaderResponseSize())
2131 }
2132
2133 select {
2134 case rc.ch <- responseAndError{err: err}:
2135 case <-rc.callerGone:
2136 return
2137 }
2138 return
2139 }
2140 pc.readLimit = maxInt64
2141
2142 pc.mu.Lock()
2143 pc.numExpectedResponses--
2144 pc.mu.Unlock()
2145
2146 bodyWritable := resp.bodyIsWritable()
2147 hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0
2148
2149 if resp.Close || rc.req.Close || resp.StatusCode <= 199 || bodyWritable {
2150
2151
2152
2153 alive = false
2154 }
2155
2156 if !hasBody || bodyWritable {
2157 replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil)
2158
2159
2160
2161
2162
2163
2164 alive = alive &&
2165 !pc.sawEOF &&
2166 pc.wroteRequest() &&
2167 replaced && tryPutIdleConn(trace)
2168
2169 if bodyWritable {
2170 closeErr = errCallerOwnsConn
2171 }
2172
2173 select {
2174 case rc.ch <- responseAndError{res: resp}:
2175 case <-rc.callerGone:
2176 return
2177 }
2178
2179
2180
2181
2182 testHookReadLoopBeforeNextRead()
2183 continue
2184 }
2185
2186 waitForBodyRead := make(chan bool, 2)
2187 body := &bodyEOFSignal{
2188 body: resp.Body,
2189 earlyCloseFn: func() error {
2190 waitForBodyRead <- false
2191 <-eofc
2192 return nil
2193
2194 },
2195 fn: func(err error) error {
2196 isEOF := err == io.EOF
2197 waitForBodyRead <- isEOF
2198 if isEOF {
2199 <-eofc
2200 } else if err != nil {
2201 if cerr := pc.canceled(); cerr != nil {
2202 return cerr
2203 }
2204 }
2205 return err
2206 },
2207 }
2208
2209 resp.Body = body
2210 if rc.addedGzip && ascii.EqualFold(resp.Header.Get("Content-Encoding"), "gzip") {
2211 resp.Body = &gzipReader{body: body}
2212 resp.Header.Del("Content-Encoding")
2213 resp.Header.Del("Content-Length")
2214 resp.ContentLength = -1
2215 resp.Uncompressed = true
2216 }
2217
2218 select {
2219 case rc.ch <- responseAndError{res: resp}:
2220 case <-rc.callerGone:
2221 return
2222 }
2223
2224
2225
2226
2227 select {
2228 case bodyEOF := <-waitForBodyRead:
2229 replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil)
2230 alive = alive &&
2231 bodyEOF &&
2232 !pc.sawEOF &&
2233 pc.wroteRequest() &&
2234 replaced && tryPutIdleConn(trace)
2235 if bodyEOF {
2236 eofc <- struct{}{}
2237 }
2238 case <-rc.req.Cancel:
2239 alive = false
2240 pc.t.CancelRequest(rc.req)
2241 case <-rc.req.Context().Done():
2242 alive = false
2243 pc.t.cancelRequest(rc.cancelKey, rc.req.Context().Err())
2244 case <-pc.closech:
2245 alive = false
2246 }
2247
2248 testHookReadLoopBeforeNextRead()
2249 }
2250 }
2251
2252 func (pc *persistConn) readLoopPeekFailLocked(peekErr error) {
2253 if pc.closed != nil {
2254 return
2255 }
2256 if n := pc.br.Buffered(); n > 0 {
2257 buf, _ := pc.br.Peek(n)
2258 if is408Message(buf) {
2259 pc.closeLocked(errServerClosedIdle)
2260 return
2261 } else {
2262 log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v", buf, peekErr)
2263 }
2264 }
2265 if peekErr == io.EOF {
2266
2267 pc.closeLocked(errServerClosedIdle)
2268 } else {
2269 pc.closeLocked(fmt.Errorf("readLoopPeekFailLocked: %w", peekErr))
2270 }
2271 }
2272
2273
2274
2275
2276 func is408Message(buf []byte) bool {
2277 if len(buf) < len("HTTP/1.x 408") {
2278 return false
2279 }
2280 if string(buf[:7]) != "HTTP/1." {
2281 return false
2282 }
2283 return string(buf[8:12]) == " 408"
2284 }
2285
2286
2287
2288
2289 func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTrace) (resp *Response, err error) {
2290 if trace != nil && trace.GotFirstResponseByte != nil {
2291 if peek, err := pc.br.Peek(1); err == nil && len(peek) == 1 {
2292 trace.GotFirstResponseByte()
2293 }
2294 }
2295 num1xx := 0
2296 const max1xxResponses = 5
2297
2298 continueCh := rc.continueCh
2299 for {
2300 resp, err = ReadResponse(pc.br, rc.req)
2301 if err != nil {
2302 return
2303 }
2304 resCode := resp.StatusCode
2305 if continueCh != nil {
2306 if resCode == 100 {
2307 if trace != nil && trace.Got100Continue != nil {
2308 trace.Got100Continue()
2309 }
2310 continueCh <- struct{}{}
2311 continueCh = nil
2312 } else if resCode >= 200 {
2313 close(continueCh)
2314 continueCh = nil
2315 }
2316 }
2317 is1xx := 100 <= resCode && resCode <= 199
2318
2319 is1xxNonTerminal := is1xx && resCode != StatusSwitchingProtocols
2320 if is1xxNonTerminal {
2321 num1xx++
2322 if num1xx > max1xxResponses {
2323 return nil, errors.New("net/http: too many 1xx informational responses")
2324 }
2325 pc.readLimit = pc.maxHeaderResponseSize()
2326 if trace != nil && trace.Got1xxResponse != nil {
2327 if err := trace.Got1xxResponse(resCode, textproto.MIMEHeader(resp.Header)); err != nil {
2328 return nil, err
2329 }
2330 }
2331 continue
2332 }
2333 break
2334 }
2335 if resp.isProtocolSwitch() {
2336 resp.Body = newReadWriteCloserBody(pc.br, pc.conn)
2337 }
2338
2339 resp.TLS = pc.tlsState
2340 return
2341 }
2342
2343
2344
2345
2346 func (pc *persistConn) waitForContinue(continueCh <-chan struct{}) func() bool {
2347 if continueCh == nil {
2348 return nil
2349 }
2350 return func() bool {
2351 timer := time.NewTimer(pc.t.ExpectContinueTimeout)
2352 defer timer.Stop()
2353
2354 select {
2355 case _, ok := <-continueCh:
2356 return ok
2357 case <-timer.C:
2358 return true
2359 case <-pc.closech:
2360 return false
2361 }
2362 }
2363 }
2364
2365 func newReadWriteCloserBody(br *bufio.Reader, rwc io.ReadWriteCloser) io.ReadWriteCloser {
2366 body := &readWriteCloserBody{ReadWriteCloser: rwc}
2367 if br.Buffered() != 0 {
2368 body.br = br
2369 }
2370 return body
2371 }
2372
2373
2374
2375
2376
2377
2378 type readWriteCloserBody struct {
2379 _ incomparable
2380 br *bufio.Reader
2381 io.ReadWriteCloser
2382 }
2383
2384 func (b *readWriteCloserBody) Read(p []byte) (n int, err error) {
2385 if b.br != nil {
2386 if n := b.br.Buffered(); len(p) > n {
2387 p = p[:n]
2388 }
2389 n, err = b.br.Read(p)
2390 if b.br.Buffered() == 0 {
2391 b.br = nil
2392 }
2393 return n, err
2394 }
2395 return b.ReadWriteCloser.Read(p)
2396 }
2397
2398
2399 type nothingWrittenError struct {
2400 error
2401 }
2402
2403 func (nwe nothingWrittenError) Unwrap() error {
2404 return nwe.error
2405 }
2406
2407 func (pc *persistConn) writeLoop() {
2408 defer close(pc.writeLoopDone)
2409 for {
2410 select {
2411 case wr := <-pc.writech:
2412 startBytesWritten := pc.nwrite
2413 err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh))
2414 if bre, ok := err.(requestBodyReadError); ok {
2415 err = bre.error
2416
2417
2418
2419
2420
2421
2422
2423 wr.req.setError(err)
2424 }
2425 if err == nil {
2426 err = pc.bw.Flush()
2427 }
2428 if err != nil {
2429 if pc.nwrite == startBytesWritten {
2430 err = nothingWrittenError{err}
2431 }
2432 }
2433 pc.writeErrCh <- err
2434 wr.ch <- err
2435 if err != nil {
2436 pc.close(err)
2437 return
2438 }
2439 case <-pc.closech:
2440 return
2441 }
2442 }
2443 }
2444
2445
2446
2447
2448 const maxWriteWaitBeforeConnReuse = 50 * time.Millisecond
2449
2450
2451
2452 func (pc *persistConn) wroteRequest() bool {
2453 select {
2454 case err := <-pc.writeErrCh:
2455
2456
2457 return err == nil
2458 default:
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469 t := time.NewTimer(maxWriteWaitBeforeConnReuse)
2470 defer t.Stop()
2471 select {
2472 case err := <-pc.writeErrCh:
2473 return err == nil
2474 case <-t.C:
2475 return false
2476 }
2477 }
2478 }
2479
2480
2481
2482 type responseAndError struct {
2483 _ incomparable
2484 res *Response
2485 err error
2486 }
2487
2488 type requestAndChan struct {
2489 _ incomparable
2490 req *Request
2491 cancelKey cancelKey
2492 ch chan responseAndError
2493
2494
2495
2496
2497 addedGzip bool
2498
2499
2500
2501
2502
2503 continueCh chan<- struct{}
2504
2505 callerGone <-chan struct{}
2506 }
2507
2508
2509
2510
2511
2512 type writeRequest struct {
2513 req *transportRequest
2514 ch chan<- error
2515
2516
2517
2518
2519 continueCh <-chan struct{}
2520 }
2521
2522 type httpError struct {
2523 err string
2524 timeout bool
2525 }
2526
2527 func (e *httpError) Error() string { return e.err }
2528 func (e *httpError) Timeout() bool { return e.timeout }
2529 func (e *httpError) Temporary() bool { return true }
2530
2531 var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
2532
2533
2534
2535 var errRequestCanceled = http2errRequestCanceled
2536 var errRequestCanceledConn = errors.New("net/http: request canceled while waiting for connection")
2537
2538 func nop() {}
2539
2540
2541 var (
2542 testHookEnterRoundTrip = nop
2543 testHookWaitResLoop = nop
2544 testHookRoundTripRetried = nop
2545 testHookPrePendingDial = nop
2546 testHookPostPendingDial = nop
2547
2548 testHookMu sync.Locker = fakeLocker{}
2549 testHookReadLoopBeforeNextRead = nop
2550 )
2551
2552 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
2553 testHookEnterRoundTrip()
2554 if !pc.t.replaceReqCanceler(req.cancelKey, pc.cancelRequest) {
2555 pc.t.putOrCloseIdleConn(pc)
2556 return nil, errRequestCanceled
2557 }
2558 pc.mu.Lock()
2559 pc.numExpectedResponses++
2560 headerFn := pc.mutateHeaderFunc
2561 pc.mu.Unlock()
2562
2563 if headerFn != nil {
2564 headerFn(req.extraHeaders())
2565 }
2566
2567
2568
2569
2570
2571 requestedGzip := false
2572 if !pc.t.DisableCompression &&
2573 req.Header.Get("Accept-Encoding") == "" &&
2574 req.Header.Get("Range") == "" &&
2575 req.Method != "HEAD" {
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588 requestedGzip = true
2589 req.extraHeaders().Set("Accept-Encoding", "gzip")
2590 }
2591
2592 var continueCh chan struct{}
2593 if req.ProtoAtLeast(1, 1) && req.Body != nil && req.expectsContinue() {
2594 continueCh = make(chan struct{}, 1)
2595 }
2596
2597 if pc.t.DisableKeepAlives &&
2598 !req.wantsClose() &&
2599 !isProtocolSwitchHeader(req.Header) {
2600 req.extraHeaders().Set("Connection", "close")
2601 }
2602
2603 gone := make(chan struct{})
2604 defer close(gone)
2605
2606 defer func() {
2607 if err != nil {
2608 pc.t.setReqCanceler(req.cancelKey, nil)
2609 }
2610 }()
2611
2612 const debugRoundTrip = false
2613
2614
2615
2616
2617 startBytesWritten := pc.nwrite
2618 writeErrCh := make(chan error, 1)
2619 pc.writech <- writeRequest{req, writeErrCh, continueCh}
2620
2621 resc := make(chan responseAndError)
2622 pc.reqch <- requestAndChan{
2623 req: req.Request,
2624 cancelKey: req.cancelKey,
2625 ch: resc,
2626 addedGzip: requestedGzip,
2627 continueCh: continueCh,
2628 callerGone: gone,
2629 }
2630
2631 var respHeaderTimer <-chan time.Time
2632 cancelChan := req.Request.Cancel
2633 ctxDoneChan := req.Context().Done()
2634 pcClosed := pc.closech
2635 canceled := false
2636 for {
2637 testHookWaitResLoop()
2638 select {
2639 case err := <-writeErrCh:
2640 if debugRoundTrip {
2641 req.logf("writeErrCh resv: %T/%#v", err, err)
2642 }
2643 if err != nil {
2644 pc.close(fmt.Errorf("write error: %w", err))
2645 return nil, pc.mapRoundTripError(req, startBytesWritten, err)
2646 }
2647 if d := pc.t.ResponseHeaderTimeout; d > 0 {
2648 if debugRoundTrip {
2649 req.logf("starting timer for %v", d)
2650 }
2651 timer := time.NewTimer(d)
2652 defer timer.Stop()
2653 respHeaderTimer = timer.C
2654 }
2655 case <-pcClosed:
2656 pcClosed = nil
2657 if canceled || pc.t.replaceReqCanceler(req.cancelKey, nil) {
2658 if debugRoundTrip {
2659 req.logf("closech recv: %T %#v", pc.closed, pc.closed)
2660 }
2661 return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed)
2662 }
2663 case <-respHeaderTimer:
2664 if debugRoundTrip {
2665 req.logf("timeout waiting for response headers.")
2666 }
2667 pc.close(errTimeout)
2668 return nil, errTimeout
2669 case re := <-resc:
2670 if (re.res == nil) == (re.err == nil) {
2671 panic(fmt.Sprintf("internal error: exactly one of res or err should be set; nil=%v", re.res == nil))
2672 }
2673 if debugRoundTrip {
2674 req.logf("resc recv: %p, %T/%#v", re.res, re.err, re.err)
2675 }
2676 if re.err != nil {
2677 return nil, pc.mapRoundTripError(req, startBytesWritten, re.err)
2678 }
2679 return re.res, nil
2680 case <-cancelChan:
2681 canceled = pc.t.cancelRequest(req.cancelKey, errRequestCanceled)
2682 cancelChan = nil
2683 case <-ctxDoneChan:
2684 canceled = pc.t.cancelRequest(req.cancelKey, req.Context().Err())
2685 cancelChan = nil
2686 ctxDoneChan = nil
2687 }
2688 }
2689 }
2690
2691
2692
2693 type tLogKey struct{}
2694
2695 func (tr *transportRequest) logf(format string, args ...any) {
2696 if logf, ok := tr.Request.Context().Value(tLogKey{}).(func(string, ...any)); ok {
2697 logf(time.Now().Format(time.RFC3339Nano)+": "+format, args...)
2698 }
2699 }
2700
2701
2702
2703 func (pc *persistConn) markReused() {
2704 pc.mu.Lock()
2705 pc.reused = true
2706 pc.mu.Unlock()
2707 }
2708
2709
2710
2711
2712
2713
2714 func (pc *persistConn) close(err error) {
2715 pc.mu.Lock()
2716 defer pc.mu.Unlock()
2717 pc.closeLocked(err)
2718 }
2719
2720 func (pc *persistConn) closeLocked(err error) {
2721 if err == nil {
2722 panic("nil error")
2723 }
2724 pc.broken = true
2725 if pc.closed == nil {
2726 pc.closed = err
2727 pc.t.decConnsPerHost(pc.cacheKey)
2728
2729
2730 if pc.alt == nil {
2731 if err != errCallerOwnsConn {
2732 pc.conn.Close()
2733 }
2734 close(pc.closech)
2735 }
2736 }
2737 pc.mutateHeaderFunc = nil
2738 }
2739
2740 var portMap = map[string]string{
2741 "http": "80",
2742 "https": "443",
2743 "socks5": "1080",
2744 }
2745
2746
2747 func canonicalAddr(url *url.URL) string {
2748 addr := url.Hostname()
2749 if v, err := idnaASCII(addr); err == nil {
2750 addr = v
2751 }
2752 port := url.Port()
2753 if port == "" {
2754 port = portMap[url.Scheme]
2755 }
2756 return net.JoinHostPort(addr, port)
2757 }
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770 type bodyEOFSignal struct {
2771 body io.ReadCloser
2772 mu sync.Mutex
2773 closed bool
2774 rerr error
2775 fn func(error) error
2776 earlyCloseFn func() error
2777 }
2778
2779 var errReadOnClosedResBody = errors.New("http: read on closed response body")
2780
2781 func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
2782 es.mu.Lock()
2783 closed, rerr := es.closed, es.rerr
2784 es.mu.Unlock()
2785 if closed {
2786 return 0, errReadOnClosedResBody
2787 }
2788 if rerr != nil {
2789 return 0, rerr
2790 }
2791
2792 n, err = es.body.Read(p)
2793 if err != nil {
2794 es.mu.Lock()
2795 defer es.mu.Unlock()
2796 if es.rerr == nil {
2797 es.rerr = err
2798 }
2799 err = es.condfn(err)
2800 }
2801 return
2802 }
2803
2804 func (es *bodyEOFSignal) Close() error {
2805 es.mu.Lock()
2806 defer es.mu.Unlock()
2807 if es.closed {
2808 return nil
2809 }
2810 es.closed = true
2811 if es.earlyCloseFn != nil && es.rerr != io.EOF {
2812 return es.earlyCloseFn()
2813 }
2814 err := es.body.Close()
2815 return es.condfn(err)
2816 }
2817
2818
2819 func (es *bodyEOFSignal) condfn(err error) error {
2820 if es.fn == nil {
2821 return err
2822 }
2823 err = es.fn(err)
2824 es.fn = nil
2825 return err
2826 }
2827
2828
2829
2830 type gzipReader struct {
2831 _ incomparable
2832 body *bodyEOFSignal
2833 zr *gzip.Reader
2834 zerr error
2835 }
2836
2837 func (gz *gzipReader) Read(p []byte) (n int, err error) {
2838 if gz.zr == nil {
2839 if gz.zerr == nil {
2840 gz.zr, gz.zerr = gzip.NewReader(gz.body)
2841 }
2842 if gz.zerr != nil {
2843 return 0, gz.zerr
2844 }
2845 }
2846
2847 gz.body.mu.Lock()
2848 if gz.body.closed {
2849 err = errReadOnClosedResBody
2850 }
2851 gz.body.mu.Unlock()
2852
2853 if err != nil {
2854 return 0, err
2855 }
2856 return gz.zr.Read(p)
2857 }
2858
2859 func (gz *gzipReader) Close() error {
2860 return gz.body.Close()
2861 }
2862
2863 type tlsHandshakeTimeoutError struct{}
2864
2865 func (tlsHandshakeTimeoutError) Timeout() bool { return true }
2866 func (tlsHandshakeTimeoutError) Temporary() bool { return true }
2867 func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" }
2868
2869
2870
2871
2872 type fakeLocker struct{}
2873
2874 func (fakeLocker) Lock() {}
2875 func (fakeLocker) Unlock() {}
2876
2877
2878
2879
2880 func cloneTLSConfig(cfg *tls.Config) *tls.Config {
2881 if cfg == nil {
2882 return &tls.Config{}
2883 }
2884 return cfg.Clone()
2885 }
2886
2887 type connLRU struct {
2888 ll *list.List
2889 m map[*persistConn]*list.Element
2890 }
2891
2892
2893 func (cl *connLRU) add(pc *persistConn) {
2894 if cl.ll == nil {
2895 cl.ll = list.New()
2896 cl.m = make(map[*persistConn]*list.Element)
2897 }
2898 ele := cl.ll.PushFront(pc)
2899 if _, ok := cl.m[pc]; ok {
2900 panic("persistConn was already in LRU")
2901 }
2902 cl.m[pc] = ele
2903 }
2904
2905 func (cl *connLRU) removeOldest() *persistConn {
2906 ele := cl.ll.Back()
2907 pc := ele.Value.(*persistConn)
2908 cl.ll.Remove(ele)
2909 delete(cl.m, pc)
2910 return pc
2911 }
2912
2913
2914 func (cl *connLRU) remove(pc *persistConn) {
2915 if ele, ok := cl.m[pc]; ok {
2916 cl.ll.Remove(ele)
2917 delete(cl.m, pc)
2918 }
2919 }
2920
2921
2922 func (cl *connLRU) len() int {
2923 return len(cl.m)
2924 }
2925
View as plain text