src/net/http/internal/http2/transport.go GO 3,363 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,363.
1// Copyright 2015 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45// Transport code.67package http289import (10	"bufio"11	"bytes"12	"compress/flate"13	"compress/gzip"14	"context"15	"crypto/rand"16	"crypto/tls"17	"errors"18	"fmt"19	"io"20	"io/fs"21	"log"22	"math"23	"math/bits"24	mathrand "math/rand"25	"net"26	"net/http/httptrace"27	"net/http/internal"28	"net/http/internal/httpcommon"29	"net/textproto"30	"slices"31	"strconv"32	"strings"33	"sync"34	"sync/atomic"35	"time"3637	"golang.org/x/net/http/httpguts"38	"golang.org/x/net/http2/hpack"39	"golang.org/x/net/idna"40)4142const (43	// transportDefaultConnFlow is how many connection-level flow control44	// tokens we give the server at start-up, past the default 64k.45	transportDefaultConnFlow = 1 << 304647	// transportDefaultStreamFlow is how many stream-level flow48	// control tokens we announce to the peer, and how many bytes49	// we buffer per stream.50	transportDefaultStreamFlow = 4 << 205152	defaultUserAgent = "Go-http-client/2.0"5354	// initialMaxConcurrentStreams is a connections maxConcurrentStreams until55	// it's received servers initial SETTINGS frame, which corresponds with the56	// spec's minimum recommended value.57	initialMaxConcurrentStreams = 1005859	// defaultMaxConcurrentStreams is a connections default maxConcurrentStreams60	// if the server doesn't include one in its initial SETTINGS frame.61	defaultMaxConcurrentStreams = 100062)6364// Transport is an HTTP/2 Transport.65//66// A Transport internally caches connections to servers. It is safe67// for concurrent use by multiple goroutines.68type Transport struct {69	t1       TransportConfig70	connPool noDialClientConnPool71	*transportTestHooks72}7374// Hook points used for testing.75// Outside of tests, t.transportTestHooks is nil and these all have minimal implementations.76// Inside tests, see the testSyncHooks function docs.7778type transportTestHooks struct {79	newclientconn func(*ClientConn)80}8182func (t *Transport) maxHeaderListSize() uint32 {83	n := t.t1.MaxHeaderListSize()84	if b := t.t1.MaxResponseHeaderBytes(); b != 0 {85		n = b86		if n > 0 {87			n = adjustHTTP1MaxHeaderSize(n)88		}89	}90	if n <= 0 {91		return 10 << 2092	}93	if n >= 0xffffffff {94		return 095	}96	return uint32(n)97}9899func (t *Transport) disableCompression() bool {100	return t.t1 != nil && t.t1.DisableCompression()101}102103func NewTransport(t1 TransportConfig) *Transport {104	connPool := new(clientConnPool)105	t2 := &Transport{106		connPool: noDialClientConnPool{connPool},107		t1:       t1,108	}109	connPool.t = t2110	return t2111}112113func (t *Transport) AddConn(scheme, authority string, c net.Conn) error {114	addr := authorityAddr(scheme, authority)115	used, err := t.connPool.addConnIfNeeded(addr, t, c)116	if !used {117		go c.Close()118	}119	return err120}121122// unencryptedTransport is a Transport with a RoundTrip method that123// always permits http:// URLs.124type unencryptedTransport Transport125126func (t *unencryptedTransport) RoundTrip(req *ClientRequest) (*ClientResponse, error) {127	return (*Transport)(t).RoundTripOpt(req, RoundTripOpt{})128}129130// ClientConn is the state of a single HTTP/2 client connection to an131// HTTP/2 server.132type ClientConn struct {133	t             *Transport134	tconn         net.Conn             // usually *tls.Conn, except specialized impls135	tlsState      *tls.ConnectionState // nil only for specialized impls136	atomicReused  uint32               // whether conn is being reused; atomic137	singleUse     bool                 // whether being used for a single http.Request138	getConnCalled bool                 // used by clientConnPool139140	// readLoop goroutine fields:141	readerDone chan struct{} // closed on error142	readerErr  error         // set before readerDone is closed143144	idleTimeout time.Duration // or 0 for never145	idleTimer   *time.Timer146147	mu               sync.Mutex // guards following148	cond             *sync.Cond // hold mu; broadcast on flow/closed changes149	flow             outflow    // our conn-level flow control quota (cs.outflow is per stream)150	inflow           inflow     // peer's conn-level flow control151	doNotReuse       bool       // whether conn is marked to not be reused for any future requests152	closing          bool153	closed           bool154	closedOnIdle     bool                     // true if conn was closed for idleness155	seenSettings     bool                     // true if we've seen a settings frame, false otherwise156	seenSettingsChan chan struct{}            // closed when seenSettings is true or frame reading fails157	wantSettingsAck  bool                     // we sent a SETTINGS frame and haven't heard back158	goAway           *GoAwayFrame             // if non-nil, the GoAwayFrame we received159	goAwayDebug      string                   // goAway frame's debug data, retained as a string160	streams          map[uint32]*clientStream // client-initiated161	streamsReserved  int                      // incr by ReserveNewRequest; decr on RoundTrip162	nextStreamID     uint32163	pendingRequests  int                       // requests blocked and waiting to be sent because len(streams) == maxConcurrentStreams164	pings            map[[8]byte]chan struct{} // in flight ping data to notification channel165	br               *bufio.Reader166	lastActive       time.Time167	lastIdle         time.Time // time last idle168	// Settings from peer: (also guarded by wmu)169	maxFrameSize                uint32170	maxConcurrentStreams        uint32171	peerMaxHeaderListSize       uint64172	peerMaxHeaderTableSize      uint32173	initialWindowSize           uint32174	initialStreamRecvWindowSize int32175	readIdleTimeout             time.Duration176	pingTimeout                 time.Duration177	extendedConnectAllowed      bool178	strictMaxConcurrentStreams  bool179180	// rstStreamPingsBlocked works around an unfortunate gRPC behavior.181	// gRPC strictly limits the number of PING frames that it will receive.182	// The default is two pings per two hours, but the limit resets every time183	// the gRPC endpoint sends a HEADERS or DATA frame. See golang/go#70575.184	//185	// rstStreamPingsBlocked is set after receiving a response to a PING frame186	// bundled with an RST_STREAM (see pendingResets below), and cleared after187	// receiving a HEADERS or DATA frame.188	rstStreamPingsBlocked bool189190	// pendingResets is the number of RST_STREAM frames we have sent to the peer,191	// without confirming that the peer has received them. When we send a RST_STREAM,192	// we bundle it with a PING frame, unless a PING is already in flight. We count193	// the reset stream against the connection's concurrency limit until we get194	// a PING response. This limits the number of requests we'll try to send to a195	// completely unresponsive connection.196	pendingResets int197198	// readBeforeStreamID is the smallest stream ID that has not been followed by199	// a frame read from the peer. We use this to determine when a request may200	// have been sent to a completely unresponsive connection:201	// If the request ID is less than readBeforeStreamID, then we have had some202	// indication of life on the connection since sending the request.203	readBeforeStreamID uint32204205	// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.206	// Write to reqHeaderMu to lock it, read from it to unlock.207	// Lock reqmu BEFORE mu or wmu.208	reqHeaderMu chan struct{}209210	// internalStateHook reports state changes back to the net/http.ClientConn.211	// Note that this is different from the user state hook registered by212	// net/http.ClientConn.SetStateHook: The internal hook calls ClientConn,213	// which calls the user hook.214	internalStateHook func()215216	// wmu is held while writing.217	// Acquire BEFORE mu when holding both, to avoid blocking mu on network writes.218	// Only acquire both at the same time when changing peer settings.219	wmu  sync.Mutex220	bw   *bufio.Writer221	fr   *Framer222	werr error        // first write error that has occurred223	hbuf bytes.Buffer // HPACK encoder writes into this224	henc *hpack.Encoder225}226227// clientStream is the state for a single HTTP/2 stream. One of these228// is created for each Transport.RoundTrip call.229type clientStream struct {230	cc *ClientConn231232	// Fields of Request that we may access even after the response body is closed.233	ctx       context.Context234	reqCancel <-chan struct{}235236	trace         *httptrace.ClientTrace // or nil237	ID            uint32238	bufPipe       pipe // buffered pipe with the flow-controlled response payload239	requestedGzip bool240	isHead        bool241242	abortOnce sync.Once243	abort     chan struct{} // closed to signal stream should end immediately244	abortErr  error         // set if abort is closed245246	peerClosed chan struct{} // closed when the peer sends an END_STREAM flag247	donec      chan struct{} // closed after the stream is in the closed state248	on100      chan struct{} // buffered; written to if a 100 is received249250	// detached, guarded by cc.mu, indicates that the writeRequest251	// goroutine has exited without waiting for the stream to end, and252	// that cleanupWriteRequest should instead be run (on a new goroutine)253	// by whichever of abortStreamLocked or clientConnReadLoop.endStream254	// ends the stream. It is cleared when that cleanup is scheduled.255	// See clientStream.detach.256	detached bool257258	// stopCtxWatch, if non-nil, cancels the context.AfterFunc watching259	// for request context cancellation on behalf of a detached stream.260	// It is set (under cc.mu) at most once, by detach, before detached261	// is set, and is called by cleanupWriteRequest.262	stopCtxWatch func() bool263264	// respHeaderTimeoutTimer, guarded by cc.mu, is a timer enforcing265	// Transport.ResponseHeaderTimeout on behalf of a detached stream.266	// It is armed by detach if response headers haven't yet arrived, and267	// stopped when they do (clientConnReadLoop.processHeaders) or when268	// the stream ends (cleanupWriteRequest).269	respHeaderTimeoutTimer *time.Timer270271	respHeaderRecv chan struct{}   // closed when headers are received272	res            *ClientResponse // set if respHeaderRecv is closed273274	flow        outflow // guarded by cc.mu275	inflow      inflow  // guarded by cc.mu276	bytesRemain int64   // -1 means unknown; owned by transportResponseBody.Read277	readErr     error   // sticky read error; owned by transportResponseBody.Read278279	reqBody              io.ReadCloser280	reqBodyContentLength int64         // -1 means unknown281	reqBodyClosed        chan struct{} // guarded by cc.mu; non-nil on Close, closed when done282283	// owned by writeRequest:284	sentEndStream bool // sent an END_STREAM flag to the peer285	sentHeaders   bool286287	// owned by clientConnReadLoop:288	firstByte       bool  // got the first response byte289	pastHeaders     bool  // got first MetaHeadersFrame (actual headers)290	pastTrailers    bool  // got optional second MetaHeadersFrame (trailers)291	readClosed      bool  // peer sent an END_STREAM flag292	readAborted     bool  // read loop reset the stream293	totalHeaderSize int64 // total size of 1xx headers seen294295	trailer    Header  // accumulated trailers296	resTrailer *Header // client's Response.Trailer297298	staticResp ClientResponse299}300301var got1xxFuncForTests func(int, textproto.MIMEHeader) error302303// get1xxTraceFunc returns the value of request's httptrace.ClientTrace.Got1xxResponse func,304// if any. It returns nil if not set or if the Go version is too old.305func (cs *clientStream) get1xxTraceFunc() func(int, textproto.MIMEHeader) error {306	if fn := got1xxFuncForTests; fn != nil {307		return fn308	}309	return traceGot1xxResponseFunc(cs.trace)310}311312func (cs *clientStream) abortStream(err error) {313	cs.cc.mu.Lock()314	defer cs.cc.mu.Unlock()315	cs.abortStreamLocked(err)316}317318func (cs *clientStream) abortStreamLocked(err error) {319	cs.abortOnce.Do(func() {320		cs.abortErr = err321		close(cs.abort)322	})323	if cs.detached {324		cs.detached = false325		go cs.cleanupWriteRequest(cs.abortErr)326	}327	if cs.reqBody != nil {328		cs.closeReqBodyLocked()329	}330	// TODO(dneil): Clean up tests where cs.cc.cond is nil.331	if cs.cc.cond != nil {332		// Wake up writeRequestBody if it is waiting on flow control.333		cs.cc.cond.Broadcast()334	}335}336337func (cs *clientStream) abortRequestBodyWrite() {338	cc := cs.cc339	cc.mu.Lock()340	defer cc.mu.Unlock()341	if cs.reqBody != nil && cs.reqBodyClosed == nil {342		cs.closeReqBodyLocked()343		cc.cond.Broadcast()344	}345}346347func (cs *clientStream) closeReqBodyLocked() {348	if cs.reqBodyClosed != nil {349		return350	}351	cs.reqBodyClosed = make(chan struct{})352	reqBodyClosed := cs.reqBodyClosed353	go func() {354		cs.reqBody.Close()355		close(reqBodyClosed)356	}()357}358359type stickyErrWriter struct {360	conn    net.Conn361	timeout time.Duration362	err     *error363}364365func (sew stickyErrWriter) Write(p []byte) (n int, err error) {366	if *sew.err != nil {367		return 0, *sew.err368	}369	n, err = writeWithByteTimeout(sew.conn, sew.timeout, p)370	*sew.err = err371	return n, err372}373374// noCachedConnError is the concrete type of ErrNoCachedConn, which375// needs to be detected by net/http regardless of whether it's its376// bundled version (in h2_bundle.go with a rewritten type name) or377// from a user's x/net/http2. As such, as it has a unique method name378// (IsHTTP2NoCachedConnError) that net/http sniffs for via func379// isNoCachedConnError.380type noCachedConnError struct{}381382func (noCachedConnError) IsHTTP2NoCachedConnError() {}383func (noCachedConnError) Error() string             { return "http2: no cached connection was available" }384385// isNoCachedConnError reports whether err is of type noCachedConnError386// or its equivalent renamed type in net/http2's h2_bundle.go. Both types387// may coexist in the same running program.388func isNoCachedConnError(err error) bool {389	_, ok := err.(interface{ IsHTTP2NoCachedConnError() })390	return ok391}392393var ErrNoCachedConn error = noCachedConnError{}394395// RoundTripOpt are options for the Transport.RoundTripOpt method.396type RoundTripOpt struct {397	// OnlyCachedConn controls whether RoundTripOpt may398	// create a new TCP connection. If set true and399	// no cached connection is available, RoundTripOpt400	// will return ErrNoCachedConn.401	OnlyCachedConn bool402}403404func (t *Transport) RoundTrip(req *ClientRequest) (*ClientResponse, error) {405	return t.RoundTripOpt(req, RoundTripOpt{})406}407408// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)409// and returns a host:port. The port 443 is added if needed.410func authorityAddr(scheme string, authority string) (addr string) {411	host, port, err := net.SplitHostPort(authority)412	if err != nil { // authority didn't have a port413		host = authority414		port = ""415	}416	if port == "" { // authority's port was empty417		port = "443"418		if scheme == "http" {419			port = "80"420		}421	}422	if a, err := idna.ToASCII(host); err == nil {423		host = a424	}425	// IPv6 address literal, without a port:426	if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {427		return host + ":" + port428	}429	return net.JoinHostPort(host, port)430}431432// RoundTripOpt is like RoundTrip, but takes options.433func (t *Transport) RoundTripOpt(req *ClientRequest, opt RoundTripOpt) (*ClientResponse, error) {434	switch req.URL.Scheme {435	case "https":436	case "http":437	default:438		return nil, errors.New("http2: unsupported scheme")439	}440441	addr := authorityAddr(req.URL.Scheme, req.URL.Host)442	for retry := 0; ; retry++ {443		cc, err := t.connPool.GetClientConn(req, addr)444		if err != nil {445			t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err)446			return nil, err447		}448		reused := !atomic.CompareAndSwapUint32(&cc.atomicReused, 0, 1)449		traceGotConn(req, cc, reused)450		res, err := cc.RoundTrip(req)451		if err != nil && retry <= 6 {452			roundTripErr := err453			if req, err = shouldRetryRequest(req, err); err == nil {454				// After the first retry, do exponential backoff with 10% jitter.455				if retry == 0 {456					t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)457					continue458				}459				backoff := float64(uint(1) << (uint(retry) - 1))460				backoff += backoff * (0.1 * mathrand.Float64())461				d := time.Second * time.Duration(backoff)462				tm := time.NewTimer(d)463				select {464				case <-tm.C:465					t.vlogf("RoundTrip retrying after failure: %v", roundTripErr)466					continue467				case <-req.Context.Done():468					tm.Stop()469					err = req.Context.Err()470				}471			}472		}473		if err == errClientConnNotEstablished {474			// This ClientConn was created recently,475			// this is the first request to use it,476			// and the connection is closed and not usable.477			//478			// In this state, cc.idleTimer will remove the conn from the pool479			// when it fires. Stop the timer and remove it here so future requests480			// won't try to use this connection.481			//482			// If the timer has already fired and we're racing it, the redundant483			// call to MarkDead is harmless.484			if cc.idleTimer != nil {485				cc.idleTimer.Stop()486			}487			t.connPool.MarkDead(cc)488		}489		if err != nil {490			t.vlogf("RoundTrip failure: %v", err)491			return nil, err492		}493		return res, nil494	}495}496497func (t *Transport) IdleConnStrsForTesting() []string {498	var ret []string499	t.connPool.mu.Lock()500	defer t.connPool.mu.Unlock()501	for k, ccs := range t.connPool.conns {502		for _, cc := range ccs {503			if cc.idleState().canTakeNewRequest {504				ret = append(ret, k)505			}506		}507	}508	slices.Sort(ret)509	return ret510}511512// CloseIdleConnections closes any connections which were previously513// connected from previous requests but are now sitting idle.514// It does not interrupt any connections currently in use.515func (t *Transport) CloseIdleConnections() {516	t.connPool.closeIdleConnections()517}518519var (520	errClientConnClosed         = errors.New("http2: client conn is closed")521	errClientConnUnusable       = errors.New("http2: client conn not usable")522	errClientConnNotEstablished = errors.New("http2: client conn could not be established")523	errClientConnGotGoAway      = errors.New("http2: Transport received Server's graceful shutdown GOAWAY")524	errClientConnForceClosed    = errors.New("http2: client connection force closed via ClientConn.Close")525)526527// shouldRetryRequest is called by RoundTrip when a request fails to get528// response headers. It is always called with a non-nil error.529// It returns either a request to retry or an error if the request can't be replayed.530// If the request is retried, it always clones the request (since requests531// contain an unreusable clientStream).532func shouldRetryRequest(req *ClientRequest, err error) (*ClientRequest, error) {533	if !canRetryError(err) {534		return nil, err535	}536	// If the Body is nil (or http.NoBody), it's safe to reuse this request's Body.537	if req.Body == nil || req.Body == NoBody {538		return req.Clone(), nil539	}540541	// If the request body can be reset back to its original542	// state via the optional req.GetBody, do that.543	if req.GetBody != nil {544		body, err := req.GetBody()545		if err != nil {546			return nil, err547		}548		newReq := req.Clone()549		newReq.Body = body550		return newReq, nil551	}552553	// The Request.Body can't reset back to the beginning, but we554	// don't seem to have started to read from it yet, so reuse the body.555	if err == errClientConnUnusable {556		return req.Clone(), nil557	}558559	return nil, fmt.Errorf("http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error", err)560}561562func canRetryError(err error) bool {563	if err == errClientConnUnusable || err == errClientConnGotGoAway {564		return true565	}566	if se, ok := err.(StreamError); ok {567		return se.Code == ErrCodeRefusedStream568	}569	return false570}571572func (t *Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*ClientConn, error) {573	if t.transportTestHooks != nil {574		return t.newClientConn(nil, singleUse, nil)575	}576	host, _, err := net.SplitHostPort(addr)577	if err != nil {578		return nil, err579	}580	tconn, err := t.dialTLS(ctx, "tcp", addr, t.newTLSConfig(host))581	if err != nil {582		return nil, err583	}584	return t.newClientConn(tconn, singleUse, nil)585}586587func (t *Transport) newTLSConfig(host string) *tls.Config {588	cfg := new(tls.Config)589	if !slices.Contains(cfg.NextProtos, NextProtoTLS) {590		cfg.NextProtos = append([]string{NextProtoTLS}, cfg.NextProtos...)591	}592	if cfg.ServerName == "" {593		cfg.ServerName = host594	}595	return cfg596}597598func (t *Transport) dialTLS(ctx context.Context, network, addr string, tlsCfg *tls.Config) (net.Conn, error) {599	tlsCn, err := t.dialTLSWithContext(ctx, network, addr, tlsCfg)600	if err != nil {601		return nil, err602	}603	state := tlsCn.ConnectionState()604	if p := state.NegotiatedProtocol; p != NextProtoTLS {605		return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", p, NextProtoTLS)606	}607	if !state.NegotiatedProtocolIsMutual {608		return nil, errors.New("http2: could not negotiate protocol mutually")609	}610	return tlsCn, nil611}612613// disableKeepAlives reports whether connections should be closed as614// soon as possible after handling the first request.615func (t *Transport) disableKeepAlives() bool {616	return t.t1 != nil && t.t1.DisableKeepAlives()617}618619func (t *Transport) expectContinueTimeout() time.Duration {620	if t.t1 == nil {621		return 0622	}623	return t.t1.ExpectContinueTimeout()624}625626func (t *Transport) NewClientConn(c net.Conn, internalStateHook func()) (NetHTTPClientConn, error) {627	cc, err := t.newClientConn(c, t.disableKeepAlives(), internalStateHook)628	if err != nil {629		return NetHTTPClientConn{}, err630	}631632	// RoundTrip should block when the conn is at its concurrency limit,633	// not return an error. Setting strictMaxConcurrentStreams enables this.634	cc.strictMaxConcurrentStreams = true635636	return NetHTTPClientConn{cc}, nil637}638639func (t *Transport) newClientConn(c net.Conn, singleUse bool, internalStateHook func()) (*ClientConn, error) {640	conf := configFromTransport(t)641	cc := &ClientConn{642		t:                           t,643		tconn:                       c,644		readerDone:                  make(chan struct{}),645		nextStreamID:                1,646		maxFrameSize:                16 << 10, // spec default647		initialWindowSize:           65535,    // spec default648		initialStreamRecvWindowSize: int32(conf.MaxReceiveBufferPerStream),649		maxConcurrentStreams:        initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings.650		strictMaxConcurrentStreams:  conf.StrictMaxConcurrentRequests,651		peerMaxHeaderListSize:       0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead.652		streams:                     make(map[uint32]*clientStream),653		singleUse:                   singleUse,654		seenSettingsChan:            make(chan struct{}),655		wantSettingsAck:             true,656		readIdleTimeout:             conf.SendPingTimeout,657		pingTimeout:                 conf.PingTimeout,658		pings:                       make(map[[8]byte]chan struct{}),659		reqHeaderMu:                 make(chan struct{}, 1),660		lastActive:                  time.Now(),661		internalStateHook:           internalStateHook,662	}663	if t.transportTestHooks != nil {664		t.transportTestHooks.newclientconn(cc)665		c = cc.tconn666	}667	if VerboseLogs {668		t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())669	}670671	cc.cond = sync.NewCond(&cc.mu)672	cc.flow.add(int32(initialWindowSize))673674	// TODO: adjust this writer size to account for frame size +675	// MTU + crypto/tls record padding.676	cc.bw = bufio.NewWriter(stickyErrWriter{677		conn:    c,678		timeout: conf.WriteByteTimeout,679		err:     &cc.werr,680	})681	cc.br = bufio.NewReader(c)682	cc.fr = NewFramer(cc.bw, cc.br)683	cc.fr.SetMaxReadFrameSize(uint32(conf.MaxReadFrameSize))684	if conf.CountError != nil {685		cc.fr.countError = conf.CountError686	}687	maxHeaderTableSize := uint32(conf.MaxDecoderHeaderTableSize)688	cc.fr.ReadMetaHeaders = hpack.NewDecoder(maxHeaderTableSize, nil)689	cc.fr.MaxHeaderListSize = t.maxHeaderListSize()690691	cc.henc = hpack.NewEncoder(&cc.hbuf)692	cc.henc.SetMaxDynamicTableSizeLimit(uint32(conf.MaxEncoderHeaderTableSize))693	cc.peerMaxHeaderTableSize = initialHeaderTableSize694695	if cs, ok := c.(connectionStater); ok {696		state := cs.ConnectionState()697		cc.tlsState = &state698	}699700	initialSettings := []Setting{701		{ID: SettingEnablePush, Val: 0},702		{ID: SettingInitialWindowSize, Val: uint32(cc.initialStreamRecvWindowSize)},703	}704	initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: uint32(conf.MaxReadFrameSize)})705	if max := t.maxHeaderListSize(); max != 0 {706		initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max})707	}708	if maxHeaderTableSize != initialHeaderTableSize {709		initialSettings = append(initialSettings, Setting{ID: SettingHeaderTableSize, Val: maxHeaderTableSize})710	}711712	cc.bw.Write(clientPreface)713	cc.fr.WriteSettings(initialSettings...)714	cc.fr.WriteWindowUpdate(0, uint32(conf.MaxReceiveBufferPerConnection))715	cc.inflow.init(int32(conf.MaxReceiveBufferPerConnection) + initialWindowSize)716	cc.bw.Flush()717	if cc.werr != nil {718		cc.Close()719		return nil, cc.werr720	}721722	// Start the idle timer after the connection is fully initialized.723	if d := t.idleConnTimeout(); d != 0 {724		cc.idleTimeout = d725		cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout)726	}727728	go cc.readLoop()729	return cc, nil730}731732func (cc *ClientConn) healthCheck() {733	pingTimeout := cc.pingTimeout734	// We don't need to periodically ping in the health check, because the readLoop of ClientConn will735	// trigger the healthCheck again if there is no frame received.736	ctx, cancel := context.WithTimeout(context.Background(), pingTimeout)737	defer cancel()738	cc.vlogf("http2: Transport sending health check")739	err := cc.Ping(ctx)740	if err != nil {741		cc.vlogf("http2: Transport health check failure: %v", err)742		cc.closeForLostPing()743	} else {744		cc.vlogf("http2: Transport health check success")745	}746}747748// SetDoNotReuse marks cc as not reusable for future HTTP requests.749func (cc *ClientConn) SetDoNotReuse() {750	cc.mu.Lock()751	defer cc.mu.Unlock()752	cc.doNotReuse = true753}754755// CanTakeNewRequest reports whether the connection can take a new request,756// meaning it has not been closed or received or sent a GOAWAY.757//758// If the caller is going to immediately make a new request on this759// connection, use ReserveNewRequest instead.760func (cc *ClientConn) CanTakeNewRequest() bool {761	cc.mu.Lock()762	defer cc.mu.Unlock()763	return cc.canTakeNewRequestLocked()764}765766// ReserveNewRequest is like CanTakeNewRequest but also reserves a767// concurrent stream in cc. The reservation is decremented on the768// next call to RoundTrip.769func (cc *ClientConn) ReserveNewRequest() bool {770	cc.mu.Lock()771	defer cc.mu.Unlock()772	if st := cc.idleStateLocked(); !st.canTakeNewRequest {773		return false774	}775	cc.streamsReserved++776	return true777}778779// ClientConnState describes the state of a ClientConn.780type ClientConnState struct {781	// Closed is whether the connection is closed.782	Closed bool783784	// Closing is whether the connection is in the process of785	// closing. It may be closing due to shutdown, being a786	// single-use connection, being marked as DoNotReuse, or787	// having received a GOAWAY frame.788	Closing bool789790	// StreamsActive is how many streams are active.791	StreamsActive int792793	// StreamsReserved is how many streams have been reserved via794	// ClientConn.ReserveNewRequest.795	StreamsReserved int796797	// StreamsPending is how many requests have been sent in excess798	// of the peer's advertised MaxConcurrentStreams setting and799	// are waiting for other streams to complete.800	StreamsPending int801802	// MaxConcurrentStreams is how many concurrent streams the803	// peer advertised as acceptable. Zero means no SETTINGS804	// frame has been received yet.805	MaxConcurrentStreams uint32806807	// LastIdle, if non-zero, is when the connection last808	// transitioned to idle state.809	LastIdle time.Time810}811812// State returns a snapshot of cc's state.813func (cc *ClientConn) State() ClientConnState {814	cc.wmu.Lock()815	maxConcurrent := cc.maxConcurrentStreams816	if !cc.seenSettings {817		maxConcurrent = 0818	}819	cc.wmu.Unlock()820821	cc.mu.Lock()822	defer cc.mu.Unlock()823	return ClientConnState{824		Closed:               cc.closed,825		Closing:              cc.closing || cc.singleUse || cc.doNotReuse || cc.goAway != nil,826		StreamsActive:        len(cc.streams) + cc.pendingResets,827		StreamsReserved:      cc.streamsReserved,828		StreamsPending:       cc.pendingRequests,829		LastIdle:             cc.lastIdle,830		MaxConcurrentStreams: maxConcurrent,831	}832}833834// clientConnIdleState describes the suitability of a client835// connection to initiate a new RoundTrip request.836type clientConnIdleState struct {837	canTakeNewRequest bool838}839840func (cc *ClientConn) idleState() clientConnIdleState {841	cc.mu.Lock()842	defer cc.mu.Unlock()843	return cc.idleStateLocked()844}845846func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) {847	if cc.singleUse && cc.nextStreamID > 1 {848		return849	}850	var maxConcurrentOkay bool851	if cc.strictMaxConcurrentStreams {852		// We'll tell the caller we can take a new request to853		// prevent the caller from dialing a new TCP854		// connection, but then we'll block later before855		// writing it.856		maxConcurrentOkay = true857	} else {858		// We can take a new request if the total of859		//   - active streams;860		//   - reservation slots for new streams; and861		//   - streams for which we have sent a RST_STREAM and a PING,862		//     but received no subsequent frame863		// is less than the concurrency limit.864		maxConcurrentOkay = cc.currentRequestCountLocked() < int(cc.maxConcurrentStreams)865	}866867	st.canTakeNewRequest = maxConcurrentOkay && cc.isUsableLocked()868869	// If this connection has never been used for a request and is closed,870	// then let it take a request (which will fail).871	// If the conn was closed for idleness, we're racing the idle timer;872	// don't try to use the conn. (Issue #70515.)873	//874	// This avoids a situation where an error early in a connection's lifetime875	// goes unreported.876	if cc.nextStreamID == 1 && cc.streamsReserved == 0 && cc.closed && !cc.closedOnIdle {877		st.canTakeNewRequest = true878	}879880	return881}882883func (cc *ClientConn) isUsableLocked() bool {884	return cc.goAway == nil &&885		!cc.closed &&886		!cc.closing &&887		!cc.doNotReuse &&888		int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 &&889		!cc.tooIdleLocked()890}891892// canReserveLocked reports whether a net/http.ClientConn can reserve a slot on this conn.893//894// This follows slightly different rules than clientConnIdleState.canTakeNewRequest.895// We only permit reservations up to the conn's concurrency limit.896// This differs from ClientConn.ReserveNewRequest, which permits reservations897// past the limit when StrictMaxConcurrentStreams is set.898func (cc *ClientConn) canReserveLocked() bool {899	if cc.currentRequestCountLocked() >= int(cc.maxConcurrentStreams) {900		return false901	}902	if !cc.isUsableLocked() {903		return false904	}905	return true906}907908// currentRequestCountLocked reports the number of concurrency slots currently in use,909// including active streams, reserved slots, and reset streams waiting for acknowledgement.910func (cc *ClientConn) currentRequestCountLocked() int {911	return len(cc.streams) + cc.streamsReserved + cc.pendingResets912}913914func (cc *ClientConn) canTakeNewRequestLocked() bool {915	st := cc.idleStateLocked()916	return st.canTakeNewRequest917}918919// availableLocked reports the number of concurrency slots available.920func (cc *ClientConn) availableLocked() int {921	if !cc.canTakeNewRequestLocked() {922		return 0923	}924	return max(0, int(cc.maxConcurrentStreams)-cc.currentRequestCountLocked())925}926927// tooIdleLocked reports whether this connection has been been sitting idle928// for too much wall time.929func (cc *ClientConn) tooIdleLocked() bool {930	// The Round(0) strips the monontonic clock reading so the931	// times are compared based on their wall time. We don't want932	// to reuse a connection that's been sitting idle during933	// VM/laptop suspend if monotonic time was also frozen.934	return cc.idleTimeout != 0 && !cc.lastIdle.IsZero() && time.Since(cc.lastIdle.Round(0)) > cc.idleTimeout935}936937// onIdleTimeout is called from a time.AfterFunc goroutine. It will938// only be called when we're idle, but because we're coming from a new939// goroutine, there could be a new request coming in at the same time,940// so this simply calls the synchronized closeIfIdle to shut down this941// connection. The timer could just call closeIfIdle, but this is more942// clear.943func (cc *ClientConn) onIdleTimeout() {944	cc.closeIfIdle()945}946947func (cc *ClientConn) closeConn() {948	t := time.AfterFunc(250*time.Millisecond, cc.forceCloseConn)949	defer t.Stop()950	cc.tconn.Close()951	cc.maybeCallStateHook()952}953954// A tls.Conn.Close can hang for a long time if the peer is unresponsive.955// Try to shut it down more aggressively.956func (cc *ClientConn) forceCloseConn() {957	tc, ok := cc.tconn.(*tls.Conn)958	if !ok {959		return960	}961	if nc := tc.NetConn(); nc != nil {962		nc.Close()963	}964}965966func (cc *ClientConn) closeIfIdle() {967	cc.mu.Lock()968	if len(cc.streams) > 0 || cc.streamsReserved > 0 {969		cc.mu.Unlock()970		return971	}972	cc.closed = true973	cc.closedOnIdle = true974	nextID := cc.nextStreamID975	// TODO: do clients send GOAWAY too? maybe? Just Close:976	cc.mu.Unlock()977978	if VerboseLogs {979		cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, nextID-2)980	}981	cc.closeConn()982}983984func (cc *ClientConn) isDoNotReuseAndIdle() bool {985	cc.mu.Lock()986	defer cc.mu.Unlock()987	return cc.doNotReuse && len(cc.streams) == 0988}989990var shutdownEnterWaitStateHook = func() {}991992// Shutdown gracefully closes the client connection, waiting for running streams to complete.993func (cc *ClientConn) Shutdown(ctx context.Context) error {994	if err := cc.sendGoAway(); err != nil {995		return err996	}997	// Wait for all in-flight streams to complete or connection to close998	done := make(chan struct{})999	cancelled := false // guarded by cc.mu1000	go func() {1001		cc.mu.Lock()1002		defer cc.mu.Unlock()1003		for {1004			if len(cc.streams) == 0 || cc.closed {1005				cc.closed = true1006				close(done)1007				break1008			}1009			if cancelled {1010				break1011			}1012			cc.cond.Wait()1013		}1014	}()1015	shutdownEnterWaitStateHook()1016	select {1017	case <-done:1018		cc.closeConn()1019		return nil1020	case <-ctx.Done():1021		cc.mu.Lock()1022		// Free the goroutine above1023		cancelled = true1024		cc.cond.Broadcast()1025		cc.mu.Unlock()1026		return ctx.Err()1027	}1028}10291030func (cc *ClientConn) sendGoAway() error {1031	cc.mu.Lock()1032	closing := cc.closing1033	cc.closing = true1034	maxStreamID := cc.nextStreamID1035	cc.mu.Unlock()1036	if closing {1037		// GOAWAY sent already1038		return nil1039	}10401041	cc.wmu.Lock()1042	defer cc.wmu.Unlock()1043	// Send a graceful shutdown frame to server1044	if err := cc.fr.WriteGoAway(maxStreamID, ErrCodeNo, nil); err != nil {1045		return err1046	}1047	if err := cc.bw.Flush(); err != nil {1048		return err1049	}1050	// Prevent new requests1051	return nil1052}10531054// closes the client connection immediately. In-flight requests are interrupted.1055// err is sent to streams.1056func (cc *ClientConn) closeForError(err error) {1057	cc.mu.Lock()1058	cc.closed = true1059	for _, cs := range cc.streams {1060		cs.abortStreamLocked(err)1061	}1062	cc.cond.Broadcast()1063	cc.mu.Unlock()1064	cc.closeConn()1065}10661067// Close closes the client connection immediately.1068//1069// In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead.1070func (cc *ClientConn) Close() error {1071	cc.closeForError(errClientConnForceClosed)1072	return nil1073}10741075// closes the client connection immediately. In-flight requests are interrupted.1076func (cc *ClientConn) closeForLostPing() {1077	err := errors.New("http2: client connection lost")1078	if f := cc.fr.countError; f != nil {1079		f("conn_close_lost_ping")1080	}1081	cc.closeForError(err)1082}10831084// errRequestCanceled is a copy of net/http's errRequestCanceled because it's not1085// exported. At least they'll be DeepEqual for h1-vs-h2 comparisons tests.1086var errRequestCanceled = internal.ErrRequestCanceled10871088func (cc *ClientConn) responseHeaderTimeout() time.Duration {1089	if cc.t.t1 != nil {1090		return cc.t.t1.ResponseHeaderTimeout()1091	}1092	// No way to do this (yet?) with just an http2.Transport. Probably1093	// no need. Request.Cancel this is the new way. We only need to support1094	// this for compatibility with the old http.Transport fields when1095	// we're doing transparent http2.1096	return 01097}10981099// actualContentLength returns a sanitized version of1100// req.ContentLength, where 0 actually means zero (not unknown) and -11101// means unknown.1102func actualContentLength(req *ClientRequest) int64 {1103	if req.Body == nil || req.Body == NoBody {1104		return 01105	}1106	if req.ContentLength != 0 {1107		return req.ContentLength1108	}1109	return -11110}11111112func (cc *ClientConn) decrStreamReservations() {1113	cc.mu.Lock()1114	defer cc.mu.Unlock()1115	cc.decrStreamReservationsLocked()1116}11171118func (cc *ClientConn) decrStreamReservationsLocked() {1119	if cc.streamsReserved > 0 {1120		cc.streamsReserved--1121	}1122}11231124func (cc *ClientConn) RoundTrip(req *ClientRequest) (*ClientResponse, error) {1125	return cc.roundTrip(req, nil)1126}11271128func (cc *ClientConn) roundTrip(req *ClientRequest, streamf func(*clientStream)) (*ClientResponse, error) {1129	ctx := req.Context1130	req.stream = clientStream{1131		cc:                   cc,1132		ctx:                  ctx,1133		reqCancel:            req.Cancel,1134		isHead:               req.Method == "HEAD",1135		reqBody:              req.Body,1136		reqBodyContentLength: actualContentLength(req),1137		trace:                httptrace.ContextClientTrace(ctx),1138		peerClosed:           make(chan struct{}),1139		abort:                make(chan struct{}),1140		respHeaderRecv:       make(chan struct{}),1141		donec:                make(chan struct{}),1142		resTrailer:           req.ResTrailer,1143	}1144	cs := &req.stream11451146	cs.requestedGzip = httpcommon.IsRequestGzip(req.Method, req.Header, cc.t.disableCompression())11471148	go cs.doRequest(req, streamf)11491150	waitDone := func() error {1151		select {1152		case <-cs.donec:1153			return nil1154		case <-ctx.Done():1155			return ctx.Err()1156		case <-cs.reqCancel:1157			return errRequestCanceled1158		}1159	}11601161	handleResponseHeaders := func() (*ClientResponse, error) {1162		res := cs.res1163		if res.StatusCode > 299 {1164			// On error or status code 3xx, 4xx, 5xx, etc abort any1165			// ongoing write, assuming that the server doesn't care1166			// about our request body. If the server replied with 1xx or1167			// 2xx, however, then assume the server DOES potentially1168			// want our body (e.g. full-duplex streaming:1169			// golang.org/issue/13444). If it turns out the server1170			// doesn't, they'll RST_STREAM us soon enough. This is a1171			// heuristic to avoid adding knobs to Transport. Hopefully1172			// we can keep it.1173			cs.abortRequestBodyWrite()1174		}1175		res.TLS = cc.tlsState1176		if res.Body == NoBody && actualContentLength(req) == 0 {1177			// If there isn't a request or response body still being1178			// written, then wait for the stream to be closed before1179			// RoundTrip returns.1180			if err := waitDone(); err != nil {1181				return nil, err1182			}1183		}1184		return res, nil1185	}11861187	cancelRequest := func(cs *clientStream, err error) error {1188		cs.cc.mu.Lock()1189		bodyClosed := cs.reqBodyClosed1190		cs.cc.mu.Unlock()1191		// Wait for the request body to be closed.1192		//1193		// If nothing closed the body before now, abortStreamLocked1194		// will have started a goroutine to close it.1195		//1196		// Closing the body before returning avoids a race condition1197		// with net/http checking its readTrackingBody to see if the1198		// body was read from or closed. See golang/go#60041.1199		//1200		// The body is closed in a separate goroutine without the1201		// connection mutex held, but dropping the mutex before waiting1202		// will keep us from holding it indefinitely if the body1203		// close is slow for some reason.1204		if bodyClosed != nil {1205			<-bodyClosed1206		}1207		return err1208	}12091210	for {1211		select {1212		case <-cs.respHeaderRecv:1213			return handleResponseHeaders()1214		case <-cs.abort:1215			select {1216			case <-cs.respHeaderRecv:1217				// If both cs.respHeaderRecv and cs.abort are signaling,1218				// pick respHeaderRecv. The server probably wrote the1219				// response and immediately reset the stream.1220				// golang.org/issue/496451221				return handleResponseHeaders()1222			default:1223				waitDone()1224				return nil, cs.abortErr1225			}1226		case <-ctx.Done():1227			err := ctx.Err()1228			cs.abortStream(err)1229			return nil, cancelRequest(cs, err)1230		case <-cs.reqCancel:1231			cs.abortStream(errRequestCanceled)1232			return nil, cancelRequest(cs, errRequestCanceled)1233		}1234	}1235}12361237// doRequest runs for the duration of the request lifetime.1238//1239// It sends the request and performs post-request cleanup (closing Request.Body, etc.),1240// except when writeRequest detaches from the stream, in which case cleanup is1241// performed at stream end by whoever ends it. See clientStream.detach.1242func (cs *clientStream) doRequest(req *ClientRequest, streamf func(*clientStream)) {1243	err := cs.writeRequest(req, streamf)1244	if err == errStreamDetached {1245		return1246	}1247	cs.cleanupWriteRequest(err)1248}12491250// errStreamDetached is a sentinel returned by writeRequest to tell doRequest1251// that the stream detached and cleanupWriteRequest will be called at stream1252// end by whoever ends it. It is never returned to users.1253var errStreamDetached = errors.New("http2: internal sentinel; stream detached from writeRequest goroutine")12541255// detach arranges for cleanupWriteRequest to run when the stream ends (the1256// peer half-closes it, it's aborted, or the request context is canceled),1257// letting the writeRequest goroutine exit instead of parking until then.1258//1259// This matters for servers and proxies with many concurrent long-lived1260// response streams (long polls): without it, each in-flight request pins a1261// goroutine and its stack for the stream's lifetime doing nothing but1262// waiting.1263//1264// respHeaderTimeout, if non-zero, gives the Transport.ResponseHeaderTimeout1265// to enforce on the detached stream if response headers haven't arrived yet.1266//1267// It reports whether the stream was detached. It returns false if the stream1268// has already ended, in which case the caller should wait for the stream end1269// events itself (they're already pending).1270func (cs *clientStream) detach(respHeaderTimeout time.Duration) bool {1271	cc := cs.cc1272	cc.mu.Lock()1273	defer cc.mu.Unlock()1274	select {1275	case <-cs.peerClosed:1276		return false1277	case <-cs.abort:1278		return false1279	default:1280	}1281	if respHeaderTimeout != 0 {1282		select {1283		case <-cs.respHeaderRecv:1284			// Headers already arrived; nothing to enforce.1285		default:1286			cs.respHeaderTimeoutTimer = time.AfterFunc(respHeaderTimeout, func() {1287				cc.mu.Lock()1288				defer cc.mu.Unlock()1289				select {1290				case <-cs.respHeaderRecv:1291					// Headers arrived after all; we lost a race1292					// with the Stop in processHeaders. Not a1293					// timeout.1294					return1295				default:1296				}1297				cs.abortStreamLocked(errTimeout)1298			})1299		}1300	}1301	// Watch for request context cancellation without parking a goroutine1302	// on ctx.Done(). If the context was canceled already, AfterFunc runs1303	// the func in a new goroutine, which blocks acquiring cc.mu until we1304	// return.1305	//1306	// stopCtxWatch must be assigned before detached is set: once detached1307	// is set, an abort or peer close can schedule cleanupWriteRequest1308	// (which calls stopCtxWatch) as soon as we release cc.mu.1309	cs.stopCtxWatch = context.AfterFunc(cs.ctx, func() {1310		cs.abortStream(cs.ctx.Err())1311	})1312	cs.detached = true1313	return true1314}13151316var errExtendedConnectNotSupported = errors.New("net/http: extended connect not supported by peer")13171318// writeRequest sends a request.1319//1320// It returns nil after the request is written, the response read,1321// and the request stream is half-closed by the peer.1322//1323// It returns non-nil if the request ends otherwise.1324// If the returned error is StreamError, the error Code may be used in resetting the stream.1325func (cs *clientStream) writeRequest(req *ClientRequest, streamf func(*clientStream)) (err error) {1326	cc := cs.cc1327	ctx := cs.ctx13281329	// wait for setting frames to be received, a server can change this value later,1330	// but we just wait for the first settings frame1331	var isExtendedConnect bool1332	if req.Method == "CONNECT" && req.Header.Get(":protocol") != "" {1333		isExtendedConnect = true1334	}13351336	// Acquire the new-request lock by writing to reqHeaderMu.1337	// This lock guards the critical section covering allocating a new stream ID1338	// (requires mu) and creating the stream (requires wmu).1339	if cc.reqHeaderMu == nil {1340		panic("RoundTrip on uninitialized ClientConn") // for tests1341	}1342	if isExtendedConnect {1343		select {1344		case <-cs.reqCancel:1345			return errRequestCanceled1346		case <-ctx.Done():1347			return ctx.Err()1348		case <-cc.seenSettingsChan:1349			if !cc.extendedConnectAllowed {1350				return errExtendedConnectNotSupported1351			}1352		}1353	}1354	select {1355	case cc.reqHeaderMu <- struct{}{}:1356	case <-cs.reqCancel:1357		return errRequestCanceled1358	case <-ctx.Done():1359		return ctx.Err()1360	}13611362	cc.mu.Lock()1363	if cc.idleTimer != nil {1364		cc.idleTimer.Stop()1365	}1366	cc.decrStreamReservationsLocked()1367	if err := cc.awaitOpenSlotForStreamLocked(cs); err != nil {1368		cc.mu.Unlock()1369		<-cc.reqHeaderMu1370		return err1371	}1372	cc.addStreamLocked(cs) // assigns stream ID1373	if isConnectionCloseRequest(req) {1374		cc.doNotReuse = true1375	}1376	cc.mu.Unlock()13771378	if streamf != nil {1379		streamf(cs)1380	}13811382	continueTimeout := cc.t.expectContinueTimeout()1383	if continueTimeout != 0 {1384		if !httpguts.HeaderValuesContainsToken(req.Header["Expect"], "100-continue") {1385			continueTimeout = 01386		} else {1387			cs.on100 = make(chan struct{}, 1)1388		}1389	}13901391	// Past this point (where we send request headers), it is possible for1392	// RoundTrip to return successfully. Since the RoundTrip contract permits1393	// the caller to "mutate or reuse" the Request after closing the Response's Body,1394	// we must take care when referencing the Request from here on.1395	err = cs.encodeAndWriteHeaders(req)1396	<-cc.reqHeaderMu1397	if err != nil {1398		return err1399	}14001401	hasBody := cs.reqBodyContentLength != 01402	if !hasBody {1403		cs.sentEndStream = true1404	} else {1405		if continueTimeout != 0 {1406			traceWait100Continue(cs.trace)1407			timer := time.NewTimer(continueTimeout)1408			select {1409			case <-timer.C:1410				err = nil1411			case <-cs.on100:1412				err = nil1413			case <-cs.abort:1414				err = cs.abortErr1415			case <-ctx.Done():1416				err = ctx.Err()1417			case <-cs.reqCancel:1418				err = errRequestCanceled1419			}1420			timer.Stop()1421			if err != nil {1422				traceWroteRequest(cs.trace, err)1423				return err1424			}1425		}14261427		if err = cs.writeRequestBody(req); err != nil {1428			if err != errStopReqBodyWrite {1429				traceWroteRequest(cs.trace, err)1430				return err1431			}1432		} else {1433			cs.sentEndStream = true1434		}1435	}14361437	traceWroteRequest(cs.trace, err)14381439	// If the request is fully sent and there's nothing left for this1440	// goroutine to do but wait for the stream to end, detach from the1441	// stream and exit rather than pinning this goroutine (and its stack)1442	// for the lifetime of what may be a very long-lived response stream.1443	// The remaining cases below then run cleanupWriteRequest from the1444	// stream-end event sites instead:1445	//   - peerClosed and abort schedule it directly1446	//     (abortStreamLocked, clientConnReadLoop.endStream)1447	//   - ctx.Done is handled via context.AfterFunc in detach1448	//   - ResponseHeaderTimeout is enforced by a time.AfterFunc timer,1449	//     armed in detach and stopped when headers arrive1450	// The deprecated Request.Cancel channel can only be watched by a1451	// goroutine, so that (rare) case keeps the historical behavior of1452	// waiting here.1453	if cs.sentEndStream && cs.reqCancel == nil && cs.detach(cc.responseHeaderTimeout()) {1454		return errStreamDetached1455	}14561457	var respHeaderTimer <-chan time.Time1458	var respHeaderRecv chan struct{}1459	if d := cc.responseHeaderTimeout(); d != 0 {1460		timer := time.NewTimer(d)1461		defer timer.Stop()1462		respHeaderTimer = timer.C1463		respHeaderRecv = cs.respHeaderRecv1464	}14651466	// Wait until the peer half-closes its end of the stream,1467	// or until the request is aborted (via context, error, or otherwise),1468	// whichever comes first.1469	for {1470		select {1471		case <-cs.peerClosed:1472			return nil1473		case <-respHeaderTimer:1474			return errTimeout1475		case <-respHeaderRecv:1476			respHeaderRecv = nil1477			respHeaderTimer = nil // keep waiting for END_STREAM1478		case <-cs.abort:1479			return cs.abortErr1480		case <-ctx.Done():1481			return ctx.Err()1482		case <-cs.reqCancel:1483			return errRequestCanceled1484		}1485	}1486}14871488func (cs *clientStream) encodeAndWriteHeaders(req *ClientRequest) error {1489	cc := cs.cc1490	ctx := cs.ctx14911492	cc.wmu.Lock()1493	defer cc.wmu.Unlock()14941495	// If the request was canceled while waiting for cc.mu, just quit.1496	select {1497	case <-cs.abort:1498		return cs.abortErr1499	case <-ctx.Done():1500		return ctx.Err()1501	case <-cs.reqCancel:1502		return errRequestCanceled1503	default:1504	}15051506	// Encode headers.1507	//1508	// we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is1509	// sent by writeRequestBody below, along with any Trailers,1510	// again in form HEADERS{1}, CONTINUATION{0,})1511	cc.hbuf.Reset()1512	res, err := encodeRequestHeaders(req, cs.requestedGzip, cc.peerMaxHeaderListSize, func(name, value string) {1513		cc.writeHeader(name, value)1514	})1515	if err != nil {1516		return fmt.Errorf("http2: %w", err)1517	}1518	hdrs := cc.hbuf.Bytes()15191520	// Write the request.1521	endStream := !res.HasBody && !res.HasTrailers1522	cs.sentHeaders = true1523	err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs)1524	traceWroteHeaders(cs.trace)1525	return err1526}15271528func encodeRequestHeaders(req *ClientRequest, addGzipHeader bool, peerMaxHeaderListSize uint64, headerf func(name, value string)) (httpcommon.EncodeHeadersResult, error) {1529	return httpcommon.EncodeHeaders(req.Context, httpcommon.EncodeHeadersParam{1530		Request: httpcommon.Request{1531			Header:              req.Header,1532			Trailer:             req.Trailer,1533			URL:                 req.URL,1534			Host:                req.Host,1535			Method:              req.Method,1536			ActualContentLength: actualContentLength(req),1537		},1538		AddGzipHeader:         addGzipHeader,1539		PeerMaxHeaderListSize: peerMaxHeaderListSize,1540		DefaultUserAgent:      defaultUserAgent,1541	}, headerf)1542}15431544// cleanupWriteRequest performs post-request tasks.1545//1546// If err (the result of writeRequest) is non-nil and the stream is not closed,1547// cleanupWriteRequest will send a reset to the peer.1548func (cs *clientStream) cleanupWriteRequest(err error) {1549	cc := cs.cc15501551	if cs.stopCtxWatch != nil {1552		cs.stopCtxWatch()1553	}15541555	if cs.ID == 0 {1556		// We were canceled before creating the stream, so return our reservation.1557		cc.decrStreamReservations()1558	}15591560	// TODO: write h12Compare test showing whether1561	// Request.Body is closed by the Transport,1562	// and in multiple cases: server replies <=299 and >2991563	// while still writing request body1564	cc.mu.Lock()1565	if t := cs.respHeaderTimeoutTimer; t != nil {1566		t.Stop()1567		cs.respHeaderTimeoutTimer = nil1568	}1569	mustCloseBody := false1570	if cs.reqBody != nil && cs.reqBodyClosed == nil {1571		mustCloseBody = true1572		cs.reqBodyClosed = make(chan struct{})1573	}1574	bodyClosed := cs.reqBodyClosed1575	closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() || cc.goAway != nil1576	// Have we read any frames from the connection since sending this request?1577	readSinceStream := cc.readBeforeStreamID > cs.ID1578	cc.mu.Unlock()1579	if mustCloseBody {1580		cs.reqBody.Close()1581		close(bodyClosed)1582	}1583	if bodyClosed != nil {1584		<-bodyClosed1585	}15861587	if err != nil && cs.sentEndStream {1588		// If the connection is closed immediately after the response is read,1589		// we may be aborted before finishing up here. If the stream was closed1590		// cleanly on both sides, there is no error.1591		select {1592		case <-cs.peerClosed:1593			err = nil1594		default:1595		}1596	}1597	if err != nil {1598		cs.abortStream(err) // possibly redundant, but harmless1599		if cs.sentHeaders {1600			if se, ok := err.(StreamError); ok {1601				if se.Cause != errFromPeer {1602					cc.writeStreamReset(cs.ID, se.Code, false, err)1603				}1604			} else {1605				// We're cancelling an in-flight request.1606				//1607				// This could be due to the server becoming unresponsive.1608				// To avoid sending too many requests on a dead connection,1609				// if we haven't read any frames from the connection since1610				// sending this request, we let it continue to consume1611				// a concurrency slot until we can confirm the server is1612				// still responding.1613				// We do this by sending a PING frame along with the RST_STREAM1614				// (unless a ping is already in flight).1615				//1616				// For simplicity, we don't bother tracking the PING payload:1617				// We reset cc.pendingResets any time we receive a PING ACK.1618				//1619				// We skip this if the conn is going to be closed on idle,1620				// because it's short lived and will probably be closed before1621				// we get the ping response.1622				ping := false1623				if !closeOnIdle && !readSinceStream {1624					cc.mu.Lock()1625					// rstStreamPingsBlocked works around a gRPC behavior:1626					// see comment on the field for details.1627					if !cc.rstStreamPingsBlocked {1628						if cc.pendingResets == 0 {1629							ping = true1630						}1631						cc.pendingResets++1632					}1633					cc.mu.Unlock()1634				}1635				cc.writeStreamReset(cs.ID, ErrCodeCancel, ping, err)1636			}1637		}1638		cs.bufPipe.CloseWithError(err) // no-op if already closed1639	} else {1640		if cs.sentHeaders && !cs.sentEndStream {1641			cc.writeStreamReset(cs.ID, ErrCodeNo, false, nil)1642		}1643		cs.bufPipe.CloseWithError(errRequestCanceled)1644	}1645	if cs.ID != 0 {1646		cc.forgetStreamID(cs.ID)1647	}16481649	cc.wmu.Lock()1650	werr := cc.werr1651	cc.wmu.Unlock()1652	if werr != nil {1653		cc.Close()1654	}16551656	close(cs.donec)1657	cc.maybeCallStateHook()1658}16591660// awaitOpenSlotForStreamLocked waits until len(streams) < maxConcurrentStreams.1661// Must hold cc.mu.1662func (cc *ClientConn) awaitOpenSlotForStreamLocked(cs *clientStream) error {1663	for {1664		if cc.closed && cc.nextStreamID == 1 && cc.streamsReserved == 0 {1665			// This is the very first request sent to this connection.1666			// Return a fatal error which aborts the retry loop.1667			return errClientConnNotEstablished1668		}1669		cc.lastActive = time.Now()1670		if cc.closed || !cc.canTakeNewRequestLocked() {1671			return errClientConnUnusable1672		}1673		cc.lastIdle = time.Time{}1674		if cc.currentRequestCountLocked() < int(cc.maxConcurrentStreams) {1675			return nil1676		}1677		cc.pendingRequests++1678		cc.cond.Wait()1679		cc.pendingRequests--1680		select {1681		case <-cs.abort:1682			return cs.abortErr1683		default:1684		}1685	}1686}16871688// requires cc.wmu be held1689func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize int, hdrs []byte) error {1690	first := true // first frame written (HEADERS is first, then CONTINUATION)1691	for len(hdrs) > 0 && cc.werr == nil {1692		chunk := hdrs1693		if len(chunk) > maxFrameSize {1694			chunk = chunk[:maxFrameSize]1695		}1696		hdrs = hdrs[len(chunk):]1697		endHeaders := len(hdrs) == 01698		if first {1699			cc.fr.WriteHeaders(HeadersFrameParam{1700				StreamID:      streamID,1701				BlockFragment: chunk,1702				EndStream:     endStream,1703				EndHeaders:    endHeaders,1704			})1705			first = false1706		} else {1707			cc.fr.WriteContinuation(streamID, endHeaders, chunk)1708		}1709	}1710	cc.bw.Flush()1711	return cc.werr1712}17131714// internal error values; they don't escape to callers1715var (1716	// abort request body write; don't send cancel1717	errStopReqBodyWrite = errors.New("http2: aborting request body write")17181719	// abort request body write, but send stream reset of cancel.1720	errStopReqBodyWriteAndCancel = errors.New("http2: canceling request")17211722	errReqBodyTooLong = errors.New("http2: request body larger than specified content length")1723)17241725// frameScratchBufferLen returns the length of a buffer to use for1726// outgoing request bodies to read/write to/from.1727//1728// It returns max(1, min(peer's advertised max frame size,1729// Request.ContentLength+1, 512KB)).1730func (cs *clientStream) frameScratchBufferLen(maxFrameSize int) int {1731	const max = 512 << 101732	n := min(int64(maxFrameSize), max)1733	if cl := cs.reqBodyContentLength; cl != -1 && cl+1 < n {1734		// Add an extra byte past the declared content-length to1735		// give the caller's Request.Body io.Reader a chance to1736		// give us more bytes than they declared, so we can catch it1737		// early.1738		n = cl + 11739	}1740	if n < 1 {1741		return 11742	}1743	return int(n) // doesn't truncate; max is 512K1744}17451746// Seven bufPools manage different frame sizes. This helps to avoid scenarios where long-running1747// streaming requests using small frame sizes occupy large buffers initially allocated for prior1748// requests needing big buffers. The size ranges are as follows:1749// {0 KB, 16 KB], {16 KB, 32 KB], {32 KB, 64 KB], {64 KB, 128 KB], {128 KB, 256 KB],1750// {256 KB, 512 KB], {512 KB, infinity}1751// In practice, the maximum scratch buffer size should not exceed 512 KB due to1752// frameScratchBufferLen(maxFrameSize), thus the "infinity pool" should never be used.1753// It exists mainly as a safety measure, for potential future increases in max buffer size.1754var bufPools [7]sync.Pool // of *[]byte1755func bufPoolIndex(size int) int {1756	if size <= 16384 {1757		return 01758	}1759	size -= 11760	bits := bits.Len(uint(size))1761	index := bits - 141762	if index >= len(bufPools) {1763		return len(bufPools) - 11764	}1765	return index1766}17671768func (cs *clientStream) writeRequestBody(req *ClientRequest) (err error) {1769	cc := cs.cc1770	body := cs.reqBody1771	sentEnd := false // whether we sent the final DATA frame w/ END_STREAM17721773	hasTrailers := req.Trailer != nil1774	remainLen := cs.reqBodyContentLength1775	hasContentLen := remainLen != -117761777	cc.mu.Lock()1778	maxFrameSize := int(cc.maxFrameSize)1779	cc.mu.Unlock()17801781	// Scratch buffer for reading into & writing from.1782	scratchLen := cs.frameScratchBufferLen(maxFrameSize)1783	var buf []byte1784	index := bufPoolIndex(scratchLen)1785	if bp, ok := bufPools[index].Get().(*[]byte); ok && len(*bp) >= scratchLen {1786		defer bufPools[index].Put(bp)1787		buf = *bp1788	} else {1789		buf = make([]byte, scratchLen)1790		defer bufPools[index].Put(&buf)1791	}17921793	var sawEOF bool1794	for !sawEOF {1795		n, err := body.Read(buf)1796		if hasContentLen {1797			remainLen -= int64(n)1798			if remainLen == 0 && err == nil {1799				// The request body's Content-Length was predeclared and1800				// we just finished reading it all, but the underlying io.Reader1801				// returned the final chunk with a nil error (which is one of1802				// the two valid things a Reader can do at EOF). Because we'd prefer1803				// to send the END_STREAM bit early, double-check that we're actually1804				// at EOF. Subsequent reads should return (0, EOF) at this point.1805				// If either value is different, we return an error in one of two ways below.1806				var scratch [1]byte1807				var n1 int1808				n1, err = body.Read(scratch[:])1809				remainLen -= int64(n1)1810			}1811			if remainLen < 0 {1812				err = errReqBodyTooLong1813				return err1814			}1815		}1816		if err != nil {1817			cc.mu.Lock()1818			bodyClosed := cs.reqBodyClosed != nil1819			cc.mu.Unlock()1820			switch {1821			case bodyClosed:1822				return errStopReqBodyWrite1823			case err == io.EOF:1824				sawEOF = true1825				err = nil1826			default:1827				return err1828			}1829		}18301831		remain := buf[:n]1832		for len(remain) > 0 && err == nil {1833			var allowed int321834			allowed, err = cs.awaitFlowControl(len(remain))1835			if err != nil {1836				return err1837			}1838			cc.wmu.Lock()1839			data := remain[:allowed]1840			remain = remain[allowed:]1841			sentEnd = sawEOF && len(remain) == 0 && !hasTrailers1842			err = cc.fr.WriteData(cs.ID, sentEnd, data)1843			if err == nil {1844				// TODO(bradfitz): this flush is for latency, not bandwidth.1845				// Most requests won't need this. Make this opt-in or1846				// opt-out?  Use some heuristic on the body type? Nagel-like1847				// timers?  Based on 'n'? Only last chunk of this for loop,1848				// unless flow control tokens are low? For now, always.1849				// If we change this, see comment below.1850				err = cc.bw.Flush()1851			}1852			cc.wmu.Unlock()1853		}1854		if err != nil {1855			return err1856		}1857	}18581859	if sentEnd {1860		// Already sent END_STREAM (which implies we have no1861		// trailers) and flushed, because currently all1862		// WriteData frames above get a flush. So we're done.1863		return nil1864	}18651866	// Since the RoundTrip contract permits the caller to "mutate or reuse"1867	// a request after the Response's Body is closed, verify that this hasn't1868	// happened before accessing the trailers.1869	cc.mu.Lock()1870	trailer := req.Trailer1871	err = cs.abortErr1872	cc.mu.Unlock()1873	if err != nil {1874		return err1875	}18761877	cc.wmu.Lock()1878	defer cc.wmu.Unlock()1879	var trls []byte1880	if len(trailer) > 0 {1881		trls, err = cc.encodeTrailers(trailer)1882		if err != nil {1883			return err1884		}1885	}18861887	// Two ways to send END_STREAM: either with trailers, or1888	// with an empty DATA frame.1889	if len(trls) > 0 {1890		err = cc.writeHeaders(cs.ID, true, maxFrameSize, trls)1891	} else {1892		err = cc.fr.WriteData(cs.ID, true, nil)1893	}1894	if ferr := cc.bw.Flush(); ferr != nil && err == nil {1895		err = ferr1896	}1897	return err1898}18991900// awaitFlowControl waits for [1, min(maxBytes, cc.cs.maxFrameSize)] flow1901// control tokens from the server.1902// It returns either the non-zero number of tokens taken or an error1903// if the stream is dead.1904func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) {1905	cc := cs.cc1906	ctx := cs.ctx1907	cc.mu.Lock()1908	defer cc.mu.Unlock()1909	for {1910		if cc.closed {1911			return 0, errClientConnClosed1912		}1913		if cs.reqBodyClosed != nil {1914			return 0, errStopReqBodyWrite1915		}1916		select {1917		case <-cs.abort:1918			return 0, cs.abortErr1919		case <-ctx.Done():1920			return 0, ctx.Err()1921		case <-cs.reqCancel:1922			return 0, errRequestCanceled1923		default:1924		}1925		if a := cs.flow.available(); a > 0 {1926			take := a1927			if int(take) > maxBytes {19281929				take = int32(maxBytes) // can't truncate int; take is int321930			}1931			if take > int32(cc.maxFrameSize) {1932				take = int32(cc.maxFrameSize)1933			}1934			cs.flow.take(take)1935			return take, nil1936		}1937		cc.cond.Wait()1938	}1939}19401941// requires cc.wmu be held.1942func (cc *ClientConn) encodeTrailers(trailer Header) ([]byte, error) {1943	cc.hbuf.Reset()19441945	hlSize := uint64(0)1946	for k, vv := range trailer {1947		for _, v := range vv {1948			hf := hpack.HeaderField{Name: k, Value: v}1949			hlSize += uint64(hf.Size())1950		}1951	}1952	if hlSize > cc.peerMaxHeaderListSize {1953		return nil, errRequestHeaderListSize1954	}19551956	for k, vv := range trailer {1957		lowKey, ascii := httpcommon.LowerHeader(k)1958		if !ascii {1959			// Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header1960			// field names have to be ASCII characters (just as in HTTP/1.x).1961			continue1962		}1963		// Transfer-Encoding, etc.. have already been filtered at the1964		// start of RoundTrip1965		for _, v := range vv {1966			cc.writeHeader(lowKey, v)1967		}1968	}1969	return cc.hbuf.Bytes(), nil1970}19711972func (cc *ClientConn) writeHeader(name, value string) {1973	if VerboseLogs {1974		log.Printf("http2: Transport encoding header %q = %q", name, value)1975	}1976	cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})1977}19781979type resAndError struct {1980	_   incomparable1981	res *ClientResponse1982	err error1983}19841985// requires cc.mu be held.1986func (cc *ClientConn) addStreamLocked(cs *clientStream) {1987	cs.flow.add(int32(cc.initialWindowSize))1988	cs.flow.setConnFlow(&cc.flow)1989	cs.inflow.init(cc.initialStreamRecvWindowSize)1990	cs.ID = cc.nextStreamID1991	cc.nextStreamID += 21992	cc.streams[cs.ID] = cs1993	if cs.ID == 0 {1994		panic("assigned stream ID 0")1995	}1996}19971998func (cc *ClientConn) forgetStreamID(id uint32) {1999	cc.mu.Lock()2000	slen := len(cc.streams)

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.