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