package http3

import (
	
	
	
	
	
	
	
	
	
	
	
	
	

	
	
	
)

// NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2.
const NextProtoH3 = "h3"

// StreamType is the stream type of a unidirectional stream.
type StreamType uint64

const (
	streamTypeControlStream      = 0
	streamTypePushStream         = 1
	streamTypeQPACKEncoderStream = 2
	streamTypeQPACKDecoderStream = 3
)

// A QUICListener listens for incoming QUIC connections.
type QUICListener interface {
	Accept(context.Context) (*quic.Conn, error)
	Addr() net.Addr
	io.Closer
}

var _ QUICListener = &quic.EarlyListener{}

// ConfigureTLSConfig creates a new tls.Config which can be used
// to create a quic.Listener meant for serving HTTP/3.
func ( *tls.Config) *tls.Config {
	// Workaround for https://github.com/golang/go/issues/60506.
	// This initializes the session tickets _before_ cloning the config.
	_, _ = .DecryptTicket(nil, tls.ConnectionState{})
	 := .Clone()
	.NextProtos = []string{NextProtoH3}
	if  := .GetConfigForClient;  != nil {
		.GetConfigForClient = func( *tls.ClientHelloInfo) (*tls.Config, error) {
			,  := ()
			if  == nil ||  != nil {
				return , 
			}
			return (), nil
		}
	}
	return 
}

// contextKey is a value for use with context.WithValue. It's used as
// a pointer so it fits in an interface{} without allocation.
type contextKey struct {
	name string
}

func ( *contextKey) () string { return "quic-go/http3 context value " + .name }

// ServerContextKey is a context key. It can be used in HTTP
// handlers with Context.Value to access the server that
// started the handler. The associated value will be of
// type *http3.Server.
var ServerContextKey = &contextKey{"http3-server"}

// RemoteAddrContextKey is a context key. It can be used in
// HTTP handlers with Context.Value to access the remote
// address of the connection. The associated value will be of
// type net.Addr.
//
// Use this value instead of [http.Request.RemoteAddr] if you
// require access to the remote address of the connection rather
// than its string representation.
var RemoteAddrContextKey = &contextKey{"remote-addr"}

// listener contains info about specific listener added with addListener
type listener struct {
	ln   *QUICListener
	port int // 0 means that no info about port is available

	// if this listener was constructed by the application, it won't be closed when the server is closed
	createdLocally bool
}

// Server is a HTTP/3 server.
type Server struct {
	// Addr optionally specifies the UDP address for the server to listen on,
	// in the form "host:port".
	//
	// When used by ListenAndServe and ListenAndServeTLS methods, if empty,
	// ":https" (port 443) is used. See net.Dial for details of the address
	// format.
	//
	// Otherwise, if Port is not set and underlying QUIC listeners do not
	// have valid port numbers, the port part is used in Alt-Svc headers set
	// with SetQUICHeaders.
	Addr string

	// Port is used in Alt-Svc response headers set with SetQUICHeaders. If
	// needed Port can be manually set when the Server is created.
	//
	// This is useful when a Layer 4 firewall is redirecting UDP traffic and
	// clients must use a port different from the port the Server is
	// listening on.
	Port int

	// TLSConfig provides a TLS configuration for use by server. It must be
	// set for ListenAndServe and Serve methods.
	TLSConfig *tls.Config

	// QUICConfig provides the parameters for QUIC connection created with Serve.
	// If nil, it uses reasonable default values.
	//
	// Configured versions are also used in Alt-Svc response header set with SetQUICHeaders.
	QUICConfig *quic.Config

	// Handler is the HTTP request handler to use. If not set, defaults to
	// http.NotFound.
	Handler http.Handler

	// EnableDatagrams enables support for HTTP/3 datagrams (RFC 9297).
	// If set to true, QUICConfig.EnableDatagrams will be set.
	EnableDatagrams bool

	// MaxHeaderBytes controls the maximum number of bytes the server will
	// read parsing the request HEADERS frame. It does not limit the size of
	// the request body. If zero or negative, http.DefaultMaxHeaderBytes is
	// used.
	MaxHeaderBytes int

	// AdditionalSettings specifies additional HTTP/3 settings.
	// It is invalid to specify any settings defined by RFC 9114 (HTTP/3) and RFC 9297 (HTTP Datagrams).
	AdditionalSettings map[uint64]uint64

	// IdleTimeout specifies how long until idle clients connection should be
	// closed. Idle refers only to the HTTP/3 layer, activity at the QUIC layer
	// like PING frames are not considered.
	// If zero or negative, there is no timeout.
	IdleTimeout time.Duration

	// ConnContext optionally specifies a function that modifies the context used for a new connection c.
	// The provided ctx has a ServerContextKey value.
	ConnContext func(ctx context.Context, c *quic.Conn) context.Context

	Logger *slog.Logger

	mutex     sync.RWMutex
	listeners []listener

	closed           bool
	closeCtx         context.Context    // canceled when the server is closed
	closeCancel      context.CancelFunc // cancels the closeCtx
	graceCtx         context.Context    // canceled when the server is closed or gracefully closed
	graceCancel      context.CancelFunc // cancels the graceCtx
	connCount        atomic.Int64
	connHandlingDone chan struct{}

	altSvcHeader string
}

