// 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.

//go:build !nethttpomithttp2

package http

import (
	
	
	
	
	
	
	
	

	_  // for go:linkname
)

// net/http supports HTTP/2 by default, but this support is removed when
// the nethttpomithttp2 build tag is set.
//
// HTTP/2 support is provided by the net/http/internal/http2 package.
//
// This file (http2.go) connects net/http to the http2 package.
// Since http imports http2, to avoid an import cycle we need to
// translate http package types (e.g., Request) into the equivalent
// http2 package types (e.g., http2.ClientRequest).
//
// The golang.org/x/net/http2 package is the original source of truth for
// the HTTP/2 implementation. At this time, users may still import that
// package and register its implementation on a net/http Transport or Server.
// However, the x/net package is no longer synchronized with std.

func () {
	// NoBody and LocalAddrContextKey need to have the same value
	// in the http and http2 packages.
	//
	// We can't define these values in net/http/internal,
	// because their concrete types are part of the net/http API and
	// moving them causes API checker failures.
	// Override the http2 package versions at init time instead.
	http2.LocalAddrContextKey = LocalAddrContextKey
	http2.NoBody = NoBody
}

type http2Server = http2.Server
type http2Transport = http2.Transport

func ( *Server) () {
	 := &http2.Server{}

	// Historically, we've configured the HTTP/2 idle timeout in this fashion:
	// Set once at configuration time.
	if .IdleTimeout != 0 {
		.h2IdleTimeout = .IdleTimeout
	} else {
		.h2IdleTimeout = .ReadTimeout
	}

	if .TLSConfig == nil {
		.TLSConfig = &tls.Config{}
	}
	.nextProtoErr = .Configure(http2ServerConfig{}, .TLSConfig)
	if .nextProtoErr != nil {
		return
	}

	.RegisterOnShutdown(.GracefulShutdown)

	if .TLSNextProto == nil {
		.TLSNextProto = make(map[string]func(*Server, *tls.Conn, Handler))
	}
	// Historically, the presence of a TLSNextProto["h2"] key has been the signal to
	// enable/disable HTTP/2 support. Set a value in the map, but we'll never use it.
	.TLSNextProto["h2"] = func( *Server,  *tls.Conn,  Handler) {
		.Close()
	}

	.h2 = 
}

func ( *Server) ( http2ExternalServerConfig) {
	if .h2Config != nil {
		panic("http: HTTP/2 Server already registered")
	}
	.h2Config = 
	.h2Config.ServeConnFunc(.serveHTTP2Conn)
	.configureHTTP2()
}

func ( *Server) ( context.Context,  net.Conn,  Handler,  bool,  *Request,  []byte) {
	.setupHTTP2_ServeTLS()
	var  *http2.ServerRequest
	if  != nil {
		 = http2ServerRequestFromRequest()
	}
	.SetReadDeadline(time.Time{})
	.SetWriteDeadline(time.Time{})
	.h2.ServeConn(, &http2.ServeConnOpts{
		Context:          ,
		Handler:          http2Handler{},
		BaseConfig:       http2ServerConfig{},
		SawClientPreface: ,
		UpgradeRequest:   ,
		Settings:         ,
	})
}

func ( *Request) *http2.ServerRequest {
	return &http2.ServerRequest{
		Context:       .Context(),
		Proto:         .Proto,
		ProtoMajor:    .ProtoMajor,
		ProtoMinor:    .ProtoMinor,
		Method:        .Method,
		URL:           .URL,
		Header:        http2.Header(.Header),
		Trailer:       http2.Header(.Trailer),
		Body:          .Body,
		Host:          .Host,
		ContentLength: .ContentLength,
		RemoteAddr:    .RemoteAddr,
		RequestURI:    .RequestURI,
		TLS:           .TLS,
		MultipartForm: .MultipartForm,
	}
}

type http2Handler struct {
	h Handler
}

func ( http2Handler) ( *http2.ResponseWriter,  *http2.ServerRequest) {
	.h.ServeHTTP(http2ResponseWriter{}, &Request{
		ctx:           .Context,
		Proto:         "HTTP/2.0",
		ProtoMajor:    2,
		ProtoMinor:    0,
		Method:        .Method,
		URL:           .URL,
		Header:        Header(.Header),
		RequestURI:    .RequestURI,
		Trailer:       Header(.Trailer),
		Body:          .Body,
		Host:          .Host,
		ContentLength: .ContentLength,
		RemoteAddr:    .RemoteAddr,
		TLS:           .TLS,
		MultipartForm: .MultipartForm,
	})
}

type http2ResponseWriter struct {
	*http2.ResponseWriter
}

// Optional http.ResponseWriter interfaces implemented.
var (
	_ CloseNotifier   = http2ResponseWriter{}
	_ Flusher         = http2ResponseWriter{}
	_ io.StringWriter = http2ResponseWriter{}
)

