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.
5 // Bridge package to expose http internals to tests in the http_test
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
39 const MaxWriteWaitBeforeConnReuse = maxWriteWaitBeforeConnReuse
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)
47 testHookClientDoResult = func(res *Response, err error) {
49 if _, ok := err.(*url.Error); !ok {
50 panic(fmt.Sprintf("unexpected Client.Do error of type %T; want *url.Error", err))
54 panic("Client.Do returned nil, nil")
57 panic("Client.Do returned nil res.Body and no error")
63 func CondSkipHTTP2(t *testing.T) {
65 t.Skip("skipping HTTP/2 test when nethttpomithttp2 build tag in use")
70 SetEnterRoundTripHook = hookSetter(&testHookEnterRoundTrip)
71 SetRoundTripRetried = hookSetter(&testHookRoundTripRetried)
74 func SetReadLoopBeforeNextReadHook(f func()) {
76 defer testHookMu.Unlock()
78 testHookReadLoopBeforeNextRead = f
81 // SetPendingDialHooks sets the hooks that run before and after handling
83 func SetPendingDialHooks(before, after func()) {
84 unnilTestHook(&before)
86 testHookPrePendingDial, testHookPostPendingDial = before, after
89 func SetTestHookServerServe(fn func(*Server, net.Listener)) { testHookServerServe = fn }
91 func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
92 ctx, cancel := context.WithCancel(context.Background())
97 return &timeoutHandler{
104 func ResetCachedEnvironment() {
108 func (t *Transport) NumPendingRequestsForTesting() int {
110 defer t.reqMu.Unlock()
111 return len(t.reqCanceler)
114 func (t *Transport) IdleConnKeysForTesting() (keys []string) {
115 keys = make([]string, 0)
117 defer t.idleMu.Unlock()
118 for key := range t.idleConn {
119 keys = append(keys, key.String())
125 func (t *Transport) IdleConnKeyCountForTesting() int {
127 defer t.idleMu.Unlock()
128 return len(t.idleConn)
131 func (t *Transport) IdleConnStrsForTesting() []string {
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())
144 func (t *Transport) IdleConnStrsForTesting_h2() []string {
146 noDialPool := t.h2transport.(*http2Transport).ConnPool.(http2noDialClientConnPool)
147 pool := noDialPool.http2clientConnPool
150 defer pool.mu.Unlock()
152 for k, cc := range pool.conns {
162 func (t *Transport) IdleConnCountForTesting(scheme, addr string) int {
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 {
175 func (t *Transport) IdleConnWaitMapSizeForTesting() int {
177 defer t.idleMu.Unlock()
178 return len(t.idleConnWait)
181 func (t *Transport) IsIdleForTesting() bool {
183 defer t.idleMu.Unlock()
187 func (t *Transport) QueueForIdleConnForTesting() {
188 t.queueForIdleConn(nil)
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 {
195 key := connectMethodKey{"", scheme, addr, false}
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)
205 t.connsPerHost[key]++
206 t.connsPerHostMu.Unlock()
209 return t.tryPutIdleConn(&persistConn{
212 closech: make(chan struct{}), // so it can be closed
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}
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)
230 t.connsPerHost[key]++
231 t.connsPerHostMu.Unlock()
234 return t.tryPutIdleConn(&persistConn{
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()) {
249 func hookSetter(dst *func()) func(func()) {
250 return func(fn func()) {
256 func ExportHttp2ConfigureTransport(t *Transport) error {
257 t2, err := http2configureTransport(t)
265 func (s *Server) ExportAllConnsIdle() bool {
268 for c := range s.activeConn {
269 st, unixSec := c.getState()
270 if unixSec == 0 || st != StateIdle {
277 func (r *Request) WithT(t *testing.T) *Request {
278 return r.WithContext(context.WithValue(r.Context(), tLogKey{}, t.Logf))
281 func ExportSetH2GoawayTimeout(d time.Duration) (restore func()) {
282 old := http2goAwayTimeout
283 http2goAwayTimeout = d
284 return func() { http2goAwayTimeout = old }
287 func (r *Request) ExportIsReplayable() bool { return r.isReplayable() }
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
294 func ExportCloseTransportConnsAbruptly(tr *Transport) {
296 for _, pcs := range tr.idleConn {
297 for _, pc := range pcs {