| // Copyright 2011 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Bridge package to expose http internals to tests in the http_test |
| // package. |
| |
| package http |
| |
| import ( |
| "net" |
| "sort" |
| "sync" |
| "time" |
| ) |
| |
| var ( |
| DefaultUserAgent = defaultUserAgent |
| NewLoggingConn = newLoggingConn |
| ExportAppendTime = appendTime |
| ExportRefererForURL = refererForURL |
| ExportServerNewConn = (*Server).newConn |
| ExportCloseWriteAndWait = (*conn).closeWriteAndWait |
| ExportErrRequestCanceled = errRequestCanceled |
| ExportErrRequestCanceledConn = errRequestCanceledConn |
| ExportServeFile = serveFile |
| ExportHttp2ConfigureServer = http2ConfigureServer |
| ) |
| |
| func init() { |
| // We only want to pay for this cost during testing. |
| // When not under test, these values are always nil |
| // and never assigned to. |
| testHookMu = new(sync.Mutex) |
| } |
| |
| var ( |
| SetEnterRoundTripHook = hookSetter(&testHookEnterRoundTrip) |
| SetRoundTripRetried = hookSetter(&testHookRoundTripRetried) |
| ) |
| |
| func SetReadLoopBeforeNextReadHook(f func()) { |
| testHookMu.Lock() |
| defer testHookMu.Unlock() |
| unnilTestHook(&f) |
| testHookReadLoopBeforeNextRead = f |
| } |
| |
| // SetPendingDialHooks sets the hooks that run before and after handling |
| // pending dials. |
| func SetPendingDialHooks(before, after func()) { |
| unnilTestHook(&before) |
| unnilTestHook(&after) |
| testHookPrePendingDial, testHookPostPendingDial = before, after |
| } |
| |
| func SetTestHookServerServe(fn func(*Server, net.Listener)) { testHookServerServe = fn } |
| |
| func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { |
| return &timeoutHandler{ |
| handler: handler, |
| testTimeout: ch, |
| // (no body) |
| } |
| } |
| |
| func ResetCachedEnvironment() { |
| httpProxyEnv.reset() |
| httpsProxyEnv.reset() |
| noProxyEnv.reset() |
| } |
| |
| func (t *Transport) NumPendingRequestsForTesting() int { |
| t.reqMu.Lock() |
| defer t.reqMu.Unlock() |
| return len(t.reqCanceler) |
| } |
| |
| func (t *Transport) IdleConnKeysForTesting() (keys []string) { |
| keys = make([]string, 0) |
| t.idleMu.Lock() |
| defer t.idleMu.Unlock() |
| for key := range t.idleConn { |
| keys = append(keys, key.String()) |
| } |
| sort.Strings(keys) |
| return |
| } |
| |
| func (t *Transport) IdleConnStrsForTesting() []string { |
| var ret []string |
| t.idleMu.Lock() |
| defer t.idleMu.Unlock() |
| for _, conns := range t.idleConn { |
| for _, pc := range conns { |
| ret = append(ret, pc.conn.LocalAddr().String()+"/"+pc.conn.RemoteAddr().String()) |
| } |
| } |
| sort.Strings(ret) |
| return ret |
| } |
| |
| func (t *Transport) IdleConnCountForTesting(cacheKey string) int { |
| t.idleMu.Lock() |
| defer t.idleMu.Unlock() |
| for k, conns := range t.idleConn { |
| if k.String() == cacheKey { |
| return len(conns) |
| } |
| } |
| return 0 |
| } |
| |
| func (t *Transport) IdleConnChMapSizeForTesting() int { |
| t.idleMu.Lock() |
| defer t.idleMu.Unlock() |
| return len(t.idleConnCh) |
| } |
| |
| func (t *Transport) IsIdleForTesting() bool { |
| t.idleMu.Lock() |
| defer t.idleMu.Unlock() |
| return t.wantIdle |
| } |
| |
| func (t *Transport) RequestIdleConnChForTesting() { |
| t.getIdleConnCh(connectMethod{nil, "http", "example.com"}) |
| } |
| |
| func (t *Transport) PutIdleTestConn() bool { |
| c, _ := net.Pipe() |
| return t.tryPutIdleConn(&persistConn{ |
| t: t, |
| conn: c, // dummy |
| closech: make(chan struct{}), // so it can be closed |
| cacheKey: connectMethodKey{"", "http", "example.com"}, |
| }) == nil |
| } |
| |
| // All test hooks must be non-nil so they can be called directly, |
| // but the tests use nil to mean hook disabled. |
| func unnilTestHook(f *func()) { |
| if *f == nil { |
| *f = nop |
| } |
| } |
| |
| func hookSetter(dst *func()) func(func()) { |
| return func(fn func()) { |
| unnilTestHook(&fn) |
| *dst = fn |
| } |
| } |
| |
| func ExportHttp2ConfigureTransport(t *Transport) error { |
| t2, err := http2configureTransport(t) |
| if err != nil { |
| return err |
| } |
| t.h2transport = t2 |
| return nil |
| } |