func ( http2ResponseWriter) ()            { .ResponseWriter.FlushError() }
func ( http2ResponseWriter) () error { return .ResponseWriter.FlushError() }

func ( http2ResponseWriter) () Header { return Header(.ResponseWriter.Header()) }

func ( http2ResponseWriter) ( string,  *PushOptions) error {
	var (
		 string
		 http2.Header
	)
	if  != nil {
		 = .Method
		 = http2.Header(.Header)
	}
	 := .ResponseWriter.Push(, , )
	if  == http2.ErrNotSupported {
		 = ErrNotSupported
	}
	return 
}

type http2ServerConfig struct {
	s *Server
}

func ( http2ServerConfig) () int      { return .s.MaxHeaderBytes }
func ( http2ServerConfig) () int { return .s.maxHeaderValueCount() }
func ( http2ServerConfig) ( net.Conn,  http2.ConnState) {
	if .s.ConnState != nil {
		.s.ConnState(, ConnState())
	}
}
func ( http2ServerConfig) () bool             { return .s.doKeepAlives() }
func ( http2ServerConfig) () time.Duration    { return .s.WriteTimeout }
func ( http2ServerConfig) () time.Duration { return .s.ReadTimeout }
func ( http2ServerConfig) () *log.Logger          { return .s.ErrorLog }
func ( http2ServerConfig) () time.Duration     { return .s.ReadTimeout }
func ( http2ServerConfig) () bool    { return .s.DisableClientPriority }

func ( http2ServerConfig) () time.Duration {
	if .s.h2Config != nil {
		return .s.h2Config.IdleTimeout()
	}
	return .s.h2IdleTimeout
}

func ( http2ServerConfig) () http2.Config {
	return mergeHTTP2Config(.s.HTTP2, .s.h2Config)
}

// http2ExternalServerConfig is an HTTP/2 configuration provided by x/net/http2.
//
// When a x/net/http2.Server wraps a net/http.Server, we need to support the user
// setting configuration settings on the x/net Server:
//
//	s1 := &http.Server{}
//	s2 := &http2.Server{}
//	http2.ConfigureServer(s1, s2)
//
//	// This setting needs to affect s1:
//	s2.MaxReadFrameSize = 10000
//
// We handle this by having http2.ConfigureServer pass us an http2ExternalServerConfig
// (see http.Server.Serve) which we can use to query the current state of the http2.Server.
type http2ExternalServerConfig interface {
	// Various configuration settings:
	HTTP2Config() HTTP2Config
	IdleTimeout() time.Duration

	// ServeConnFunc provides a function to the x/net/http2.Server which it
	// can use to serve a new connection.
	ServeConnFunc(func(ctx context.Context, nc net.Conn, h Handler, sawClientPreface bool, upgradeReq *Request, settings []byte))
}

// http2ExternalTransportConfig is an HTTP/2 configuration provided by x/net/http2.
//
// When a x/net/http2.Transport wraps a net/http.Transport, we need to support the user
// setting configuration settings on the x/net Transport:
//
//	tr1 := &http.Transport{}
//	tr2 := http2.ConfigureTransports(t1)
//
//	// This setting needs to affect tr1:
//	tr2.MaxHeaderListSize = 10000
//
// We handle this by having http2.ConfigureTransports pass us an http2ExternalTransportConfig,
// which we can use to query the current state of the http2.Transport.
type http2ExternalTransportConfig interface {
	// Various configuration settings:
	HTTP2Config() HTTP2Config
	DisableCompression() bool
	MaxHeaderListSize() int64
	IdleConnTimeout() time.Duration

	// ConnFromContext is used to pass a net.Conn to Transport.NewClientConn
	// via a context value. See Transport.http2NewClientConnFromContext.
	ConnFromContext(context.Context) net.Conn

	// DialFromContext is used to dial new connections, overriding Transport.DialContext etc.
	// This is used when the user calls x/net/http2.Transport.RoundTrip directly,
	// in which case the historical behavior is to use the http2.Transport's dial functions.
	DialFromContext(ctx context.Context, network, addr string) (net.Conn, error)

	// ExternalRoundTrip reports whether Transport.RoundTrip should call the
	// external transport's RoundTrip. This is used when x/net/http2.Transport.ConnPool
	// is set, in which case the user-provided ClientConnPool has taken responsibility
	// for picking a connection to use.
	ExternalRoundTrip() bool

	// RoundTrip performs a round trip.
	// It should only be used when ExternalRoundTrip requests it.
	RoundTrip(*Request) (*Response, error)

	// Registered is called to report successful registration of the config.
	Registered(*Transport)
}

