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
, ctx context
.Context
) Handler
{
92 return &timeoutHandler
{
99 func ResetCachedEnvironment() {
103 func (t
*Transport
) NumPendingRequestsForTesting() int {
105 defer t
.reqMu
.Unlock()
106 return len(t
.reqCanceler
)
109 func (t
*Transport
) IdleConnKeysForTesting() (keys
[]string) {
110 keys
= make([]string, 0)
112 defer t
.idleMu
.Unlock()
113 for key
:= range t
.idleConn
{
114 keys
= append(keys
, key
.String())
120 func (t
*Transport
) IdleConnKeyCountForTesting() int {
122 defer t
.idleMu
.Unlock()
123 return len(t
.idleConn
)
126 func (t
*Transport
) IdleConnStrsForTesting() []string {
129 defer t
.idleMu
.Unlock()
130 for _
, conns
:= range t
.idleConn
{
131 for _
, pc
:= range conns
{
132 ret
= append(ret
, pc
.conn
.LocalAddr().String()+"/"+pc
.conn
.RemoteAddr().String())
139 func (t
*Transport
) IdleConnStrsForTesting_h2() []string {
141 noDialPool
:= t
.h2transport
.(*http2Transport
).ConnPool
.(http2noDialClientConnPool
)
142 pool
:= noDialPool
.http2clientConnPool
145 defer pool
.mu
.Unlock()
147 for k
, cc
:= range pool
.conns
{
157 func (t
*Transport
) IdleConnCountForTesting(scheme
, addr
string) int {
159 defer t
.idleMu
.Unlock()
160 key
:= connectMethodKey
{"", scheme
, addr
, false}
161 cacheKey
:= key
.String()
162 for k
, conns
:= range t
.idleConn
{
163 if k
.String() == cacheKey
{
170 func (t
*Transport
) IdleConnWaitMapSizeForTesting() int {
172 defer t
.idleMu
.Unlock()
173 return len(t
.idleConnWait
)
176 func (t
*Transport
) IsIdleForTesting() bool {
178 defer t
.idleMu
.Unlock()
182 func (t
*Transport
) QueueForIdleConnForTesting() {
183 t
.queueForIdleConn(nil)
186 // PutIdleTestConn reports whether it was able to insert a fresh
187 // persistConn for scheme, addr into the idle connection pool.
188 func (t
*Transport
) PutIdleTestConn(scheme
, addr
string) bool {
190 key
:= connectMethodKey
{"", scheme
, addr
, false}
192 if t
.MaxConnsPerHost
> 0 {
193 // Transport is tracking conns-per-host.
194 // Increment connection count to account
195 // for new persistConn created below.
196 t
.connsPerHostMu
.Lock()
197 if t
.connsPerHost
== nil {
198 t
.connsPerHost
= make(map[connectMethodKey
]int)
200 t
.connsPerHost
[key
]++
201 t
.connsPerHostMu
.Unlock()
204 return t
.tryPutIdleConn(&persistConn
{
207 closech
: make(chan struct{}), // so it can be closed
212 // PutIdleTestConnH2 reports whether it was able to insert a fresh
213 // HTTP/2 persistConn for scheme, addr into the idle connection pool.
214 func (t
*Transport
) PutIdleTestConnH2(scheme
, addr
string, alt RoundTripper
) bool {
215 key
:= connectMethodKey
{"", scheme
, addr
, false}
217 if t
.MaxConnsPerHost
> 0 {
218 // Transport is tracking conns-per-host.
219 // Increment connection count to account
220 // for new persistConn created below.
221 t
.connsPerHostMu
.Lock()
222 if t
.connsPerHost
== nil {
223 t
.connsPerHost
= make(map[connectMethodKey
]int)
225 t
.connsPerHost
[key
]++
226 t
.connsPerHostMu
.Unlock()
229 return t
.tryPutIdleConn(&persistConn
{
236 // All test hooks must be non-nil so they can be called directly,
237 // but the tests use nil to mean hook disabled.
238 func unnilTestHook(f
*func()) {
244 func hookSetter(dst
*func()) func(func()) {
245 return func(fn
func()) {
251 func ExportHttp2ConfigureTransport(t
*Transport
) error
{
252 t2
, err
:= http2configureTransports(t
)
260 func (s
*Server
) ExportAllConnsIdle() bool {
263 for c
:= range s
.activeConn
{
264 st
, unixSec
:= c
.getState()
265 if unixSec
== 0 || st
!= StateIdle
{
272 func (s
*Server
) ExportAllConnsByState() map[ConnState
]int {
273 states
:= map[ConnState
]int{}
276 for c
:= range s
.activeConn
{
277 st
, _
:= c
.getState()
283 func (r
*Request
) WithT(t
*testing
.T
) *Request
{
284 return r
.WithContext(context
.WithValue(r
.Context(), tLogKey
{}, t
.Logf
))
287 func ExportSetH2GoawayTimeout(d time
.Duration
) (restore
func()) {
288 old
:= http2goAwayTimeout
289 http2goAwayTimeout
= d
290 return func() { http2goAwayTimeout
= old
}
293 func (r
*Request
) ExportIsReplayable() bool { return r
.isReplayable() }
295 // ExportCloseTransportConnsAbruptly closes all idle connections from
296 // tr in an abrupt way, just reaching into the underlying Conns and
297 // closing them, without telling the Transport or its persistConns
298 // that it's doing so. This is to simulate the server closing connections
300 func ExportCloseTransportConnsAbruptly(tr
*Transport
) {
302 for _
, pcs
:= range tr
.idleConn
{
303 for _
, pc
:= range pcs
{