// ListenAndServe listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.
//
// If s.Addr is blank, ":https" is used.
func ( *Server) () error {
	,  := .setupListenerForConn(.TLSConfig, nil)
	if  != nil {
		return 
	}
	defer .removeListener()

	return .serveListener(*)
}

// ListenAndServeTLS listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.
//
// If s.Addr is blank, ":https" is used.
func ( *Server) (,  string) error {
	var  error
	 := make([]tls.Certificate, 1)
	[0],  = tls.LoadX509KeyPair(, )
	if  != nil {
		return 
	}
	// We currently only use the cert-related stuff from tls.Config,
	// so we don't need to make a full copy.
	,  := .setupListenerForConn(&tls.Config{Certificates: }, nil)
	if  != nil {
		return 
	}
	defer .removeListener()

	return .serveListener(*)
}

// Serve an existing UDP connection.
// It is possible to reuse the same connection for outgoing connections.
// Closing the server does not close the connection.
func ( *Server) ( net.PacketConn) error {
	,  := .setupListenerForConn(.TLSConfig, )
	if  != nil {
		return 
	}
	defer .removeListener()

	return .serveListener(*)
}

// init initializes the contexts used for shutting down the server.
// It must be called with the mutex held.
func ( *Server) () {
	if .closeCtx == nil {
		.closeCtx, .closeCancel = context.WithCancel(context.Background())
		.graceCtx, .graceCancel = context.WithCancel(.closeCtx)
	}
	.connHandlingDone = make(chan struct{}, 1)
}

func ( *Server) () {
	if .connCount.Add(-1) == 0 && .graceCtx.Err() != nil {
		close(.connHandlingDone)
	}
}

// ServeQUICConn serves a single QUIC connection.
func ( *Server) ( *quic.Conn) error {
	.mutex.Lock()
	if .closed {
		.mutex.Unlock()
		return http.ErrServerClosed
	}

	.init()
	.mutex.Unlock()

	.connCount.Add(1)
	defer .decreaseConnCount()

	return .handleConn()
}

// ServeListener serves an existing QUIC listener.
// Make sure you use http3.ConfigureTLSConfig to configure a tls.Config
// and use it to construct a http3-friendly QUIC listener.
// Closing the server does not close the listener. It is the application's responsibility to close them.
// ServeListener always returns a non-nil error. After Shutdown or Close, the returned error is http.ErrServerClosed.
func ( *Server) ( QUICListener) error {
	.mutex.Lock()
	if  := .addListener(&, false);  != nil {
		.mutex.Unlock()
		return 
	}
	.mutex.Unlock()
	defer .removeListener(&)

	return .serveListener()
}

func ( *Server) ( QUICListener) error {
	for {
		,  := .Accept(.graceCtx)
		// server closed
		if errors.Is(, quic.ErrServerClosed) || .graceCtx.Err() != nil {
			return http.ErrServerClosed
		}
		if  != nil {
			return 
		}
		.connCount.Add(1)
		go func() {
			defer .decreaseConnCount()
			if  := .handleConn();  != nil {
				if .Logger != nil {
					.Logger.Debug("handling connection failed", "error", )
				}
			}
		}()
	}
}

var errServerWithoutTLSConfig = errors.New("use of http3.Server without TLSConfig")

func ( *Server) ( *tls.Config,  net.PacketConn) (*QUICListener, error) {
	if  == nil {
		return nil, errServerWithoutTLSConfig
	}

	 := ConfigureTLSConfig()
	 := .QUICConfig
	if  == nil {
		 = &quic.Config{Allow0RTT: true}
	} else {
		 = .QUICConfig.Clone()
	}
	if .EnableDatagrams {
		.EnableDatagrams = true
	}

	.mutex.Lock()
	defer .mutex.Unlock()
	 := .closed
	if  {
		return nil, http.ErrServerClosed
	}

	var  QUICListener
	var  error
	if  == nil {
		 := .Addr
		if  == "" {
			 = ":https"
		}
		,  = quic.ListenAddrEarly(, , )
	} else {
		,  = quic.ListenEarly(, , )
	}
	if  != nil {
		return nil, 
	}
	if  := .addListener(&, true);  != nil {
		return nil, 
	}
	return &, nil
}

func extractPort( string) (int, error) {
	, ,  := net.SplitHostPort()
	if  != nil {
		return 0, 
	}

	,  := net.LookupPort("tcp", )
	if  != nil {
		return 0, 
	}
	return , nil
}

func ( *Server) () {
	if len(.listeners) == 0 {
		// Don't announce any ports since no one is listening for connections
		.altSvcHeader = ""
		return
	}

	// This code assumes that we will use protocol.SupportedVersions if no quic.Config is passed.

	var  []string
	 := func( int) {
		 = append(, fmt.Sprintf(`%s=":%d"; ma=2592000`, NextProtoH3, ))
	}

	if .Port != 0 {
		// if Port is specified, we must use it instead of the
		// listener addresses since there's a reason it's specified.
		(.Port)
	} else {
		// if we have some listeners assigned, try to find ports
		// which we can announce, otherwise nothing should be announced
		 := false
		for ,  := range .listeners {
			if .port != 0 {
				(.port)
				 = true
			}
		}
		if ! {
			if ,  := extractPort(.Addr);  == nil {
				()
			}
		}
	}

	.altSvcHeader = strings.Join(, ",")
}

func ( *Server) ( *QUICListener,  bool) error {
	if .closed {
		return http.ErrServerClosed
	}
	.init()

	 := (*).Addr()
	if ,  := extractPort(.String());  == nil {
		.listeners = append(.listeners, listener{ln: , port: , createdLocally: })
	} else {
		 := .Logger
		if  == nil {
			 = slog.Default()
		}
		.Error("Unable to extract port from listener, will not be announced using SetQUICHeaders", "local addr", , "error", )
		.listeners = append(.listeners, listener{ln: , port: 0, createdLocally: })
	}
	.generateAltSvcHeader()
	return nil
}

func ( *Server) ( *QUICListener) {
	.mutex.Lock()
	defer .mutex.Unlock()

	.listeners = slices.DeleteFunc(.listeners, func( listener) bool {
		return .ln == 
	})
	.generateAltSvcHeader()
}

func ( *Server) ( *quic.Conn) (*RawServerConn, error) {
	, , ,  := .newRawServerConn()
	if  != nil {
		return nil, 
	}
	return , nil
}

func ( *Server) ( *quic.Conn) (*RawServerConn, *quic.SendStream, qlogwriter.Recorder, error) {
	var  qlogwriter.Recorder
	if  := .QlogTrace();  != nil && .SupportsSchemas(qlog.EventSchema) {
		 = .AddProducer()
	}
	 := .Context()
	 = context.WithValue(, ServerContextKey, )
	 = context.WithValue(, http.LocalAddrContextKey, .LocalAddr())
	 = context.WithValue(, RemoteAddrContextKey, .RemoteAddr())
	if .ConnContext != nil {
		 = .ConnContext(, )
		if  == nil {
			panic("http3: ConnContext returned nil")
		}
	}
	 := newRawServerConn(
		,
		.EnableDatagrams,
		.IdleTimeout,
		,
		.Logger,
		,
		.Handler,
		.maxHeaderBytes(),
	)

	// open the control stream and send a SETTINGS frame, it's also used to send a GOAWAY frame later
	// when the server is gracefully closed
	,  := .openControlStream(&settingsFrame{
		MaxFieldSectionSize: int64(.maxHeaderBytes()),
		Datagram:            .EnableDatagrams,
		ExtendedConnect:     true,
		Other:               .AdditionalSettings,
	})
	if  != nil {
		return nil, nil, nil, fmt.Errorf("opening the control stream failed: %w", )
	}
	return , , , nil
}