func ( *Transport) ( Protocols) {
	if .TLSClientConfig == nil {
		.TLSClientConfig = &tls.Config{}
	}
	if .HTTP2 == nil {
		.HTTP2 = &HTTP2Config{}
	}
	 := http2.NewTransport(transportConfig{})
	.h2Transport = 

	.registerProtocol("https", http2RoundTripper{, true})
	if .TLSNextProto == nil {
		.TLSNextProto = make(map[string]func( string,  *tls.Conn) RoundTripper)
	}
	// Historically, the presence of a TLSNextProto["h2"] key has been the signal to
	// enable/disable HTTP/2 support. Set a value in the map, but we'll never use it.
	.TLSNextProto["h2"] = func( string,  *tls.Conn) RoundTripper {
		return http2ErringRoundTripper{
			errors.New("unexpected use of stub RoundTripper"),
		}
	}

	// Server.ServeTLS clones the tls.Config before modifying it.
	// Transport doesn't. We may want to make the two consistent some day.
	//
	// http2configureTransport will have already set NextProtos, but adjust it again
	// here to remove HTTP/1.1 if the user has disabled it.
	.TLSClientConfig.NextProtos = adjustNextProtos(.TLSClientConfig.NextProtos, )
}

type http2ErringRoundTripper struct{ err error }

func ( http2ErringRoundTripper) () error                   { return .err }
func ( http2ErringRoundTripper) (*Request) (*Response, error) { return nil, .err }

func ( *Request,  func(*http2.ClientRequest) (*http2.ClientResponse, error)) (*Response, error) {
	 := &Response{}
	,  := (&http2.ClientRequest{
		Context:       .Context(),
		Method:        .Method,
		URL:           .URL,
		Header:        http2.Header(.Header),
		Trailer:       http2.Header(.Trailer),
		Body:          .Body,
		Host:          .Host,
		GetBody:       .GetBody,
		ContentLength: .ContentLength,
		Cancel:        .Cancel,
		Close:         .Close,
		ResTrailer:    (*http2.Header)(&.Trailer),
	})
	if  != nil {
		return nil, 
	}
	.Status = .Status + " " + StatusText(.StatusCode)
	.StatusCode = .StatusCode
	.Proto = "HTTP/2.0"
	.ProtoMajor = 2
	.ProtoMinor = 0
	.ContentLength = .ContentLength
	.Uncompressed = .Uncompressed
	.Header = Header(.Header)
	.Trailer = Header(.Trailer)
	.Body = .Body
	.TLS = .TLS
	.Request = 
	return , nil
}

// http2AddConn adds nc to the HTTP/2 connection pool.
func ( *Transport) (,  string,  net.Conn) (RoundTripper, error) {
	if .h2Transport == nil {
		return nil, errors.ErrUnsupported
	}
	 := .h2Transport.AddConn(, , )
	if  != nil {
		return nil, 
	}
	return http2RoundTripper{.h2Transport, false}, nil
}

// http2NewClientConn creates an HTTP/2 genericClientConn (used to implement ClientConn) from nc.
// The connection is not added to the HTTP/2 connection pool.
func ( *Transport) ( net.Conn,  func()) (genericClientConn, error) {
	if .h2Transport == nil {
		return nil, errors.ErrUnsupported
	}
	,  := .h2Transport.NewClientConn(, )
	if  != nil {
		return nil, 
	}
	return http2ClientConn{}, nil
}

// http2NewClientConnFromContext creates a *ClientConn from a net.Conn.
//
// Transport.NewClientConn takes an address and dials a new net.Conn.
// We don't currently provide a simple way for the user to provide a net.Conn and get a
// *ClientConn out of it (although we do let the user provide their own Transport.DialContext,
// which can be used to effectively do this).
//
// x/net/http2.Transport.NewClientConn, in contrast, requires the user to provide a net.Conn.
// To support implementing the x/net/http2 NewClientConn in terms of a net/http.Transport,
// we permit x/net/http2 to pass us a net.Conn via a context key.
//
// http2NewClientConnFromContext handles extracting the net.Conn from the Context
// (when present) and creating a *ClientConn from it.
func ( *Transport) ( context.Context) (*ClientConn, error) {
	if .h2Config == nil {
		return nil, errors.ErrUnsupported
	}
	 := .h2Config.ConnFromContext()
	if  == nil {
		return nil, errors.ErrUnsupported
	}
	if .h2Transport == nil {
		return nil, errors.New("http: Transport does not support HTTP/2")
	}
	 := &ClientConn{}
	,  := .http2NewClientConn(, .maybeRunStateHook)
	if  != nil {
		return nil, 
	}
	.stateHookMu.Lock()
	defer .stateHookMu.Unlock()
	.cc = 
	.lastAvailable = .Available()
	return , nil
}

