...

Source file src/net/http/export_test.go

Documentation: net/http

		 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 := http2configureTransports(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 (s *Server) ExportAllConnsByState() map[ConnState]int {
	 278  	states := map[ConnState]int{}
	 279  	s.mu.Lock()
	 280  	defer s.mu.Unlock()
	 281  	for c := range s.activeConn {
	 282  		st, _ := c.getState()
	 283  		states[st] += 1
	 284  	}
	 285  	return states
	 286  }
	 287  
	 288  func (r *Request) WithT(t *testing.T) *Request {
	 289  	return r.WithContext(context.WithValue(r.Context(), tLogKey{}, t.Logf))
	 290  }
	 291  
	 292  func ExportSetH2GoawayTimeout(d time.Duration) (restore func()) {
	 293  	old := http2goAwayTimeout
	 294  	http2goAwayTimeout = d
	 295  	return func() { http2goAwayTimeout = old }
	 296  }
	 297  
	 298  func (r *Request) ExportIsReplayable() bool { return r.isReplayable() }
	 299  
	 300  // ExportCloseTransportConnsAbruptly closes all idle connections from
	 301  // tr in an abrupt way, just reaching into the underlying Conns and
	 302  // closing them, without telling the Transport or its persistConns
	 303  // that it's doing so. This is to simulate the server closing connections
	 304  // on the Transport.
	 305  func ExportCloseTransportConnsAbruptly(tr *Transport) {
	 306  	tr.idleMu.Lock()
	 307  	for _, pcs := range tr.idleConn {
	 308  		for _, pc := range pcs {
	 309  			pc.conn.Close()
	 310  		}
	 311  	}
	 312  	tr.idleMu.Unlock()
	 313  }
	 314  

View as plain text