// handleConn handles the HTTP/3 exchange on a QUIC connection.
// It blocks until all HTTP handlers for all streams have returned.
func ( *Server) ( *quic.Conn) error {
	, , ,  := .newRawServerConn()
	if  != nil {
		return 
	}

	var  sync.WaitGroup
	.Add(1)

	go func() {
		defer .Done()
		for {
			,  := .AcceptUniStream(context.Background())
			if  != nil {
				return
			}
			go .HandleUnidirectionalStream()
		}
	}()

	var  quic.StreamID
	var  error
	var  bool
	// Process all requests immediately.
	// It's the client's responsibility to decide which requests are eligible for 0-RTT.
	 := .graceCtx
	for {
		// The context used here is:
		// * before graceful shutdown: s.graceCtx
		// * after graceful shutdown: s.closeCtx
		// This allows us to keep accepting (and resetting) streams after graceful shutdown has started.
		,  := .AcceptStream()
		if  != nil {
			// the underlying connection was closed (by either side)
			if .Context().Err() != nil {
				var  *quic.ApplicationError
				if !errors.As(, &) || .ErrorCode != quic.ApplicationErrorCode(ErrCodeNoError) {
					 = fmt.Errorf("accepting stream failed: %w", )
				}
				break
			}
			// server (not gracefully) closed, close the connection immediately
			if .closeCtx.Err() != nil {
				.CloseWithError(quic.ApplicationErrorCode(ErrCodeNoError), "")
				 = http.ErrServerClosed
				break
			}
			 = .graceCtx.Err() != nil
			if ! {
				var  *quic.ApplicationError
				if !errors.As(, &) || .ErrorCode != quic.ApplicationErrorCode(ErrCodeNoError) {
					 = fmt.Errorf("accepting stream failed: %w", )
				}
				break
			}

			// gracefully closed, send GOAWAY frame and wait for requests to complete or grace period to end
			// new requests will be rejected and shouldn't be sent
			if  != nil {
				.RecordEvent(qlog.FrameCreated{
					StreamID: .StreamID(),
					Frame:    qlog.Frame{Frame: qlog.GoAwayFrame{StreamID: }},
				})
			}
			.Add(1)
			// Send the GOAWAY frame in a separate Goroutine.
			// Sending might block if the peer didn't grant enough flow control credit.
			// Write is guaranteed to return once the connection is closed.
			go func() {
				defer .Done()
				_, _ = .Write((&goAwayFrame{StreamID: }).Append(nil))
			}()
			 = .closeCtx
			continue
		}
		if  {
			.CancelRead(quic.StreamErrorCode(ErrCodeRequestRejected))
			.CancelWrite(quic.StreamErrorCode(ErrCodeRequestRejected))
			continue
		}

		 = .StreamID() + 4
		.Add(1)
		go func() {
			// HandleRequestStream will return once the request has been handled,
			// or the underlying connection is closed.
			defer .Done()
			.HandleRequestStream()
		}()
	}
	.Wait()
	return 
}

func ( *Server) () int {
	if .MaxHeaderBytes <= 0 {
		return http.DefaultMaxHeaderBytes
	}
	return .MaxHeaderBytes
}

// Close the server immediately, aborting requests and sending CONNECTION_CLOSE frames to connected clients.
// Close in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.
// It is the caller's responsibility to close any connection passed to ServeQUICConn.
func ( *Server) () error {
	.mutex.Lock()
	defer .mutex.Unlock()

	.closed = true
	// server is never used
	if .closeCtx == nil {
		return nil
	}
	.closeCancel()

	var  error
	for ,  := range .listeners {
		if .createdLocally {
			if  := (*.ln).Close();  != nil &&  == nil {
				 = 
			}
		}
	}
	if .connCount.Load() == 0 {
		return 
	}
	// wait for all connections to be closed
	<-.connHandlingDone
	return 
}

