Source File
transport_common.go
Belonging Package
golang.org/x/net/http2
// Copyright 2026 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 http2import (mathrand)// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.// It returns an error if t1 has already been HTTP/2-enabled.//// Use ConfigureTransports instead to configure the HTTP/2 Transport.func ( *http.Transport) error {return configureTransport()}// ConfigureTransports configures a net/http HTTP/1 Transport to use HTTP/2.// It returns a new HTTP/2 Transport for further configuration.// It returns an error if t1 has already been HTTP/2-enabled.func ( *http.Transport) (*Transport, error) {return configureTransports()}// Transport is an HTTP/2 Transport.//// A Transport internally caches connections to servers. It is safe// for concurrent use by multiple goroutines.type Transport struct {// DialTLSContext specifies an optional dial function with context for// creating TLS connections for requests.//// If DialTLSContext and DialTLS is nil, tls.Dial is used.//// If the returned net.Conn has a ConnectionState method like tls.Conn,// it will be used to set http.Response.TLS.DialTLSContext func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error)// DialTLS specifies an optional dial function for creating// TLS connections for requests.//// If DialTLSContext and DialTLS is nil, tls.Dial is used.//// Deprecated: Use DialTLSContext instead, which allows the transport// to cancel dials as soon as they are no longer needed.// If both are set, DialTLSContext takes priority.DialTLS func(network, addr string, cfg *tls.Config) (net.Conn, error)// TLSClientConfig specifies the TLS configuration to use with// tls.Client. If nil, the default configuration is used.TLSClientConfig *tls.Config// ConnPool optionally specifies an alternate connection pool to use.// If nil, the default is used.ConnPool ClientConnPool// DisableCompression, if true, prevents the Transport from// requesting compression with an "Accept-Encoding: gzip"// request header when the Request contains no existing// Accept-Encoding value. If the Transport requests gzip on// its own and gets a gzipped response, it's transparently// decoded in the Response.Body. However, if the user// explicitly requested gzip it is not automatically// uncompressed.DisableCompression bool// AllowHTTP, if true, permits HTTP/2 requests using the insecure,// plain-text "http" scheme. Note that this does not enable h2c support.AllowHTTP bool// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to// send in the initial settings frame. It is how many bytes// of response headers are allowed. Unlike the http2 spec, zero here// means to use a default limit (currently 10MB). If you actually// want to advertise an unlimited value to the peer, Transport// interprets the highest possible value here (0xffffffff or 1<<32-1)// to mean no limit.MaxHeaderListSize uint32// MaxReadFrameSize is the http2 SETTINGS_MAX_FRAME_SIZE to send in the// initial settings frame. It is the size in bytes of the largest frame// payload that the sender is willing to receive. If 0, no setting is// sent, and the value is provided by the peer, which should be 16384// according to the spec:// https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2.// Values are bounded in the range 16k to 16M.MaxReadFrameSize uint32// MaxDecoderHeaderTableSize optionally specifies the http2// SETTINGS_HEADER_TABLE_SIZE to send in the initial settings frame. It// informs the remote endpoint of the maximum size of the header compression// table used to decode header blocks, in octets. If zero, the default value// of 4096 is used.MaxDecoderHeaderTableSize uint32// MaxEncoderHeaderTableSize optionally specifies an upper limit for the// header compression table used for encoding request headers. Received// SETTINGS_HEADER_TABLE_SIZE settings are capped at this limit. If zero,// the default value of 4096 is used.MaxEncoderHeaderTableSize uint32// StrictMaxConcurrentStreams controls whether the server's// SETTINGS_MAX_CONCURRENT_STREAMS should be respected// globally. If false, new TCP connections are created to the// server as needed to keep each under the per-connection// SETTINGS_MAX_CONCURRENT_STREAMS limit. If true, the// server's SETTINGS_MAX_CONCURRENT_STREAMS is interpreted as// a global limit and callers of RoundTrip block when needed,// waiting for their turn.StrictMaxConcurrentStreams bool// IdleConnTimeout is the maximum amount of time an idle// (keep-alive) connection will remain idle before closing// itself.// Zero means no limit.IdleConnTimeout time.Duration// ReadIdleTimeout is the timeout after which a health check using ping// frame will be carried out if no frame is received on the connection.// Note that a ping response will is considered a received frame, so if// there is no other traffic on the connection, the health check will// be performed every ReadIdleTimeout interval.// 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 Ping is not received.// Defaults to 15s.PingTimeout time.Duration// WriteByteTimeout is the timeout after which the connection will be// closed no data can be written to it. The timeout begins when data is// available to write, and is extended whenever any bytes are written.WriteByteTimeout time.Duration// CountError, if non-nil, is called on HTTP/2 transport errors.// It's intended to increment a metric for monitoring, such// as an expvar or Prometheus metric.// The errType consists of only ASCII word characters.CountError func(errType string)// Internal state, differs between wrapped and non-wrapped implementations.transportInternal}var (errClientConnClosed = errors.New("http2: client conn is closed")errClientConnNotEstablished = errors.New("http2: client conn could not be established")errClientConnGotGoAway = errors.New("http2: Transport received Server's graceful shutdown GOAWAY")errClientConnForceClosed = errors.New("http2: client connection force closed via ClientConn.Close")errClientConnUnusable = errors.New("http2: client conn not usable"))// ClientConnPool manages a pool of HTTP/2 client connections.type ClientConnPool interface {// GetClientConn returns a specific HTTP/2 connection (usually// a TLS-TCP connection) to an HTTP/2 server. On success, the// returned ClientConn accounts for the upcoming RoundTrip// call, so the caller should not omit it. If the caller needs// to, ClientConn.RoundTrip can be called with a bogus// new(http.Request) to release the stream reservation.GetClientConn(req *http.Request, addr string) (*ClientConn, error)MarkDead(*ClientConn)}// ClientConnState describes the state of a ClientConn.type ClientConnState struct {// Closed is whether the connection is closed.Closed bool// Closing is whether the connection is in the process of// closing. It may be closing due to shutdown, being a// single-use connection, being marked as DoNotReuse, or// having received a GOAWAY frame.Closing bool// StreamsActive is how many streams are active.StreamsActive int// StreamsReserved is how many streams have been reserved via// ClientConn.ReserveNewRequest.StreamsReserved int// StreamsPending is how many requests have been sent in excess// of the peer's advertised MaxConcurrentStreams setting and// are waiting for other streams to complete.StreamsPending int// MaxConcurrentStreams is how many concurrent streams the// peer advertised as acceptable. Zero means no SETTINGS// frame has been received yet.MaxConcurrentStreams uint32// LastIdle, if non-zero, is when the connection last// transitioned to idle state.LastIdle time.Time}// RoundTripOpt are options for the Transport.RoundTripOpt method.type RoundTripOpt struct {// OnlyCachedConn controls whether RoundTripOpt may// create a new TCP connection. If set true and// no cached connection is available, RoundTripOpt// will return ErrNoCachedConn.// OnlyCachedConn was broken in https://go.dev/cl/16699.OnlyCachedConn boolallowHTTP bool // allow http:// URLs}func ( *Transport) ( *http.Request) (*http.Response, error) {return .RoundTripOpt(, RoundTripOpt{})}// RoundTripOpt is like RoundTrip, but takes options.func ( *Transport) ( *http.Request, RoundTripOpt) (*http.Response, error) {return .roundTripOpt(, )}// CloseIdleConnections closes any connections which were previously// connected from previous requests but are now sitting idle.// It does not interrupt any connections currently in use.func ( *Transport) () {.closeIdleConnections()}func ( *Transport) ( net.Conn) (*ClientConn, error) {return .newUserClientConn()}// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)// and returns a host:port. The port 443 is added if needed.func ( string, string) ( string) {, , := net.SplitHostPort()if != nil { // authority didn't have a port== ""}if == "" { // authority's port was empty= "443"if == "http" {= "80"}}if , := idna.ToASCII(); == nil {=}// IPv6 address literal, without a port:if strings.HasPrefix(, "[") && strings.HasSuffix(, "]") {return + ":" +}return net.JoinHostPort(, )}func ( *Transport) ( *http.Request, RoundTripOpt, ClientConnPool) (*http.Response, error) {:= authorityAddr(.URL.Scheme, .URL.Host)for := 0; ; ++ {, := .GetClientConn(, )if != nil {.vlogf("http2: Transport failed to get client conn for %s: %v", , )return nil,}:= !atomic.CompareAndSwapUint32(&.atomicReused, 0, 1)traceGotConn(, , ), := .RoundTrip()if != nil && <= 6 {:=if , = shouldRetryRequest(, ); == nil {// After the first retry, do exponential backoff with 10% jitter.if == 0 {.vlogf("RoundTrip retrying after failure: %v", )continue}:= float64(uint(1) << (uint() - 1))+= * (0.1 * mathrand.Float64()):= time.Second * time.Duration():= time.NewTimer()select {case <-.C:.vlogf("RoundTrip retrying after failure: %v", )continuecase <-.Context().Done():.Stop()= .Context().Err()}}}if == errClientConnNotEstablished {// This ClientConn was created recently,// this is the first request to use it,// and the connection is closed and not usable.//// In this state, cc.idleTimer will remove the conn from the pool// when it fires. Stop the timer and remove it here so future requests// won't try to use this connection.//// If the timer has already fired and we're racing it, the redundant// call to MarkDead is harmless..stopIdleTimer().MarkDead()}if != nil {.vlogf("RoundTrip failure: %v", )return nil,}return , nil}}// shouldRetryRequest is called by RoundTrip when a request fails to get// response headers. It is always called with a non-nil error.// It returns either a request to retry (either the same request, or a// modified clone), or an error if the request can't be replayed.func ( *http.Request, error) (*http.Request, error) {if !canRetryError() {return nil,}// If the Body is nil (or http.NoBody), it's safe to reuse// this request and its Body.if .Body == nil || .Body == http.NoBody {return , nil}// If the request body can be reset back to its original// state via the optional req.GetBody, do that.if .GetBody != nil {, := .GetBody()if != nil {return nil,}:= *.Body =return &, nil}// The Request.Body can't reset back to the beginning, but we// don't seem to have started to read from it yet, so reuse// the request directly.if == errClientConnUnusable {return , nil}return nil, fmt.Errorf("http2: Transport: cannot retry err [%v] after Request.Body was written; define Request.GetBody to avoid this error", )}func ( error) bool {if == errClientConnUnusable || == errClientConnGotGoAway {return true}if , := .(StreamError); {return .Code == ErrCodeRefusedStream}return false}func ( *Transport) ( string, ...interface{}) {if VerboseLogs {.logf(, ...)}}func ( *Transport) ( string, ...interface{}) {log.Printf(, ...)}func ( *Transport) ( context.Context, , string, *tls.Config) (net.Conn, error) {if .DialTLSContext != nil {return .DialTLSContext(, , , )} else if .DialTLS != nil {return .DialTLS(, , )}, := .dialTLSWithContext(, , , )if != nil {return nil,}:= .ConnectionState()if := .NegotiatedProtocol; != NextProtoTLS {return nil, fmt.Errorf("http2: unexpected ALPN protocol %q; want %q", , NextProtoTLS)}if !.NegotiatedProtocolIsMutual {return nil, errors.New("http2: could not negotiate protocol mutually")}return , nil}// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS// connection.func ( *Transport) ( context.Context, , string, *tls.Config) (*tls.Conn, error) {:= &tls.Dialer{Config: ,}, := .DialContext(, , )if != nil {return nil,}:= .(*tls.Conn) // DialContext comment promises this will always succeedreturn , nil}// GoAwayError is returned by the Transport when the server closes the// TCP connection after sending a GOAWAY frame.type GoAwayError struct {LastStreamID uint32ErrCode ErrCodeDebugData string}func ( GoAwayError) () string {return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",.LastStreamID, .ErrCode, .DebugData)}// noCachedConnError is the concrete type of ErrNoCachedConn, which// needs to be detected by net/http regardless of whether it's its// bundled version (in h2_bundle.go with a rewritten type name) or// from a user's x/net/http2. As such, as it has a unique method name// (IsHTTP2NoCachedConnError) that net/http sniffs for via func// isNoCachedConnError.type noCachedConnError struct{}func (noCachedConnError) () {}func (noCachedConnError) () string { return "http2: no cached connection was available" }// isNoCachedConnError reports whether err is of type noCachedConnError// or its equivalent renamed type in net/http2's h2_bundle.go. Both types// may coexist in the same running program.func ( error) bool {, := .(interface{ () })return}var ErrNoCachedConn error = noCachedConnError{}
The pages are generated with Golds v0.8.4. (GOOS=linux GOARCH=amd64)