// http2ExternalDial creates a new HTTP/2 connection,
// using the x/net/http2.Transport's dial functions.
//
// This is used when the user has called x/net/http2.Transport.RoundTrip.
// If the RoundTrip needs to create a new connection,
// the historical behavior is for it to use the http2.Transport's DialTLS or DialTLSContext
// functions, and not any dial functions on the http.Transport.
func ( *Transport) ( context.Context,  connectMethod) (RoundTripper, error) {
	if .h2Config == nil {
		return nil, errors.ErrUnsupported
	}
	,  := .h2Config.DialFromContext(, "tcp", .targetAddr)
	if  != nil {
		return nil, 
	}
	return .http2AddConn(.targetScheme, .targetAddr, )
}

type http2RoundTripper struct {
	t                *http2.Transport
	mapCachedConnErr bool
}

func ( http2RoundTripper) ( *Request) (*Response, error) {
	,  := http2RoundTrip(, .t.RoundTrip)
	if  != nil {
		if .mapCachedConnErr && http2isNoCachedConnError() {
			 = ErrSkipAltProtocol
		}
		return nil, 
	}
	return , nil
}

type http2ClientConn struct {
	http2.NetHTTPClientConn
}

func ( http2ClientConn) ( *Request) (*Response, error) {
	return http2RoundTrip(, .NetHTTPClientConn.RoundTrip)
}

// transportConfig implements the http2.TransportConfig interface,
// providing the net/http Transport's configuration to the HTTP/2 implementation.
//
// When an x/net/http2 Transport has provided a configuration (see http2ExternalTransportConfig),
// the transportConfig merges the x/net/http2 and net/http Transport configurations.
type transportConfig struct {
	t *Transport
}

func ( transportConfig) () int64        { return .t.MaxResponseHeaderBytes }
func ( transportConfig) () bool              { return .t.DisableKeepAlives }
func ( transportConfig) () time.Duration { return .t.ExpectContinueTimeout }
func ( transportConfig) () time.Duration { return .t.ResponseHeaderTimeout }

func ( transportConfig) () int64 {
	if .t.h2Config != nil {
		return .t.h2Config.MaxHeaderListSize()
	}
	return 0
}

func ( transportConfig) () bool {
	if .t.h2Config != nil && .t.h2Config.DisableCompression() {
		return true
	}
	return .t.DisableCompression
}

func ( transportConfig) () time.Duration {
	// Unlike most config settings, historically IdleConnTimeout prefers the
	// http2.Transport's setting over the http.Transport.
	if .t.h2Config != nil {
		if  := .t.h2Config.IdleConnTimeout();  != 0 {
			return 
		}
	}
	return .t.IdleConnTimeout
}

type http2Configer interface {
	HTTP2Config() HTTP2Config
}

func ( *HTTP2Config,  http2Configer) http2.Config {
	if  == nil &&  == nil {
		return http2.Config{}
	}
	var  http2.Config
	if  != nil {
		 = (http2.Config)(*)
	}
	var  HTTP2Config
	if  != nil {
		 = .HTTP2Config()
	}
	if .MaxConcurrentStreams == 0 {
		.MaxConcurrentStreams = .MaxConcurrentStreams
	}
	if .StrictMaxConcurrentRequests {
		.StrictMaxConcurrentRequests = true
	}
	if .MaxDecoderHeaderTableSize == 0 {
		.MaxDecoderHeaderTableSize = .MaxDecoderHeaderTableSize
	}
	if .MaxEncoderHeaderTableSize == 0 {
		.MaxEncoderHeaderTableSize = .MaxEncoderHeaderTableSize
	}
	if .MaxReadFrameSize == 0 {
		.MaxReadFrameSize = .MaxReadFrameSize
	}
	if .MaxReceiveBufferPerConnection == 0 {
		.MaxReceiveBufferPerConnection = .MaxReceiveBufferPerConnection
	}
	if .MaxReceiveBufferPerStream == 0 {
		.MaxReceiveBufferPerStream = .MaxReceiveBufferPerStream
	}
	if .SendPingTimeout == 0 {
		.SendPingTimeout = .SendPingTimeout
	}
	if .PingTimeout == 0 {
		.PingTimeout = .PingTimeout
	}
	if .WriteByteTimeout == 0 {
		.WriteByteTimeout = .WriteByteTimeout
	}
	if .PermitProhibitedCipherSuites {
		.PermitProhibitedCipherSuites = true
	}
	if .CountError == nil {
		.CountError = .CountError
	}
	return 
}

func ( transportConfig) () http2.Config {
	return mergeHTTP2Config(.t.HTTP2, .t.h2Config)
}

// transportFromH1Transport provides a way for HTTP/2 tests to extract
// the http2.Transport from an http.Transport.
//
//go:linkname transportFromH1Transport net/http/internal/http2_test.transportFromH1Transport
func ( *Transport) any {
	.nextProtoOnce.Do(.onceSetNextProtoDefaults)
	return .h2Transport
}