Merge pull request #24173 from containers/renovate/golang.org-x-net-0.x
fix(deps): update module golang.org/x/net to v0.30.0
This commit is contained in:
		
						commit
						35768aef2b
					
				
							
								
								
									
										2
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										2
									
								
								go.mod
								
								
								
								
							|  | @ -72,7 +72,7 @@ require ( | |||
| 	go.etcd.io/bbolt v1.3.11 | ||||
| 	golang.org/x/crypto v0.28.0 | ||||
| 	golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 | ||||
| 	golang.org/x/net v0.29.0 | ||||
| 	golang.org/x/net v0.30.0 | ||||
| 	golang.org/x/sync v0.8.0 | ||||
| 	golang.org/x/sys v0.26.0 | ||||
| 	golang.org/x/term v0.25.0 | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										4
									
								
								go.sum
								
								
								
								
							|  | @ -605,8 +605,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug | |||
| golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= | ||||
| golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | ||||
| golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= | ||||
| golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= | ||||
| golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= | ||||
| golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= | ||||
| golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= | ||||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||
| golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= | ||||
| golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= | ||||
|  |  | |||
|  | @ -0,0 +1,122 @@ | |||
| // Copyright 2024 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.
 | ||||
| 
 | ||||
| package http2 | ||||
| 
 | ||||
| import ( | ||||
| 	"math" | ||||
| 	"net/http" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| // http2Config is a package-internal version of net/http.HTTP2Config.
 | ||||
| //
 | ||||
| // http.HTTP2Config was added in Go 1.24.
 | ||||
| // When running with a version of net/http that includes HTTP2Config,
 | ||||
| // we merge the configuration with the fields in Transport or Server
 | ||||
| // to produce an http2Config.
 | ||||
| //
 | ||||
| // Zero valued fields in http2Config are interpreted as in the
 | ||||
| // net/http.HTTPConfig documentation.
 | ||||
| //
 | ||||
| // Precedence order for reconciling configurations is:
 | ||||
| //
 | ||||
| //   - Use the net/http.{Server,Transport}.HTTP2Config value, when non-zero.
 | ||||
| //   - Otherwise use the http2.{Server.Transport} value.
 | ||||
| //   - If the resulting value is zero or out of range, use a default.
 | ||||
| type http2Config struct { | ||||
| 	MaxConcurrentStreams         uint32 | ||||
| 	MaxDecoderHeaderTableSize    uint32 | ||||
| 	MaxEncoderHeaderTableSize    uint32 | ||||
| 	MaxReadFrameSize             uint32 | ||||
| 	MaxUploadBufferPerConnection int32 | ||||
| 	MaxUploadBufferPerStream     int32 | ||||
| 	SendPingTimeout              time.Duration | ||||
| 	PingTimeout                  time.Duration | ||||
| 	WriteByteTimeout             time.Duration | ||||
| 	PermitProhibitedCipherSuites bool | ||||
| 	CountError                   func(errType string) | ||||
| } | ||||
| 
 | ||||
| // configFromServer merges configuration settings from
 | ||||
| // net/http.Server.HTTP2Config and http2.Server.
 | ||||
| func configFromServer(h1 *http.Server, h2 *Server) http2Config { | ||||
| 	conf := http2Config{ | ||||
| 		MaxConcurrentStreams:         h2.MaxConcurrentStreams, | ||||
| 		MaxEncoderHeaderTableSize:    h2.MaxEncoderHeaderTableSize, | ||||
| 		MaxDecoderHeaderTableSize:    h2.MaxDecoderHeaderTableSize, | ||||
| 		MaxReadFrameSize:             h2.MaxReadFrameSize, | ||||
| 		MaxUploadBufferPerConnection: h2.MaxUploadBufferPerConnection, | ||||
| 		MaxUploadBufferPerStream:     h2.MaxUploadBufferPerStream, | ||||
| 		SendPingTimeout:              h2.ReadIdleTimeout, | ||||
| 		PingTimeout:                  h2.PingTimeout, | ||||
| 		WriteByteTimeout:             h2.WriteByteTimeout, | ||||
| 		PermitProhibitedCipherSuites: h2.PermitProhibitedCipherSuites, | ||||
| 		CountError:                   h2.CountError, | ||||
| 	} | ||||
| 	fillNetHTTPServerConfig(&conf, h1) | ||||
| 	setConfigDefaults(&conf, true) | ||||
| 	return conf | ||||
| } | ||||
| 
 | ||||
| // configFromServer merges configuration settings from h2 and h2.t1.HTTP2
 | ||||
| // (the net/http Transport).
 | ||||
| func configFromTransport(h2 *Transport) http2Config { | ||||
| 	conf := http2Config{ | ||||
| 		MaxEncoderHeaderTableSize: h2.MaxEncoderHeaderTableSize, | ||||
| 		MaxDecoderHeaderTableSize: h2.MaxDecoderHeaderTableSize, | ||||
| 		MaxReadFrameSize:          h2.MaxReadFrameSize, | ||||
| 		SendPingTimeout:           h2.ReadIdleTimeout, | ||||
| 		PingTimeout:               h2.PingTimeout, | ||||
| 		WriteByteTimeout:          h2.WriteByteTimeout, | ||||
| 	} | ||||
| 
 | ||||
| 	// Unlike most config fields, where out-of-range values revert to the default,
 | ||||
| 	// Transport.MaxReadFrameSize clips.
 | ||||
| 	if conf.MaxReadFrameSize < minMaxFrameSize { | ||||
| 		conf.MaxReadFrameSize = minMaxFrameSize | ||||
| 	} else if conf.MaxReadFrameSize > maxFrameSize { | ||||
| 		conf.MaxReadFrameSize = maxFrameSize | ||||
| 	} | ||||
| 
 | ||||
| 	if h2.t1 != nil { | ||||
| 		fillNetHTTPTransportConfig(&conf, h2.t1) | ||||
| 	} | ||||
| 	setConfigDefaults(&conf, false) | ||||
| 	return conf | ||||
| } | ||||
| 
 | ||||
| func setDefault[T ~int | ~int32 | ~uint32 | ~int64](v *T, minval, maxval, defval T) { | ||||
| 	if *v < minval || *v > maxval { | ||||
| 		*v = defval | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func setConfigDefaults(conf *http2Config, server bool) { | ||||
| 	setDefault(&conf.MaxConcurrentStreams, 1, math.MaxUint32, defaultMaxStreams) | ||||
| 	setDefault(&conf.MaxEncoderHeaderTableSize, 1, math.MaxUint32, initialHeaderTableSize) | ||||
| 	setDefault(&conf.MaxDecoderHeaderTableSize, 1, math.MaxUint32, initialHeaderTableSize) | ||||
| 	if server { | ||||
| 		setDefault(&conf.MaxUploadBufferPerConnection, initialWindowSize, math.MaxInt32, 1<<20) | ||||
| 	} else { | ||||
| 		setDefault(&conf.MaxUploadBufferPerConnection, initialWindowSize, math.MaxInt32, transportDefaultConnFlow) | ||||
| 	} | ||||
| 	if server { | ||||
| 		setDefault(&conf.MaxUploadBufferPerStream, 1, math.MaxInt32, 1<<20) | ||||
| 	} else { | ||||
| 		setDefault(&conf.MaxUploadBufferPerStream, 1, math.MaxInt32, transportDefaultStreamFlow) | ||||
| 	} | ||||
| 	setDefault(&conf.MaxReadFrameSize, minMaxFrameSize, maxFrameSize, defaultMaxReadFrameSize) | ||||
| 	setDefault(&conf.PingTimeout, 1, math.MaxInt64, 15*time.Second) | ||||
| } | ||||
| 
 | ||||
| // adjustHTTP1MaxHeaderSize converts a limit in bytes on the size of an HTTP/1 header
 | ||||
| // to an HTTP/2 MAX_HEADER_LIST_SIZE value.
 | ||||
| func adjustHTTP1MaxHeaderSize(n int64) int64 { | ||||
| 	// http2's count is in a slightly different unit and includes 32 bytes per pair.
 | ||||
| 	// So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
 | ||||
| 	const perFieldOverhead = 32 // per http2 spec
 | ||||
| 	const typicalHeaders = 10   // conservative
 | ||||
| 	return n + typicalHeaders*perFieldOverhead | ||||
| } | ||||
|  | @ -0,0 +1,61 @@ | |||
| // Copyright 2024 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.
 | ||||
| 
 | ||||
| //go:build go1.24
 | ||||
| 
 | ||||
| package http2 | ||||
| 
 | ||||
| import "net/http" | ||||
| 
 | ||||
| // fillNetHTTPServerConfig sets fields in conf from srv.HTTP2.
 | ||||
| func fillNetHTTPServerConfig(conf *http2Config, srv *http.Server) { | ||||
| 	fillNetHTTPConfig(conf, srv.HTTP2) | ||||
| } | ||||
| 
 | ||||
| // fillNetHTTPServerConfig sets fields in conf from tr.HTTP2.
 | ||||
| func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) { | ||||
| 	fillNetHTTPConfig(conf, tr.HTTP2) | ||||
| } | ||||
| 
 | ||||
| func fillNetHTTPConfig(conf *http2Config, h2 *http.HTTP2Config) { | ||||
| 	if h2 == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if h2.MaxConcurrentStreams != 0 { | ||||
| 		conf.MaxConcurrentStreams = uint32(h2.MaxConcurrentStreams) | ||||
| 	} | ||||
| 	if h2.MaxEncoderHeaderTableSize != 0 { | ||||
| 		conf.MaxEncoderHeaderTableSize = uint32(h2.MaxEncoderHeaderTableSize) | ||||
| 	} | ||||
| 	if h2.MaxDecoderHeaderTableSize != 0 { | ||||
| 		conf.MaxDecoderHeaderTableSize = uint32(h2.MaxDecoderHeaderTableSize) | ||||
| 	} | ||||
| 	if h2.MaxConcurrentStreams != 0 { | ||||
| 		conf.MaxConcurrentStreams = uint32(h2.MaxConcurrentStreams) | ||||
| 	} | ||||
| 	if h2.MaxReadFrameSize != 0 { | ||||
| 		conf.MaxReadFrameSize = uint32(h2.MaxReadFrameSize) | ||||
| 	} | ||||
| 	if h2.MaxReceiveBufferPerConnection != 0 { | ||||
| 		conf.MaxUploadBufferPerConnection = int32(h2.MaxReceiveBufferPerConnection) | ||||
| 	} | ||||
| 	if h2.MaxReceiveBufferPerStream != 0 { | ||||
| 		conf.MaxUploadBufferPerStream = int32(h2.MaxReceiveBufferPerStream) | ||||
| 	} | ||||
| 	if h2.SendPingTimeout != 0 { | ||||
| 		conf.SendPingTimeout = h2.SendPingTimeout | ||||
| 	} | ||||
| 	if h2.PingTimeout != 0 { | ||||
| 		conf.PingTimeout = h2.PingTimeout | ||||
| 	} | ||||
| 	if h2.WriteByteTimeout != 0 { | ||||
| 		conf.WriteByteTimeout = h2.WriteByteTimeout | ||||
| 	} | ||||
| 	if h2.PermitProhibitedCipherSuites { | ||||
| 		conf.PermitProhibitedCipherSuites = true | ||||
| 	} | ||||
| 	if h2.CountError != nil { | ||||
| 		conf.CountError = h2.CountError | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,16 @@ | |||
| // Copyright 2024 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.
 | ||||
| 
 | ||||
| //go:build !go1.24
 | ||||
| 
 | ||||
| package http2 | ||||
| 
 | ||||
| import "net/http" | ||||
| 
 | ||||
| // Pre-Go 1.24 fallback.
 | ||||
| // The Server.HTTP2 and Transport.HTTP2 config fields were added in Go 1.24.
 | ||||
| 
 | ||||
| func fillNetHTTPServerConfig(conf *http2Config, srv *http.Server) {} | ||||
| 
 | ||||
| func fillNetHTTPTransportConfig(conf *http2Config, tr *http.Transport) {} | ||||
|  | @ -19,8 +19,9 @@ import ( | |||
| 	"bufio" | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"sort" | ||||
|  | @ -237,13 +238,19 @@ func (cw closeWaiter) Wait() { | |||
| // Its buffered writer is lazily allocated as needed, to minimize
 | ||||
| // idle memory usage with many connections.
 | ||||
| type bufferedWriter struct { | ||||
| 	_  incomparable | ||||
| 	w  io.Writer     // immutable
 | ||||
| 	bw *bufio.Writer // non-nil when data is buffered
 | ||||
| 	_           incomparable | ||||
| 	group       synctestGroupInterface // immutable
 | ||||
| 	conn        net.Conn               // immutable
 | ||||
| 	bw          *bufio.Writer          // non-nil when data is buffered
 | ||||
| 	byteTimeout time.Duration          // immutable, WriteByteTimeout
 | ||||
| } | ||||
| 
 | ||||
| func newBufferedWriter(w io.Writer) *bufferedWriter { | ||||
| 	return &bufferedWriter{w: w} | ||||
| func newBufferedWriter(group synctestGroupInterface, conn net.Conn, timeout time.Duration) *bufferedWriter { | ||||
| 	return &bufferedWriter{ | ||||
| 		group:       group, | ||||
| 		conn:        conn, | ||||
| 		byteTimeout: timeout, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // bufWriterPoolBufferSize is the size of bufio.Writer's
 | ||||
|  | @ -270,7 +277,7 @@ func (w *bufferedWriter) Available() int { | |||
| func (w *bufferedWriter) Write(p []byte) (n int, err error) { | ||||
| 	if w.bw == nil { | ||||
| 		bw := bufWriterPool.Get().(*bufio.Writer) | ||||
| 		bw.Reset(w.w) | ||||
| 		bw.Reset((*bufferedWriterTimeoutWriter)(w)) | ||||
| 		w.bw = bw | ||||
| 	} | ||||
| 	return w.bw.Write(p) | ||||
|  | @ -288,6 +295,38 @@ func (w *bufferedWriter) Flush() error { | |||
| 	return err | ||||
| } | ||||
| 
 | ||||
| type bufferedWriterTimeoutWriter bufferedWriter | ||||
| 
 | ||||
| func (w *bufferedWriterTimeoutWriter) Write(p []byte) (n int, err error) { | ||||
| 	return writeWithByteTimeout(w.group, w.conn, w.byteTimeout, p) | ||||
| } | ||||
| 
 | ||||
| // writeWithByteTimeout writes to conn.
 | ||||
| // If more than timeout passes without any bytes being written to the connection,
 | ||||
| // the write fails.
 | ||||
| func writeWithByteTimeout(group synctestGroupInterface, conn net.Conn, timeout time.Duration, p []byte) (n int, err error) { | ||||
| 	if timeout <= 0 { | ||||
| 		return conn.Write(p) | ||||
| 	} | ||||
| 	for { | ||||
| 		var now time.Time | ||||
| 		if group == nil { | ||||
| 			now = time.Now() | ||||
| 		} else { | ||||
| 			now = group.Now() | ||||
| 		} | ||||
| 		conn.SetWriteDeadline(now.Add(timeout)) | ||||
| 		nn, err := conn.Write(p[n:]) | ||||
| 		n += nn | ||||
| 		if n == len(p) || nn == 0 || !errors.Is(err, os.ErrDeadlineExceeded) { | ||||
| 			// Either we finished the write, made no progress, or hit the deadline.
 | ||||
| 			// Whichever it is, we're done now.
 | ||||
| 			conn.SetWriteDeadline(time.Time{}) | ||||
| 			return n, err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func mustUint31(v int32) uint32 { | ||||
| 	if v < 0 || v > 2147483647 { | ||||
| 		panic("out of range") | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ import ( | |||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
|  | @ -52,10 +53,14 @@ import ( | |||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	prefaceTimeout         = 10 * time.Second | ||||
| 	firstSettingsTimeout   = 2 * time.Second // should be in-flight with preface anyway
 | ||||
| 	handlerChunkWriteSize  = 4 << 10 | ||||
| 	defaultMaxStreams      = 250 // TODO: make this 100 as the GFE seems to?
 | ||||
| 	prefaceTimeout        = 10 * time.Second | ||||
| 	firstSettingsTimeout  = 2 * time.Second // should be in-flight with preface anyway
 | ||||
| 	handlerChunkWriteSize = 4 << 10 | ||||
| 	defaultMaxStreams     = 250 // TODO: make this 100 as the GFE seems to?
 | ||||
| 
 | ||||
| 	// maxQueuedControlFrames is the maximum number of control frames like
 | ||||
| 	// SETTINGS, PING and RST_STREAM that will be queued for writing before
 | ||||
| 	// the connection is closed to prevent memory exhaustion attacks.
 | ||||
| 	maxQueuedControlFrames = 10000 | ||||
| ) | ||||
| 
 | ||||
|  | @ -127,6 +132,22 @@ type Server struct { | |||
| 	// If zero or negative, there is no timeout.
 | ||||
| 	IdleTimeout time.Duration | ||||
| 
 | ||||
| 	// ReadIdleTimeout is the timeout after which a health check using a ping
 | ||||
| 	// frame will be carried out if no frame is received on the connection.
 | ||||
| 	// If zero, no health check is performed.
 | ||||
| 	ReadIdleTimeout time.Duration | ||||
| 
 | ||||
| 	// PingTimeout is the timeout after which the connection will be closed
 | ||||
| 	// if a response to a ping is not received.
 | ||||
| 	// If zero, a default of 15 seconds is used.
 | ||||
| 	PingTimeout time.Duration | ||||
| 
 | ||||
| 	// WriteByteTimeout is the timeout after which a connection will be
 | ||||
| 	// closed if no data can be written to it. The timeout begins when data is
 | ||||
| 	// available to write, and is extended whenever any bytes are written.
 | ||||
| 	// If zero or negative, there is no timeout.
 | ||||
| 	WriteByteTimeout time.Duration | ||||
| 
 | ||||
| 	// MaxUploadBufferPerConnection is the size of the initial flow
 | ||||
| 	// control window for each connections. The HTTP/2 spec does not
 | ||||
| 	// allow this to be smaller than 65535 or larger than 2^32-1.
 | ||||
|  | @ -189,57 +210,6 @@ func (s *Server) afterFunc(d time.Duration, f func()) timer { | |||
| 	return timeTimer{time.AfterFunc(d, f)} | ||||
| } | ||||
| 
 | ||||
| func (s *Server) initialConnRecvWindowSize() int32 { | ||||
| 	if s.MaxUploadBufferPerConnection >= initialWindowSize { | ||||
| 		return s.MaxUploadBufferPerConnection | ||||
| 	} | ||||
| 	return 1 << 20 | ||||
| } | ||||
| 
 | ||||
| func (s *Server) initialStreamRecvWindowSize() int32 { | ||||
| 	if s.MaxUploadBufferPerStream > 0 { | ||||
| 		return s.MaxUploadBufferPerStream | ||||
| 	} | ||||
| 	return 1 << 20 | ||||
| } | ||||
| 
 | ||||
| func (s *Server) maxReadFrameSize() uint32 { | ||||
| 	if v := s.MaxReadFrameSize; v >= minMaxFrameSize && v <= maxFrameSize { | ||||
| 		return v | ||||
| 	} | ||||
| 	return defaultMaxReadFrameSize | ||||
| } | ||||
| 
 | ||||
| func (s *Server) maxConcurrentStreams() uint32 { | ||||
| 	if v := s.MaxConcurrentStreams; v > 0 { | ||||
| 		return v | ||||
| 	} | ||||
| 	return defaultMaxStreams | ||||
| } | ||||
| 
 | ||||
| func (s *Server) maxDecoderHeaderTableSize() uint32 { | ||||
| 	if v := s.MaxDecoderHeaderTableSize; v > 0 { | ||||
| 		return v | ||||
| 	} | ||||
| 	return initialHeaderTableSize | ||||
| } | ||||
| 
 | ||||
| func (s *Server) maxEncoderHeaderTableSize() uint32 { | ||||
| 	if v := s.MaxEncoderHeaderTableSize; v > 0 { | ||||
| 		return v | ||||
| 	} | ||||
| 	return initialHeaderTableSize | ||||
| } | ||||
| 
 | ||||
| // maxQueuedControlFrames is the maximum number of control frames like
 | ||||
| // SETTINGS, PING and RST_STREAM that will be queued for writing before
 | ||||
| // the connection is closed to prevent memory exhaustion attacks.
 | ||||
| func (s *Server) maxQueuedControlFrames() int { | ||||
| 	// TODO: if anybody asks, add a Server field, and remember to define the
 | ||||
| 	// behavior of negative values.
 | ||||
| 	return maxQueuedControlFrames | ||||
| } | ||||
| 
 | ||||
| type serverInternalState struct { | ||||
| 	mu          sync.Mutex | ||||
| 	activeConns map[*serverConn]struct{} | ||||
|  | @ -440,13 +410,15 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon | |||
| 	baseCtx, cancel := serverConnBaseContext(c, opts) | ||||
| 	defer cancel() | ||||
| 
 | ||||
| 	http1srv := opts.baseConfig() | ||||
| 	conf := configFromServer(http1srv, s) | ||||
| 	sc := &serverConn{ | ||||
| 		srv:                         s, | ||||
| 		hs:                          opts.baseConfig(), | ||||
| 		hs:                          http1srv, | ||||
| 		conn:                        c, | ||||
| 		baseCtx:                     baseCtx, | ||||
| 		remoteAddrStr:               c.RemoteAddr().String(), | ||||
| 		bw:                          newBufferedWriter(c), | ||||
| 		bw:                          newBufferedWriter(s.group, c, conf.WriteByteTimeout), | ||||
| 		handler:                     opts.handler(), | ||||
| 		streams:                     make(map[uint32]*stream), | ||||
| 		readFrameCh:                 make(chan readFrameResult), | ||||
|  | @ -456,9 +428,12 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon | |||
| 		bodyReadCh:                  make(chan bodyReadMsg),         // buffering doesn't matter either way
 | ||||
| 		doneServing:                 make(chan struct{}), | ||||
| 		clientMaxStreams:            math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value"
 | ||||
| 		advMaxStreams:               s.maxConcurrentStreams(), | ||||
| 		advMaxStreams:               conf.MaxConcurrentStreams, | ||||
| 		initialStreamSendWindowSize: initialWindowSize, | ||||
| 		initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream, | ||||
| 		maxFrameSize:                initialMaxFrameSize, | ||||
| 		pingTimeout:                 conf.PingTimeout, | ||||
| 		countErrorFunc:              conf.CountError, | ||||
| 		serveG:                      newGoroutineLock(), | ||||
| 		pushEnabled:                 true, | ||||
| 		sawClientPreface:            opts.SawClientPreface, | ||||
|  | @ -491,15 +466,15 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon | |||
| 	sc.flow.add(initialWindowSize) | ||||
| 	sc.inflow.init(initialWindowSize) | ||||
| 	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf) | ||||
| 	sc.hpackEncoder.SetMaxDynamicTableSizeLimit(s.maxEncoderHeaderTableSize()) | ||||
| 	sc.hpackEncoder.SetMaxDynamicTableSizeLimit(conf.MaxEncoderHeaderTableSize) | ||||
| 
 | ||||
| 	fr := NewFramer(sc.bw, c) | ||||
| 	if s.CountError != nil { | ||||
| 		fr.countError = s.CountError | ||||
| 	if conf.CountError != nil { | ||||
| 		fr.countError = conf.CountError | ||||
| 	} | ||||
| 	fr.ReadMetaHeaders = hpack.NewDecoder(s.maxDecoderHeaderTableSize(), nil) | ||||
| 	fr.ReadMetaHeaders = hpack.NewDecoder(conf.MaxDecoderHeaderTableSize, nil) | ||||
| 	fr.MaxHeaderListSize = sc.maxHeaderListSize() | ||||
| 	fr.SetMaxReadFrameSize(s.maxReadFrameSize()) | ||||
| 	fr.SetMaxReadFrameSize(conf.MaxReadFrameSize) | ||||
| 	sc.framer = fr | ||||
| 
 | ||||
| 	if tc, ok := c.(connectionStater); ok { | ||||
|  | @ -532,7 +507,7 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon | |||
| 			// So for now, do nothing here again.
 | ||||
| 		} | ||||
| 
 | ||||
| 		if !s.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) { | ||||
| 		if !conf.PermitProhibitedCipherSuites && isBadCipher(sc.tlsState.CipherSuite) { | ||||
| 			// "Endpoints MAY choose to generate a connection error
 | ||||
| 			// (Section 5.4.1) of type INADEQUATE_SECURITY if one of
 | ||||
| 			// the prohibited cipher suites are negotiated."
 | ||||
|  | @ -569,7 +544,7 @@ func (s *Server) serveConn(c net.Conn, opts *ServeConnOpts, newf func(*serverCon | |||
| 		opts.UpgradeRequest = nil | ||||
| 	} | ||||
| 
 | ||||
| 	sc.serve() | ||||
| 	sc.serve(conf) | ||||
| } | ||||
| 
 | ||||
| func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) { | ||||
|  | @ -609,6 +584,7 @@ type serverConn struct { | |||
| 	tlsState         *tls.ConnectionState   // shared by all handlers, like net/http
 | ||||
| 	remoteAddrStr    string | ||||
| 	writeSched       WriteScheduler | ||||
| 	countErrorFunc   func(errType string) | ||||
| 
 | ||||
| 	// Everything following is owned by the serve loop; use serveG.check():
 | ||||
| 	serveG                      goroutineLock // used to verify funcs are on serve()
 | ||||
|  | @ -628,6 +604,7 @@ type serverConn struct { | |||
| 	streams                     map[uint32]*stream | ||||
| 	unstartedHandlers           []unstartedHandler | ||||
| 	initialStreamSendWindowSize int32 | ||||
| 	initialStreamRecvWindowSize int32 | ||||
| 	maxFrameSize                int32 | ||||
| 	peerMaxHeaderListSize       uint32            // zero means unknown (default)
 | ||||
| 	canonHeader                 map[string]string // http2-lower-case -> Go-Canonical-Case
 | ||||
|  | @ -638,9 +615,14 @@ type serverConn struct { | |||
| 	inGoAway                    bool              // we've started to or sent GOAWAY
 | ||||
| 	inFrameScheduleLoop         bool              // whether we're in the scheduleFrameWrite loop
 | ||||
| 	needToSendGoAway            bool              // we need to schedule a GOAWAY frame write
 | ||||
| 	pingSent                    bool | ||||
| 	sentPingData                [8]byte | ||||
| 	goAwayCode                  ErrCode | ||||
| 	shutdownTimer               timer // nil until used
 | ||||
| 	idleTimer                   timer // nil if unused
 | ||||
| 	readIdleTimeout             time.Duration | ||||
| 	pingTimeout                 time.Duration | ||||
| 	readIdleTimer               timer // nil if unused
 | ||||
| 
 | ||||
| 	// Owned by the writeFrameAsync goroutine:
 | ||||
| 	headerWriteBuf bytes.Buffer | ||||
|  | @ -655,11 +637,7 @@ func (sc *serverConn) maxHeaderListSize() uint32 { | |||
| 	if n <= 0 { | ||||
| 		n = http.DefaultMaxHeaderBytes | ||||
| 	} | ||||
| 	// http2's count is in a slightly different unit and includes 32 bytes per pair.
 | ||||
| 	// So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
 | ||||
| 	const perFieldOverhead = 32 // per http2 spec
 | ||||
| 	const typicalHeaders = 10   // conservative
 | ||||
| 	return uint32(n + typicalHeaders*perFieldOverhead) | ||||
| 	return uint32(adjustHTTP1MaxHeaderSize(int64(n))) | ||||
| } | ||||
| 
 | ||||
| func (sc *serverConn) curOpenStreams() uint32 { | ||||
|  | @ -923,7 +901,7 @@ func (sc *serverConn) notePanic() { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (sc *serverConn) serve() { | ||||
| func (sc *serverConn) serve(conf http2Config) { | ||||
| 	sc.serveG.check() | ||||
| 	defer sc.notePanic() | ||||
| 	defer sc.conn.Close() | ||||
|  | @ -937,18 +915,18 @@ func (sc *serverConn) serve() { | |||
| 
 | ||||
| 	sc.writeFrame(FrameWriteRequest{ | ||||
| 		write: writeSettings{ | ||||
| 			{SettingMaxFrameSize, sc.srv.maxReadFrameSize()}, | ||||
| 			{SettingMaxFrameSize, conf.MaxReadFrameSize}, | ||||
| 			{SettingMaxConcurrentStreams, sc.advMaxStreams}, | ||||
| 			{SettingMaxHeaderListSize, sc.maxHeaderListSize()}, | ||||
| 			{SettingHeaderTableSize, sc.srv.maxDecoderHeaderTableSize()}, | ||||
| 			{SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())}, | ||||
| 			{SettingHeaderTableSize, conf.MaxDecoderHeaderTableSize}, | ||||
| 			{SettingInitialWindowSize, uint32(sc.initialStreamRecvWindowSize)}, | ||||
| 		}, | ||||
| 	}) | ||||
| 	sc.unackedSettings++ | ||||
| 
 | ||||
| 	// Each connection starts with initialWindowSize inflow tokens.
 | ||||
| 	// If a higher value is configured, we add more tokens.
 | ||||
| 	if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 { | ||||
| 	if diff := conf.MaxUploadBufferPerConnection - initialWindowSize; diff > 0 { | ||||
| 		sc.sendWindowUpdate(nil, int(diff)) | ||||
| 	} | ||||
| 
 | ||||
|  | @ -968,11 +946,18 @@ func (sc *serverConn) serve() { | |||
| 		defer sc.idleTimer.Stop() | ||||
| 	} | ||||
| 
 | ||||
| 	if conf.SendPingTimeout > 0 { | ||||
| 		sc.readIdleTimeout = conf.SendPingTimeout | ||||
| 		sc.readIdleTimer = sc.srv.afterFunc(conf.SendPingTimeout, sc.onReadIdleTimer) | ||||
| 		defer sc.readIdleTimer.Stop() | ||||
| 	} | ||||
| 
 | ||||
| 	go sc.readFrames() // closed by defer sc.conn.Close above
 | ||||
| 
 | ||||
| 	settingsTimer := sc.srv.afterFunc(firstSettingsTimeout, sc.onSettingsTimer) | ||||
| 	defer settingsTimer.Stop() | ||||
| 
 | ||||
| 	lastFrameTime := sc.srv.now() | ||||
| 	loopNum := 0 | ||||
| 	for { | ||||
| 		loopNum++ | ||||
|  | @ -986,6 +971,7 @@ func (sc *serverConn) serve() { | |||
| 		case res := <-sc.wroteFrameCh: | ||||
| 			sc.wroteFrame(res) | ||||
| 		case res := <-sc.readFrameCh: | ||||
| 			lastFrameTime = sc.srv.now() | ||||
| 			// Process any written frames before reading new frames from the client since a
 | ||||
| 			// written frame could have triggered a new stream to be started.
 | ||||
| 			if sc.writingFrameAsync { | ||||
|  | @ -1017,6 +1003,8 @@ func (sc *serverConn) serve() { | |||
| 				case idleTimerMsg: | ||||
| 					sc.vlogf("connection is idle") | ||||
| 					sc.goAway(ErrCodeNo) | ||||
| 				case readIdleTimerMsg: | ||||
| 					sc.handlePingTimer(lastFrameTime) | ||||
| 				case shutdownTimerMsg: | ||||
| 					sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr()) | ||||
| 					return | ||||
|  | @ -1039,7 +1027,7 @@ func (sc *serverConn) serve() { | |||
| 		// If the peer is causing us to generate a lot of control frames,
 | ||||
| 		// but not reading them from us, assume they are trying to make us
 | ||||
| 		// run out of memory.
 | ||||
| 		if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() { | ||||
| 		if sc.queuedControlFrames > maxQueuedControlFrames { | ||||
| 			sc.vlogf("http2: too many control frames in send queue, closing connection") | ||||
| 			return | ||||
| 		} | ||||
|  | @ -1055,12 +1043,39 @@ func (sc *serverConn) serve() { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (sc *serverConn) handlePingTimer(lastFrameReadTime time.Time) { | ||||
| 	if sc.pingSent { | ||||
| 		sc.vlogf("timeout waiting for PING response") | ||||
| 		sc.conn.Close() | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	pingAt := lastFrameReadTime.Add(sc.readIdleTimeout) | ||||
| 	now := sc.srv.now() | ||||
| 	if pingAt.After(now) { | ||||
| 		// We received frames since arming the ping timer.
 | ||||
| 		// Reset it for the next possible timeout.
 | ||||
| 		sc.readIdleTimer.Reset(pingAt.Sub(now)) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	sc.pingSent = true | ||||
| 	// Ignore crypto/rand.Read errors: It generally can't fail, and worse case if it does
 | ||||
| 	// is we send a PING frame containing 0s.
 | ||||
| 	_, _ = rand.Read(sc.sentPingData[:]) | ||||
| 	sc.writeFrame(FrameWriteRequest{ | ||||
| 		write: &writePing{data: sc.sentPingData}, | ||||
| 	}) | ||||
| 	sc.readIdleTimer.Reset(sc.pingTimeout) | ||||
| } | ||||
| 
 | ||||
| type serverMessage int | ||||
| 
 | ||||
| // Message values sent to serveMsgCh.
 | ||||
| var ( | ||||
| 	settingsTimerMsg    = new(serverMessage) | ||||
| 	idleTimerMsg        = new(serverMessage) | ||||
| 	readIdleTimerMsg    = new(serverMessage) | ||||
| 	shutdownTimerMsg    = new(serverMessage) | ||||
| 	gracefulShutdownMsg = new(serverMessage) | ||||
| 	handlerDoneMsg      = new(serverMessage) | ||||
|  | @ -1068,6 +1083,7 @@ var ( | |||
| 
 | ||||
| func (sc *serverConn) onSettingsTimer() { sc.sendServeMsg(settingsTimerMsg) } | ||||
| func (sc *serverConn) onIdleTimer()     { sc.sendServeMsg(idleTimerMsg) } | ||||
| func (sc *serverConn) onReadIdleTimer() { sc.sendServeMsg(readIdleTimerMsg) } | ||||
| func (sc *serverConn) onShutdownTimer() { sc.sendServeMsg(shutdownTimerMsg) } | ||||
| 
 | ||||
| func (sc *serverConn) sendServeMsg(msg interface{}) { | ||||
|  | @ -1320,6 +1336,10 @@ func (sc *serverConn) wroteFrame(res frameWriteResult) { | |||
| 	sc.writingFrame = false | ||||
| 	sc.writingFrameAsync = false | ||||
| 
 | ||||
| 	if res.err != nil { | ||||
| 		sc.conn.Close() | ||||
| 	} | ||||
| 
 | ||||
| 	wr := res.wr | ||||
| 
 | ||||
| 	if writeEndsStream(wr.write) { | ||||
|  | @ -1594,6 +1614,11 @@ func (sc *serverConn) processFrame(f Frame) error { | |||
| func (sc *serverConn) processPing(f *PingFrame) error { | ||||
| 	sc.serveG.check() | ||||
| 	if f.IsAck() { | ||||
| 		if sc.pingSent && sc.sentPingData == f.Data { | ||||
| 			// This is a response to a PING we sent.
 | ||||
| 			sc.pingSent = false | ||||
| 			sc.readIdleTimer.Reset(sc.readIdleTimeout) | ||||
| 		} | ||||
| 		// 6.7 PING: " An endpoint MUST NOT respond to PING frames
 | ||||
| 		// containing this flag."
 | ||||
| 		return nil | ||||
|  | @ -2160,7 +2185,7 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream | |||
| 	st.cw.Init() | ||||
| 	st.flow.conn = &sc.flow // link to conn-level counter
 | ||||
| 	st.flow.add(sc.initialStreamSendWindowSize) | ||||
| 	st.inflow.init(sc.srv.initialStreamRecvWindowSize()) | ||||
| 	st.inflow.init(sc.initialStreamRecvWindowSize) | ||||
| 	if sc.hs.WriteTimeout > 0 { | ||||
| 		st.writeDeadline = sc.srv.afterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) | ||||
| 	} | ||||
|  | @ -3301,7 +3326,7 @@ func (sc *serverConn) countError(name string, err error) error { | |||
| 	if sc == nil || sc.srv == nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	f := sc.srv.CountError | ||||
| 	f := sc.countErrorFunc | ||||
| 	if f == nil { | ||||
| 		return err | ||||
| 	} | ||||
|  |  | |||
|  | @ -25,7 +25,6 @@ import ( | |||
| 	"net/http" | ||||
| 	"net/http/httptrace" | ||||
| 	"net/textproto" | ||||
| 	"os" | ||||
| 	"sort" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | @ -227,40 +226,26 @@ func (t *Transport) contextWithTimeout(ctx context.Context, d time.Duration) (co | |||
| } | ||||
| 
 | ||||
| func (t *Transport) maxHeaderListSize() uint32 { | ||||
| 	if t.MaxHeaderListSize == 0 { | ||||
| 	n := int64(t.MaxHeaderListSize) | ||||
| 	if t.t1 != nil && t.t1.MaxResponseHeaderBytes != 0 { | ||||
| 		n = t.t1.MaxResponseHeaderBytes | ||||
| 		if n > 0 { | ||||
| 			n = adjustHTTP1MaxHeaderSize(n) | ||||
| 		} | ||||
| 	} | ||||
| 	if n <= 0 { | ||||
| 		return 10 << 20 | ||||
| 	} | ||||
| 	if t.MaxHeaderListSize == 0xffffffff { | ||||
| 	if n >= 0xffffffff { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return t.MaxHeaderListSize | ||||
| } | ||||
| 
 | ||||
| func (t *Transport) maxFrameReadSize() uint32 { | ||||
| 	if t.MaxReadFrameSize == 0 { | ||||
| 		return 0 // use the default provided by the peer
 | ||||
| 	} | ||||
| 	if t.MaxReadFrameSize < minMaxFrameSize { | ||||
| 		return minMaxFrameSize | ||||
| 	} | ||||
| 	if t.MaxReadFrameSize > maxFrameSize { | ||||
| 		return maxFrameSize | ||||
| 	} | ||||
| 	return t.MaxReadFrameSize | ||||
| 	return uint32(n) | ||||
| } | ||||
| 
 | ||||
| func (t *Transport) disableCompression() bool { | ||||
| 	return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression) | ||||
| } | ||||
| 
 | ||||
| func (t *Transport) pingTimeout() time.Duration { | ||||
| 	if t.PingTimeout == 0 { | ||||
| 		return 15 * time.Second | ||||
| 	} | ||||
| 	return t.PingTimeout | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
 | ||||
| // It returns an error if t1 has already been HTTP/2-enabled.
 | ||||
| //
 | ||||
|  | @ -370,11 +355,14 @@ type ClientConn struct { | |||
| 	lastActive      time.Time | ||||
| 	lastIdle        time.Time // time last idle
 | ||||
| 	// Settings from peer: (also guarded by wmu)
 | ||||
| 	maxFrameSize           uint32 | ||||
| 	maxConcurrentStreams   uint32 | ||||
| 	peerMaxHeaderListSize  uint64 | ||||
| 	peerMaxHeaderTableSize uint32 | ||||
| 	initialWindowSize      uint32 | ||||
| 	maxFrameSize                uint32 | ||||
| 	maxConcurrentStreams        uint32 | ||||
| 	peerMaxHeaderListSize       uint64 | ||||
| 	peerMaxHeaderTableSize      uint32 | ||||
| 	initialWindowSize           uint32 | ||||
| 	initialStreamRecvWindowSize int32 | ||||
| 	readIdleTimeout             time.Duration | ||||
| 	pingTimeout                 time.Duration | ||||
| 
 | ||||
| 	// reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests.
 | ||||
| 	// Write to reqHeaderMu to lock it, read from it to unlock.
 | ||||
|  | @ -499,6 +487,7 @@ func (cs *clientStream) closeReqBodyLocked() { | |||
| } | ||||
| 
 | ||||
| type stickyErrWriter struct { | ||||
| 	group   synctestGroupInterface | ||||
| 	conn    net.Conn | ||||
| 	timeout time.Duration | ||||
| 	err     *error | ||||
|  | @ -508,22 +497,9 @@ func (sew stickyErrWriter) Write(p []byte) (n int, err error) { | |||
| 	if *sew.err != nil { | ||||
| 		return 0, *sew.err | ||||
| 	} | ||||
| 	for { | ||||
| 		if sew.timeout != 0 { | ||||
| 			sew.conn.SetWriteDeadline(time.Now().Add(sew.timeout)) | ||||
| 		} | ||||
| 		nn, err := sew.conn.Write(p[n:]) | ||||
| 		n += nn | ||||
| 		if n < len(p) && nn > 0 && errors.Is(err, os.ErrDeadlineExceeded) { | ||||
| 			// Keep extending the deadline so long as we're making progress.
 | ||||
| 			continue | ||||
| 		} | ||||
| 		if sew.timeout != 0 { | ||||
| 			sew.conn.SetWriteDeadline(time.Time{}) | ||||
| 		} | ||||
| 		*sew.err = err | ||||
| 		return n, err | ||||
| 	} | ||||
| 	n, err = writeWithByteTimeout(sew.group, sew.conn, sew.timeout, p) | ||||
| 	*sew.err = err | ||||
| 	return n, err | ||||
| } | ||||
| 
 | ||||
| // noCachedConnError is the concrete type of ErrNoCachedConn, which
 | ||||
|  | @ -758,44 +734,36 @@ func (t *Transport) expectContinueTimeout() time.Duration { | |||
| 	return t.t1.ExpectContinueTimeout | ||||
| } | ||||
| 
 | ||||
| func (t *Transport) maxDecoderHeaderTableSize() uint32 { | ||||
| 	if v := t.MaxDecoderHeaderTableSize; v > 0 { | ||||
| 		return v | ||||
| 	} | ||||
| 	return initialHeaderTableSize | ||||
| } | ||||
| 
 | ||||
| func (t *Transport) maxEncoderHeaderTableSize() uint32 { | ||||
| 	if v := t.MaxEncoderHeaderTableSize; v > 0 { | ||||
| 		return v | ||||
| 	} | ||||
| 	return initialHeaderTableSize | ||||
| } | ||||
| 
 | ||||
| func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) { | ||||
| 	return t.newClientConn(c, t.disableKeepAlives()) | ||||
| } | ||||
| 
 | ||||
| func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, error) { | ||||
| 	conf := configFromTransport(t) | ||||
| 	cc := &ClientConn{ | ||||
| 		t:                     t, | ||||
| 		tconn:                 c, | ||||
| 		readerDone:            make(chan struct{}), | ||||
| 		nextStreamID:          1, | ||||
| 		maxFrameSize:          16 << 10,                    // spec default
 | ||||
| 		initialWindowSize:     65535,                       // spec default
 | ||||
| 		maxConcurrentStreams:  initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings.
 | ||||
| 		peerMaxHeaderListSize: 0xffffffffffffffff,          // "infinite", per spec. Use 2^64-1 instead.
 | ||||
| 		streams:               make(map[uint32]*clientStream), | ||||
| 		singleUse:             singleUse, | ||||
| 		wantSettingsAck:       true, | ||||
| 		pings:                 make(map[[8]byte]chan struct{}), | ||||
| 		reqHeaderMu:           make(chan struct{}, 1), | ||||
| 		t:                           t, | ||||
| 		tconn:                       c, | ||||
| 		readerDone:                  make(chan struct{}), | ||||
| 		nextStreamID:                1, | ||||
| 		maxFrameSize:                16 << 10, // spec default
 | ||||
| 		initialWindowSize:           65535,    // spec default
 | ||||
| 		initialStreamRecvWindowSize: conf.MaxUploadBufferPerStream, | ||||
| 		maxConcurrentStreams:        initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings.
 | ||||
| 		peerMaxHeaderListSize:       0xffffffffffffffff,          // "infinite", per spec. Use 2^64-1 instead.
 | ||||
| 		streams:                     make(map[uint32]*clientStream), | ||||
| 		singleUse:                   singleUse, | ||||
| 		wantSettingsAck:             true, | ||||
| 		readIdleTimeout:             conf.SendPingTimeout, | ||||
| 		pingTimeout:                 conf.PingTimeout, | ||||
| 		pings:                       make(map[[8]byte]chan struct{}), | ||||
| 		reqHeaderMu:                 make(chan struct{}, 1), | ||||
| 	} | ||||
| 	var group synctestGroupInterface | ||||
| 	if t.transportTestHooks != nil { | ||||
| 		t.markNewGoroutine() | ||||
| 		t.transportTestHooks.newclientconn(cc) | ||||
| 		c = cc.tconn | ||||
| 		group = t.group | ||||
| 	} | ||||
| 	if VerboseLogs { | ||||
| 		t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr()) | ||||
|  | @ -807,24 +775,23 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
| 	// TODO: adjust this writer size to account for frame size +
 | ||||
| 	// MTU + crypto/tls record padding.
 | ||||
| 	cc.bw = bufio.NewWriter(stickyErrWriter{ | ||||
| 		group:   group, | ||||
| 		conn:    c, | ||||
| 		timeout: t.WriteByteTimeout, | ||||
| 		timeout: conf.WriteByteTimeout, | ||||
| 		err:     &cc.werr, | ||||
| 	}) | ||||
| 	cc.br = bufio.NewReader(c) | ||||
| 	cc.fr = NewFramer(cc.bw, cc.br) | ||||
| 	if t.maxFrameReadSize() != 0 { | ||||
| 		cc.fr.SetMaxReadFrameSize(t.maxFrameReadSize()) | ||||
| 	} | ||||
| 	cc.fr.SetMaxReadFrameSize(conf.MaxReadFrameSize) | ||||
| 	if t.CountError != nil { | ||||
| 		cc.fr.countError = t.CountError | ||||
| 	} | ||||
| 	maxHeaderTableSize := t.maxDecoderHeaderTableSize() | ||||
| 	maxHeaderTableSize := conf.MaxDecoderHeaderTableSize | ||||
| 	cc.fr.ReadMetaHeaders = hpack.NewDecoder(maxHeaderTableSize, nil) | ||||
| 	cc.fr.MaxHeaderListSize = t.maxHeaderListSize() | ||||
| 
 | ||||
| 	cc.henc = hpack.NewEncoder(&cc.hbuf) | ||||
| 	cc.henc.SetMaxDynamicTableSizeLimit(t.maxEncoderHeaderTableSize()) | ||||
| 	cc.henc.SetMaxDynamicTableSizeLimit(conf.MaxEncoderHeaderTableSize) | ||||
| 	cc.peerMaxHeaderTableSize = initialHeaderTableSize | ||||
| 
 | ||||
| 	if cs, ok := c.(connectionStater); ok { | ||||
|  | @ -834,11 +801,9 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
| 
 | ||||
| 	initialSettings := []Setting{ | ||||
| 		{ID: SettingEnablePush, Val: 0}, | ||||
| 		{ID: SettingInitialWindowSize, Val: transportDefaultStreamFlow}, | ||||
| 	} | ||||
| 	if max := t.maxFrameReadSize(); max != 0 { | ||||
| 		initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: max}) | ||||
| 		{ID: SettingInitialWindowSize, Val: uint32(cc.initialStreamRecvWindowSize)}, | ||||
| 	} | ||||
| 	initialSettings = append(initialSettings, Setting{ID: SettingMaxFrameSize, Val: conf.MaxReadFrameSize}) | ||||
| 	if max := t.maxHeaderListSize(); max != 0 { | ||||
| 		initialSettings = append(initialSettings, Setting{ID: SettingMaxHeaderListSize, Val: max}) | ||||
| 	} | ||||
|  | @ -848,8 +813,8 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
| 
 | ||||
| 	cc.bw.Write(clientPreface) | ||||
| 	cc.fr.WriteSettings(initialSettings...) | ||||
| 	cc.fr.WriteWindowUpdate(0, transportDefaultConnFlow) | ||||
| 	cc.inflow.init(transportDefaultConnFlow + initialWindowSize) | ||||
| 	cc.fr.WriteWindowUpdate(0, uint32(conf.MaxUploadBufferPerConnection)) | ||||
| 	cc.inflow.init(conf.MaxUploadBufferPerConnection + initialWindowSize) | ||||
| 	cc.bw.Flush() | ||||
| 	if cc.werr != nil { | ||||
| 		cc.Close() | ||||
|  | @ -867,7 +832,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
| } | ||||
| 
 | ||||
| func (cc *ClientConn) healthCheck() { | ||||
| 	pingTimeout := cc.t.pingTimeout() | ||||
| 	pingTimeout := cc.pingTimeout | ||||
| 	// We don't need to periodically ping in the health check, because the readLoop of ClientConn will
 | ||||
| 	// trigger the healthCheck again if there is no frame received.
 | ||||
| 	ctx, cancel := cc.t.contextWithTimeout(context.Background(), pingTimeout) | ||||
|  | @ -2199,7 +2164,7 @@ type resAndError struct { | |||
| func (cc *ClientConn) addStreamLocked(cs *clientStream) { | ||||
| 	cs.flow.add(int32(cc.initialWindowSize)) | ||||
| 	cs.flow.setConnFlow(&cc.flow) | ||||
| 	cs.inflow.init(transportDefaultStreamFlow) | ||||
| 	cs.inflow.init(cc.initialStreamRecvWindowSize) | ||||
| 	cs.ID = cc.nextStreamID | ||||
| 	cc.nextStreamID += 2 | ||||
| 	cc.streams[cs.ID] = cs | ||||
|  | @ -2345,7 +2310,7 @@ func (cc *ClientConn) countReadFrameError(err error) { | |||
| func (rl *clientConnReadLoop) run() error { | ||||
| 	cc := rl.cc | ||||
| 	gotSettings := false | ||||
| 	readIdleTimeout := cc.t.ReadIdleTimeout | ||||
| 	readIdleTimeout := cc.readIdleTimeout | ||||
| 	var t timer | ||||
| 	if readIdleTimeout != 0 { | ||||
| 		t = cc.t.afterFunc(readIdleTimeout, cc.healthCheck) | ||||
|  |  | |||
|  | @ -131,6 +131,16 @@ func (se StreamError) writeFrame(ctx writeContext) error { | |||
| 
 | ||||
| func (se StreamError) staysWithinBuffer(max int) bool { return frameHeaderLen+4 <= max } | ||||
| 
 | ||||
| type writePing struct { | ||||
| 	data [8]byte | ||||
| } | ||||
| 
 | ||||
| func (w writePing) writeFrame(ctx writeContext) error { | ||||
| 	return ctx.Framer().WritePing(false, w.data) | ||||
| } | ||||
| 
 | ||||
| func (w writePing) staysWithinBuffer(max int) bool { return frameHeaderLen+len(w.data) <= max } | ||||
| 
 | ||||
| type writePingAck struct{ pf *PingFrame } | ||||
| 
 | ||||
| func (w writePingAck) writeFrame(ctx writeContext) error { | ||||
|  |  | |||
|  | @ -1194,7 +1194,7 @@ golang.org/x/exp/slices | |||
| ## explicit; go 1.22.0 | ||||
| golang.org/x/mod/semver | ||||
| golang.org/x/mod/sumdb/note | ||||
| # golang.org/x/net v0.29.0 | ||||
| # golang.org/x/net v0.30.0 | ||||
| ## explicit; go 1.18 | ||||
| golang.org/x/net/bpf | ||||
| golang.org/x/net/context | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue