github.com/guyezi/gofrontend@v0.0.0-20200228202240-7a62a49e62c0/libgo/go/net/http/export_test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Bridge package to expose http internals to tests in the http_test 6 // package. 7 8 package http 9 10 import ( 11 "context" 12 "fmt" 13 "net" 14 "net/url" 15 "sort" 16 "sync" 17 "testing" 18 "time" 19 ) 20 21 var ( 22 DefaultUserAgent = defaultUserAgent 23 NewLoggingConn = newLoggingConn 24 ExportAppendTime = appendTime 25 ExportRefererForURL = refererForURL 26 ExportServerNewConn = (*Server).newConn 27 ExportCloseWriteAndWait = (*conn).closeWriteAndWait 28 ExportErrRequestCanceled = errRequestCanceled 29 ExportErrRequestCanceledConn = errRequestCanceledConn 30 ExportErrServerClosedIdle = errServerClosedIdle 31 ExportServeFile = serveFile 32 ExportScanETag = scanETag 33 ExportHttp2ConfigureServer = http2ConfigureServer 34 Export_shouldCopyHeaderOnRedirect = shouldCopyHeaderOnRedirect 35 Export_writeStatusLine = writeStatusLine 36 Export_is408Message = is408Message 37 ) 38 39 const MaxWriteWaitBeforeConnReuse = maxWriteWaitBeforeConnReuse 40 41 func init() { 42 // We only want to pay for this cost during testing. 43 // When not under test, these values are always nil 44 // and never assigned to. 45 testHookMu = new(sync.Mutex) 46 47 testHookClientDoResult = func(res *Response, err error) { 48 if err != nil { 49 if _, ok := err.(*url.Error); !ok { 50 panic(fmt.Sprintf("unexpected Client.Do error of type %T; want *url.Error", err)) 51 } 52 } else { 53 if res == nil { 54 panic("Client.Do returned nil, nil") 55 } 56 if res.Body == nil { 57 panic("Client.Do returned nil res.Body and no error") 58 } 59 } 60 } 61 } 62 63 func CondSkipHTTP2(t *testing.T) { 64 if omitBundledHTTP2 { 65 t.Skip("skipping HTTP/2 test when nethttpomithttp2 build tag in use") 66 } 67 } 68 69 var ( 70 SetEnterRoundTripHook = hookSetter(&testHookEnterRoundTrip) 71 SetRoundTripRetried = hookSetter(&testHookRoundTripRetried) 72 ) 73 74 func SetReadLoopBeforeNextReadHook(f func()) { 75 testHookMu.Lock() 76 defer testHookMu.Unlock() 77 unnilTestHook(&f) 78 testHookReadLoopBeforeNextRead = f 79 } 80 81 // SetPendingDialHooks sets the hooks that run before and after handling 82 // pending dials. 83 func SetPendingDialHooks(before, after func()) { 84 unnilTestHook(&before) 85 unnilTestHook(&after) 86 testHookPrePendingDial, testHookPostPendingDial = before, after 87 } 88 89 func SetTestHookServerServe(fn func(*Server, net.Listener)) { testHookServerServe = fn } 90 91 func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { 92 ctx, cancel := context.WithCancel(context.Background()) 93 go func() { 94 <-ch 95 cancel() 96 }() 97 return &timeoutHandler{ 98 handler: handler, 99 testContext: ctx, 100 // (no body) 101 } 102 } 103 104 func ResetCachedEnvironment() { 105 resetProxyConfig() 106 } 107 108 func (t *Transport) NumPendingRequestsForTesting() int { 109 t.reqMu.Lock() 110 defer t.reqMu.Unlock() 111 return len(t.reqCanceler) 112 } 113 114 func (t *Transport) IdleConnKeysForTesting() (keys []string) { 115 keys = make([]string, 0) 116 t.idleMu.Lock() 117 defer t.idleMu.Unlock() 118 for key := range t.idleConn { 119 keys = append(keys, key.String()) 120 } 121 sort.Strings(keys) 122 return 123 } 124 125 func (t *Transport) IdleConnKeyCountForTesting() int { 126 t.idleMu.Lock() 127 defer t.idleMu.Unlock() 128 return len(t.idleConn) 129 } 130 131 func (t *Transport) IdleConnStrsForTesting() []string { 132 var ret []string 133 t.idleMu.Lock() 134 defer t.idleMu.Unlock() 135 for _, conns := range t.idleConn { 136 for _, pc := range conns { 137 ret = append(ret, pc.conn.LocalAddr().String()+"/"+pc.conn.RemoteAddr().String()) 138 } 139 } 140 sort.Strings(ret) 141 return ret 142 } 143 144 func (t *Transport) IdleConnStrsForTesting_h2() []string { 145 var ret []string 146 noDialPool := t.h2transport.(*http2Transport).ConnPool.(http2noDialClientConnPool) 147 pool := noDialPool.http2clientConnPool 148 149 pool.mu.Lock() 150 defer pool.mu.Unlock() 151 152 for k, cc := range pool.conns { 153 for range cc { 154 ret = append(ret, k) 155 } 156 } 157 158 sort.Strings(ret) 159 return ret 160 } 161 162 func (t *Transport) IdleConnCountForTesting(scheme, addr string) int { 163 t.idleMu.Lock() 164 defer t.idleMu.Unlock() 165 key := connectMethodKey{"", scheme, addr, false} 166 cacheKey := key.String() 167 for k, conns := range t.idleConn { 168 if k.String() == cacheKey { 169 return len(conns) 170 } 171 } 172 return 0 173 } 174 175 func (t *Transport) IdleConnWaitMapSizeForTesting() int { 176 t.idleMu.Lock() 177 defer t.idleMu.Unlock() 178 return len(t.idleConnWait) 179 } 180 181 func (t *Transport) IsIdleForTesting() bool { 182 t.idleMu.Lock() 183 defer t.idleMu.Unlock() 184 return t.closeIdle 185 } 186 187 func (t *Transport) QueueForIdleConnForTesting() { 188 t.queueForIdleConn(nil) 189 } 190 191 // PutIdleTestConn reports whether it was able to insert a fresh 192 // persistConn for scheme, addr into the idle connection pool. 193 func (t *Transport) PutIdleTestConn(scheme, addr string) bool { 194 c, _ := net.Pipe() 195 key := connectMethodKey{"", scheme, addr, false} 196 197 if t.MaxConnsPerHost > 0 { 198 // Transport is tracking conns-per-host. 199 // Increment connection count to account 200 // for new persistConn created below. 201 t.connsPerHostMu.Lock() 202 if t.connsPerHost == nil { 203 t.connsPerHost = make(map[connectMethodKey]int) 204 } 205 t.connsPerHost[key]++ 206 t.connsPerHostMu.Unlock() 207 } 208 209 return t.tryPutIdleConn(&persistConn{ 210 t: t, 211 conn: c, // dummy 212 closech: make(chan struct{}), // so it can be closed 213 cacheKey: key, 214 }) == nil 215 } 216 217 // PutIdleTestConnH2 reports whether it was able to insert a fresh 218 // HTTP/2 persistConn for scheme, addr into the idle connection pool. 219 func (t *Transport) PutIdleTestConnH2(scheme, addr string, alt RoundTripper) bool { 220 key := connectMethodKey{"", scheme, addr, false} 221 222 if t.MaxConnsPerHost > 0 { 223 // Transport is tracking conns-per-host. 224 // Increment connection count to account 225 // for new persistConn created below. 226 t.connsPerHostMu.Lock() 227 if t.connsPerHost == nil { 228 t.connsPerHost = make(map[connectMethodKey]int) 229 } 230 t.connsPerHost[key]++ 231 t.connsPerHostMu.Unlock() 232 } 233 234 return t.tryPutIdleConn(&persistConn{ 235 t: t, 236 alt: alt, 237 cacheKey: key, 238 }) == nil 239 } 240 241 // All test hooks must be non-nil so they can be called directly, 242 // but the tests use nil to mean hook disabled. 243 func unnilTestHook(f *func()) { 244 if *f == nil { 245 *f = nop 246 } 247 } 248 249 func hookSetter(dst *func()) func(func()) { 250 return func(fn func()) { 251 unnilTestHook(&fn) 252 *dst = fn 253 } 254 } 255 256 func ExportHttp2ConfigureTransport(t *Transport) error { 257 t2, err := http2configureTransport(t) 258 if err != nil { 259 return err 260 } 261 t.h2transport = t2 262 return nil 263 } 264 265 func (s *Server) ExportAllConnsIdle() bool { 266 s.mu.Lock() 267 defer s.mu.Unlock() 268 for c := range s.activeConn { 269 st, unixSec := c.getState() 270 if unixSec == 0 || st != StateIdle { 271 return false 272 } 273 } 274 return true 275 } 276 277 func (r *Request) WithT(t *testing.T) *Request { 278 return r.WithContext(context.WithValue(r.Context(), tLogKey{}, t.Logf)) 279 } 280 281 func ExportSetH2GoawayTimeout(d time.Duration) (restore func()) { 282 old := http2goAwayTimeout 283 http2goAwayTimeout = d 284 return func() { http2goAwayTimeout = old } 285 } 286 287 func (r *Request) ExportIsReplayable() bool { return r.isReplayable() } 288 289 // ExportCloseTransportConnsAbruptly closes all idle connections from 290 // tr in an abrupt way, just reaching into the underlying Conns and 291 // closing them, without telling the Transport or its persistConns 292 // that it's doing so. This is to simulate the server closing connections 293 // on the Transport. 294 func ExportCloseTransportConnsAbruptly(tr *Transport) { 295 tr.idleMu.Lock() 296 for _, pcs := range tr.idleConn { 297 for _, pc := range pcs { 298 pc.conn.Close() 299 } 300 } 301 tr.idleMu.Unlock() 302 }