// Shutdown gracefully shuts down the server without interrupting any active connections.
// The server sends a GOAWAY frame first, then or for all running requests to complete.
// Shutdown in combination with ListenAndServe may race if it is called before a UDP socket is established.
// It is recommended to use Serve instead.
func ( *Server) ( context.Context) error {
	.mutex.Lock()
	.closed = true
	// server was never used
	if .closeCtx == nil {
		.mutex.Unlock()
		return nil
	}
	.graceCancel()

	// close all listeners
	var  []error
	for ,  := range .listeners {
		if .createdLocally {
			if  := (*.ln).Close();  != nil {
				 = append(, )
			}
		}
	}
	.mutex.Unlock()
	if len() > 0 {
		return errors.Join(...)
	}

	if .connCount.Load() == 0 {
		return .Close()
	}
	select {
	case <-.connHandlingDone: // all connections were closed
		// When receiving a GOAWAY frame, HTTP/3 clients are expected to close the connection
		// once all requests were successfully handled...
		return .Close()
	case <-.Done():
		// ... however, clients handling long-lived requests (and misbehaving clients),
		// might not do so before the context is cancelled.
		// In this case, we close the server, which closes all existing connections
		// (expect those passed to ServeQUICConn).
		_ = .Close()
		return .Err()
	}
}

// ErrNoAltSvcPort is the error returned by SetQUICHeaders when no port was found
// for Alt-Svc to announce. This can happen if listening on a PacketConn without a port
// (UNIX socket, for example) and no port is specified in Server.Port or Server.Addr.
var ErrNoAltSvcPort = errors.New("no port can be announced, specify it explicitly using Server.Port or Server.Addr")

// SetQUICHeaders can be used to set the proper headers that announce that this server supports HTTP/3.
// The values set by default advertise all the ports the server is listening on, but can be
// changed to a specific port by setting Server.Port before launching the server.
// If no listener's Addr().String() returns an address with a valid port, Server.Addr will be used
// to extract the port, if specified.
// For example, a server launched using ListenAndServe on an address with port 443 would set:
//
//	Alt-Svc: h3=":443"; ma=2592000
func ( *Server) ( http.Header) error {
	.mutex.RLock()
	defer .mutex.RUnlock()

	if .altSvcHeader == "" {
		return ErrNoAltSvcPort
	}
	// use the map directly to avoid constant canonicalization since the key is already canonicalized
	["Alt-Svc"] = append(["Alt-Svc"], .altSvcHeader)
	return nil
}

// ListenAndServeQUIC listens on the UDP network address addr and calls the
// handler for HTTP/3 requests on incoming connections. http.DefaultServeMux is
// used when handler is nil.
func (, ,  string,  http.Handler) error {
	 := &Server{
		Addr:    ,
		Handler: ,
	}
	return .ListenAndServeTLS(, )
}

// ListenAndServeTLS listens on the given network address for both TLS/TCP and QUIC
// connections in parallel. It returns if one of the two returns an error.
// http.DefaultServeMux is used when handler is nil.
// The correct Alt-Svc headers for QUIC are set.
func (, ,  string,  http.Handler) error {
	// Load certs
	var  error
	 := make([]tls.Certificate, 1)
	[0],  = tls.LoadX509KeyPair(, )
	if  != nil {
		return 
	}
	// We currently only use the cert-related stuff from tls.Config,
	// so we don't need to make a full copy.
	 := &tls.Config{
		Certificates: ,
	}

	if  == "" {
		 = ":https"
	}

	// Open the listeners
	,  := net.ResolveUDPAddr("udp", )
	if  != nil {
		return 
	}
	,  := net.ListenUDP("udp", )
	if  != nil {
		return 
	}
	defer .Close()

	if  == nil {
		 = http.DefaultServeMux
	}
	// Start the servers
	 := &Server{
		TLSConfig: ,
		Handler:   ,
	}

	 := make(chan error, 1)
	 := make(chan error, 1)
	go func() {
		 <- http.ListenAndServeTLS(, , , http.HandlerFunc(func( http.ResponseWriter,  *http.Request) {
			.SetQUICHeaders(.Header())
			.ServeHTTP(, )
		}))
	}()
	go func() {
		 <- .Serve()
	}()

	select {
	case  := <-:
		.Close()
		return 
	case  := <-:
		// Cannot close the HTTP server or wait for requests to complete properly :/
		return 
	}
}