github.com/quic-go/quic-go@v0.44.0/http3/server.go (about)

     1  package http3
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"log/slog"
    10  	"net"
    11  	"net/http"
    12  	"runtime"
    13  	"strconv"
    14  	"strings"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/quic-go/quic-go"
    19  	"github.com/quic-go/quic-go/internal/protocol"
    20  	"github.com/quic-go/quic-go/quicvarint"
    21  
    22  	"github.com/quic-go/qpack"
    23  )
    24  
    25  // allows mocking of quic.Listen and quic.ListenAddr
    26  var (
    27  	quicListen = func(conn net.PacketConn, tlsConf *tls.Config, config *quic.Config) (QUICEarlyListener, error) {
    28  		return quic.ListenEarly(conn, tlsConf, config)
    29  	}
    30  	quicListenAddr = func(addr string, tlsConf *tls.Config, config *quic.Config) (QUICEarlyListener, error) {
    31  		return quic.ListenAddrEarly(addr, tlsConf, config)
    32  	}
    33  )
    34  
    35  // NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2.
    36  const NextProtoH3 = "h3"
    37  
    38  // StreamType is the stream type of a unidirectional stream.
    39  type StreamType uint64
    40  
    41  const (
    42  	streamTypeControlStream      = 0
    43  	streamTypePushStream         = 1
    44  	streamTypeQPACKEncoderStream = 2
    45  	streamTypeQPACKDecoderStream = 3
    46  )
    47  
    48  // A QUICEarlyListener listens for incoming QUIC connections.
    49  type QUICEarlyListener interface {
    50  	Accept(context.Context) (quic.EarlyConnection, error)
    51  	Addr() net.Addr
    52  	io.Closer
    53  }
    54  
    55  var _ QUICEarlyListener = &quic.EarlyListener{}
    56  
    57  func versionToALPN(v protocol.Version) string {
    58  	//nolint:exhaustive // These are all the versions we care about.
    59  	switch v {
    60  	case protocol.Version1, protocol.Version2:
    61  		return NextProtoH3
    62  	default:
    63  		return ""
    64  	}
    65  }
    66  
    67  // ConfigureTLSConfig creates a new tls.Config which can be used
    68  // to create a quic.Listener meant for serving http3. The created
    69  // tls.Config adds the functionality of detecting the used QUIC version
    70  // in order to set the correct ALPN value for the http3 connection.
    71  func ConfigureTLSConfig(tlsConf *tls.Config) *tls.Config {
    72  	// The tls.Config used to setup the quic.Listener needs to have the GetConfigForClient callback set.
    73  	// That way, we can get the QUIC version and set the correct ALPN value.
    74  	return &tls.Config{
    75  		GetConfigForClient: func(ch *tls.ClientHelloInfo) (*tls.Config, error) {
    76  			// determine the ALPN from the QUIC version used
    77  			proto := NextProtoH3
    78  			val := ch.Context().Value(quic.QUICVersionContextKey)
    79  			if v, ok := val.(quic.Version); ok {
    80  				proto = versionToALPN(v)
    81  			}
    82  			config := tlsConf
    83  			if tlsConf.GetConfigForClient != nil {
    84  				getConfigForClient := tlsConf.GetConfigForClient
    85  				var err error
    86  				conf, err := getConfigForClient(ch)
    87  				if err != nil {
    88  					return nil, err
    89  				}
    90  				if conf != nil {
    91  					config = conf
    92  				}
    93  			}
    94  			if config == nil {
    95  				return nil, nil
    96  			}
    97  			config = config.Clone()
    98  			config.NextProtos = []string{proto}
    99  			return config, nil
   100  		},
   101  	}
   102  }
   103  
   104  // contextKey is a value for use with context.WithValue. It's used as
   105  // a pointer so it fits in an interface{} without allocation.
   106  type contextKey struct {
   107  	name string
   108  }
   109  
   110  func (k *contextKey) String() string { return "quic-go/http3 context value " + k.name }
   111  
   112  // ServerContextKey is a context key. It can be used in HTTP
   113  // handlers with Context.Value to access the server that
   114  // started the handler. The associated value will be of
   115  // type *http3.Server.
   116  var ServerContextKey = &contextKey{"http3-server"}
   117  
   118  // RemoteAddrContextKey is a context key. It can be used in
   119  // HTTP handlers with Context.Value to access the remote
   120  // address of the connection. The associated value will be of
   121  // type net.Addr.
   122  //
   123  // Use this value instead of [http.Request.RemoteAddr] if you
   124  // require access to the remote address of the connection rather
   125  // than its string representation.
   126  var RemoteAddrContextKey = &contextKey{"remote-addr"}
   127  
   128  // listenerInfo contains info about specific listener added with addListener
   129  type listenerInfo struct {
   130  	port int // 0 means that no info about port is available
   131  }
   132  
   133  // Server is a HTTP/3 server.
   134  type Server struct {
   135  	// Addr optionally specifies the UDP address for the server to listen on,
   136  	// in the form "host:port".
   137  	//
   138  	// When used by ListenAndServe and ListenAndServeTLS methods, if empty,
   139  	// ":https" (port 443) is used. See net.Dial for details of the address
   140  	// format.
   141  	//
   142  	// Otherwise, if Port is not set and underlying QUIC listeners do not
   143  	// have valid port numbers, the port part is used in Alt-Svc headers set
   144  	// with SetQUICHeaders.
   145  	Addr string
   146  
   147  	// Port is used in Alt-Svc response headers set with SetQUICHeaders. If
   148  	// needed Port can be manually set when the Server is created.
   149  	//
   150  	// This is useful when a Layer 4 firewall is redirecting UDP traffic and
   151  	// clients must use a port different from the port the Server is
   152  	// listening on.
   153  	Port int
   154  
   155  	// TLSConfig provides a TLS configuration for use by server. It must be
   156  	// set for ListenAndServe and Serve methods.
   157  	TLSConfig *tls.Config
   158  
   159  	// QUICConfig provides the parameters for QUIC connection created with Serve.
   160  	// If nil, it uses reasonable default values.
   161  	//
   162  	// Configured versions are also used in Alt-Svc response header set with SetQUICHeaders.
   163  	QUICConfig *quic.Config
   164  
   165  	// Handler is the HTTP request handler to use. If not set, defaults to
   166  	// http.NotFound.
   167  	Handler http.Handler
   168  
   169  	// EnableDatagrams enables support for HTTP/3 datagrams (RFC 9297).
   170  	// If set to true, QUICConfig.EnableDatagrams will be set.
   171  	EnableDatagrams bool
   172  
   173  	// MaxHeaderBytes controls the maximum number of bytes the server will
   174  	// read parsing the request HEADERS frame. It does not limit the size of
   175  	// the request body. If zero or negative, http.DefaultMaxHeaderBytes is
   176  	// used.
   177  	MaxHeaderBytes int
   178  
   179  	// AdditionalSettings specifies additional HTTP/3 settings.
   180  	// It is invalid to specify any settings defined by RFC 9114 (HTTP/3) and RFC 9297 (HTTP Datagrams).
   181  	AdditionalSettings map[uint64]uint64
   182  
   183  	// StreamHijacker, when set, is called for the first unknown frame parsed on a bidirectional stream.
   184  	// It is called right after parsing the frame type.
   185  	// If parsing the frame type fails, the error is passed to the callback.
   186  	// In that case, the frame type will not be set.
   187  	// Callers can either ignore the frame and return control of the stream back to HTTP/3
   188  	// (by returning hijacked false).
   189  	// Alternatively, callers can take over the QUIC stream (by returning hijacked true).
   190  	StreamHijacker func(FrameType, quic.ConnectionTracingID, quic.Stream, error) (hijacked bool, err error)
   191  
   192  	// UniStreamHijacker, when set, is called for unknown unidirectional stream of unknown stream type.
   193  	// If parsing the stream type fails, the error is passed to the callback.
   194  	// In that case, the stream type will not be set.
   195  	UniStreamHijacker func(StreamType, quic.ConnectionTracingID, quic.ReceiveStream, error) (hijacked bool)
   196  
   197  	// ConnContext optionally specifies a function that modifies
   198  	// the context used for a new connection c. The provided ctx
   199  	// has a ServerContextKey value.
   200  	ConnContext func(ctx context.Context, c quic.Connection) context.Context
   201  
   202  	Logger *slog.Logger
   203  
   204  	mutex     sync.RWMutex
   205  	listeners map[*QUICEarlyListener]listenerInfo
   206  
   207  	closed bool
   208  
   209  	altSvcHeader string
   210  }
   211  
   212  // ListenAndServe listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.
   213  //
   214  // If s.Addr is blank, ":https" is used.
   215  func (s *Server) ListenAndServe() error {
   216  	return s.serveConn(s.TLSConfig, nil)
   217  }
   218  
   219  // ListenAndServeTLS listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.
   220  //
   221  // If s.Addr is blank, ":https" is used.
   222  func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
   223  	var err error
   224  	certs := make([]tls.Certificate, 1)
   225  	certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
   226  	if err != nil {
   227  		return err
   228  	}
   229  	// We currently only use the cert-related stuff from tls.Config,
   230  	// so we don't need to make a full copy.
   231  	config := &tls.Config{
   232  		Certificates: certs,
   233  	}
   234  	return s.serveConn(config, nil)
   235  }
   236  
   237  // Serve an existing UDP connection.
   238  // It is possible to reuse the same connection for outgoing connections.
   239  // Closing the server does not close the connection.
   240  func (s *Server) Serve(conn net.PacketConn) error {
   241  	return s.serveConn(s.TLSConfig, conn)
   242  }
   243  
   244  // ServeQUICConn serves a single QUIC connection.
   245  func (s *Server) ServeQUICConn(conn quic.Connection) error {
   246  	return s.handleConn(conn)
   247  }
   248  
   249  // ServeListener serves an existing QUIC listener.
   250  // Make sure you use http3.ConfigureTLSConfig to configure a tls.Config
   251  // and use it to construct a http3-friendly QUIC listener.
   252  // Closing the server does close the listener.
   253  // ServeListener always returns a non-nil error. After Shutdown or Close, the returned error is http.ErrServerClosed.
   254  func (s *Server) ServeListener(ln QUICEarlyListener) error {
   255  	if err := s.addListener(&ln); err != nil {
   256  		return err
   257  	}
   258  	defer s.removeListener(&ln)
   259  	for {
   260  		conn, err := ln.Accept(context.Background())
   261  		if err == quic.ErrServerClosed {
   262  			return http.ErrServerClosed
   263  		}
   264  		if err != nil {
   265  			return err
   266  		}
   267  		go func() {
   268  			if err := s.handleConn(conn); err != nil {
   269  				if s.Logger != nil {
   270  					s.Logger.Debug("handling connection failed", "error", err)
   271  				}
   272  			}
   273  		}()
   274  	}
   275  }
   276  
   277  var errServerWithoutTLSConfig = errors.New("use of http3.Server without TLSConfig")
   278  
   279  func (s *Server) serveConn(tlsConf *tls.Config, conn net.PacketConn) error {
   280  	if tlsConf == nil {
   281  		return errServerWithoutTLSConfig
   282  	}
   283  
   284  	s.mutex.Lock()
   285  	closed := s.closed
   286  	s.mutex.Unlock()
   287  	if closed {
   288  		return http.ErrServerClosed
   289  	}
   290  
   291  	baseConf := ConfigureTLSConfig(tlsConf)
   292  	quicConf := s.QUICConfig
   293  	if quicConf == nil {
   294  		quicConf = &quic.Config{Allow0RTT: true}
   295  	} else {
   296  		quicConf = s.QUICConfig.Clone()
   297  	}
   298  	if s.EnableDatagrams {
   299  		quicConf.EnableDatagrams = true
   300  	}
   301  
   302  	var ln QUICEarlyListener
   303  	var err error
   304  	if conn == nil {
   305  		addr := s.Addr
   306  		if addr == "" {
   307  			addr = ":https"
   308  		}
   309  		ln, err = quicListenAddr(addr, baseConf, quicConf)
   310  	} else {
   311  		ln, err = quicListen(conn, baseConf, quicConf)
   312  	}
   313  	if err != nil {
   314  		return err
   315  	}
   316  	return s.ServeListener(ln)
   317  }
   318  
   319  func extractPort(addr string) (int, error) {
   320  	_, portStr, err := net.SplitHostPort(addr)
   321  	if err != nil {
   322  		return 0, err
   323  	}
   324  
   325  	portInt, err := net.LookupPort("tcp", portStr)
   326  	if err != nil {
   327  		return 0, err
   328  	}
   329  	return portInt, nil
   330  }
   331  
   332  func (s *Server) generateAltSvcHeader() {
   333  	if len(s.listeners) == 0 {
   334  		// Don't announce any ports since no one is listening for connections
   335  		s.altSvcHeader = ""
   336  		return
   337  	}
   338  
   339  	// This code assumes that we will use protocol.SupportedVersions if no quic.Config is passed.
   340  	supportedVersions := protocol.SupportedVersions
   341  	if s.QUICConfig != nil && len(s.QUICConfig.Versions) > 0 {
   342  		supportedVersions = s.QUICConfig.Versions
   343  	}
   344  
   345  	// keep track of which have been seen so we don't yield duplicate values
   346  	seen := make(map[string]struct{}, len(supportedVersions))
   347  	var versionStrings []string
   348  	for _, version := range supportedVersions {
   349  		if v := versionToALPN(version); len(v) > 0 {
   350  			if _, ok := seen[v]; !ok {
   351  				versionStrings = append(versionStrings, v)
   352  				seen[v] = struct{}{}
   353  			}
   354  		}
   355  	}
   356  
   357  	var altSvc []string
   358  	addPort := func(port int) {
   359  		for _, v := range versionStrings {
   360  			altSvc = append(altSvc, fmt.Sprintf(`%s=":%d"; ma=2592000`, v, port))
   361  		}
   362  	}
   363  
   364  	if s.Port != 0 {
   365  		// if Port is specified, we must use it instead of the
   366  		// listener addresses since there's a reason it's specified.
   367  		addPort(s.Port)
   368  	} else {
   369  		// if we have some listeners assigned, try to find ports
   370  		// which we can announce, otherwise nothing should be announced
   371  		validPortsFound := false
   372  		for _, info := range s.listeners {
   373  			if info.port != 0 {
   374  				addPort(info.port)
   375  				validPortsFound = true
   376  			}
   377  		}
   378  		if !validPortsFound {
   379  			if port, err := extractPort(s.Addr); err == nil {
   380  				addPort(port)
   381  			}
   382  		}
   383  	}
   384  
   385  	s.altSvcHeader = strings.Join(altSvc, ",")
   386  }
   387  
   388  // We store a pointer to interface in the map set. This is safe because we only
   389  // call trackListener via Serve and can track+defer untrack the same pointer to
   390  // local variable there. We never need to compare a Listener from another caller.
   391  func (s *Server) addListener(l *QUICEarlyListener) error {
   392  	s.mutex.Lock()
   393  	defer s.mutex.Unlock()
   394  
   395  	if s.closed {
   396  		return http.ErrServerClosed
   397  	}
   398  	if s.listeners == nil {
   399  		s.listeners = make(map[*QUICEarlyListener]listenerInfo)
   400  	}
   401  
   402  	laddr := (*l).Addr()
   403  	if port, err := extractPort(laddr.String()); err == nil {
   404  		s.listeners[l] = listenerInfo{port}
   405  	} else {
   406  		logger := s.Logger
   407  		if logger == nil {
   408  			logger = slog.Default()
   409  		}
   410  		logger.Error("Unable to extract port from listener, will not be announced using SetQUICHeaders", "local addr", laddr, "error", err)
   411  		s.listeners[l] = listenerInfo{}
   412  	}
   413  	s.generateAltSvcHeader()
   414  	return nil
   415  }
   416  
   417  func (s *Server) removeListener(l *QUICEarlyListener) {
   418  	s.mutex.Lock()
   419  	defer s.mutex.Unlock()
   420  	delete(s.listeners, l)
   421  	s.generateAltSvcHeader()
   422  }
   423  
   424  func (s *Server) handleConn(conn quic.Connection) error {
   425  	// send a SETTINGS frame
   426  	str, err := conn.OpenUniStream()
   427  	if err != nil {
   428  		return fmt.Errorf("opening the control stream failed: %w", err)
   429  	}
   430  	b := make([]byte, 0, 64)
   431  	b = quicvarint.Append(b, streamTypeControlStream) // stream type
   432  	b = (&settingsFrame{
   433  		Datagram:        s.EnableDatagrams,
   434  		ExtendedConnect: true,
   435  		Other:           s.AdditionalSettings,
   436  	}).Append(b)
   437  	str.Write(b)
   438  
   439  	hconn := newConnection(
   440  		conn,
   441  		s.EnableDatagrams,
   442  		protocol.PerspectiveServer,
   443  		s.Logger,
   444  	)
   445  	go hconn.HandleUnidirectionalStreams(s.UniStreamHijacker)
   446  	// Process all requests immediately.
   447  	// It's the client's responsibility to decide which requests are eligible for 0-RTT.
   448  	for {
   449  		str, datagrams, err := hconn.acceptStream(context.Background())
   450  		if err != nil {
   451  			var appErr *quic.ApplicationError
   452  			if errors.As(err, &appErr) && appErr.ErrorCode == quic.ApplicationErrorCode(ErrCodeNoError) {
   453  				return nil
   454  			}
   455  			return fmt.Errorf("accepting stream failed: %w", err)
   456  		}
   457  		go s.handleRequest(hconn, str, datagrams, hconn.decoder)
   458  	}
   459  }
   460  
   461  func (s *Server) maxHeaderBytes() uint64 {
   462  	if s.MaxHeaderBytes <= 0 {
   463  		return http.DefaultMaxHeaderBytes
   464  	}
   465  	return uint64(s.MaxHeaderBytes)
   466  }
   467  
   468  func (s *Server) handleRequest(conn *connection, str quic.Stream, datagrams *datagrammer, decoder *qpack.Decoder) {
   469  	var ufh unknownFrameHandlerFunc
   470  	if s.StreamHijacker != nil {
   471  		ufh = func(ft FrameType, e error) (processed bool, err error) {
   472  			return s.StreamHijacker(
   473  				ft,
   474  				conn.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID),
   475  				str,
   476  				e,
   477  			)
   478  		}
   479  	}
   480  	fp := &frameParser{conn: conn, r: str, unknownFrameHandler: ufh}
   481  	frame, err := fp.ParseNext()
   482  	if err != nil {
   483  		if !errors.Is(err, errHijacked) {
   484  			str.CancelRead(quic.StreamErrorCode(ErrCodeRequestIncomplete))
   485  			str.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete))
   486  		}
   487  		return
   488  	}
   489  	hf, ok := frame.(*headersFrame)
   490  	if !ok {
   491  		conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "expected first frame to be a HEADERS frame")
   492  		return
   493  	}
   494  	if hf.Length > s.maxHeaderBytes() {
   495  		str.CancelRead(quic.StreamErrorCode(ErrCodeFrameError))
   496  		str.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError))
   497  		return
   498  	}
   499  	headerBlock := make([]byte, hf.Length)
   500  	if _, err := io.ReadFull(str, headerBlock); err != nil {
   501  		str.CancelRead(quic.StreamErrorCode(ErrCodeRequestIncomplete))
   502  		str.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete))
   503  		return
   504  	}
   505  	hfs, err := decoder.DecodeFull(headerBlock)
   506  	if err != nil {
   507  		// TODO: use the right error code
   508  		conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeGeneralProtocolError), "expected first frame to be a HEADERS frame")
   509  		return
   510  	}
   511  	req, err := requestFromHeaders(hfs)
   512  	if err != nil {
   513  		str.CancelRead(quic.StreamErrorCode(ErrCodeMessageError))
   514  		str.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError))
   515  		return
   516  	}
   517  
   518  	connState := conn.ConnectionState().TLS
   519  	req.TLS = &connState
   520  	req.RemoteAddr = conn.RemoteAddr().String()
   521  
   522  	// Check that the client doesn't send more data in DATA frames than indicated by the Content-Length header (if set).
   523  	// See section 4.1.2 of RFC 9114.
   524  	contentLength := int64(-1)
   525  	if _, ok := req.Header["Content-Length"]; ok && req.ContentLength >= 0 {
   526  		contentLength = req.ContentLength
   527  	}
   528  	hstr := newStream(str, conn, datagrams)
   529  	body := newRequestBody(hstr, contentLength, conn.Context(), conn.ReceivedSettings(), conn.Settings)
   530  	req.Body = body
   531  
   532  	if s.Logger != nil {
   533  		s.Logger.Debug("handling request", "method", req.Method, "host", req.Host, "uri", req.RequestURI)
   534  	}
   535  
   536  	ctx := str.Context()
   537  	ctx = context.WithValue(ctx, ServerContextKey, s)
   538  	ctx = context.WithValue(ctx, http.LocalAddrContextKey, conn.LocalAddr())
   539  	ctx = context.WithValue(ctx, RemoteAddrContextKey, conn.RemoteAddr())
   540  	if s.ConnContext != nil {
   541  		ctx = s.ConnContext(ctx, conn.Connection)
   542  		if ctx == nil {
   543  			panic("http3: ConnContext returned nil")
   544  		}
   545  	}
   546  	req = req.WithContext(ctx)
   547  	r := newResponseWriter(hstr, conn, req.Method == http.MethodHead, s.Logger)
   548  	handler := s.Handler
   549  	if handler == nil {
   550  		handler = http.DefaultServeMux
   551  	}
   552  
   553  	// It's the client's responsibility to decide which requests are eligible for 0-RTT.
   554  	var panicked bool
   555  	func() {
   556  		defer func() {
   557  			if p := recover(); p != nil {
   558  				panicked = true
   559  				if p == http.ErrAbortHandler {
   560  					return
   561  				}
   562  				// Copied from net/http/server.go
   563  				const size = 64 << 10
   564  				buf := make([]byte, size)
   565  				buf = buf[:runtime.Stack(buf, false)]
   566  				logger := s.Logger
   567  				if logger == nil {
   568  					logger = slog.Default()
   569  				}
   570  				logger.Error("http: panic serving", "arg", p, "trace", buf)
   571  			}
   572  		}()
   573  		handler.ServeHTTP(r, req)
   574  	}()
   575  
   576  	if r.wasStreamHijacked() {
   577  		return
   578  	}
   579  
   580  	// only write response when there is no panic
   581  	if !panicked {
   582  		// response not written to the client yet, set Content-Length
   583  		if !r.headerWritten {
   584  			if _, haveCL := r.header["Content-Length"]; !haveCL {
   585  				r.header.Set("Content-Length", strconv.FormatInt(r.numWritten, 10))
   586  			}
   587  		}
   588  		r.Flush()
   589  	}
   590  
   591  	// abort the stream when there is a panic
   592  	if panicked {
   593  		str.CancelRead(quic.StreamErrorCode(ErrCodeInternalError))
   594  		str.CancelWrite(quic.StreamErrorCode(ErrCodeInternalError))
   595  		return
   596  	}
   597  
   598  	// If the EOF was read by the handler, CancelRead() is a no-op.
   599  	str.CancelRead(quic.StreamErrorCode(ErrCodeNoError))
   600  
   601  	str.Close()
   602  }
   603  
   604  // Close the server immediately, aborting requests and sending CONNECTION_CLOSE frames to connected clients.
   605  // Close in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.
   606  func (s *Server) Close() error {
   607  	s.mutex.Lock()
   608  	defer s.mutex.Unlock()
   609  
   610  	s.closed = true
   611  
   612  	var err error
   613  	for ln := range s.listeners {
   614  		if cerr := (*ln).Close(); cerr != nil && err == nil {
   615  			err = cerr
   616  		}
   617  	}
   618  	return err
   619  }
   620  
   621  // CloseGracefully shuts down the server gracefully. The server sends a GOAWAY frame first, then waits for either timeout to trigger, or for all running requests to complete.
   622  // CloseGracefully in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.
   623  func (s *Server) CloseGracefully(timeout time.Duration) error {
   624  	// TODO: implement
   625  	return nil
   626  }
   627  
   628  // ErrNoAltSvcPort is the error returned by SetQUICHeaders when no port was found
   629  // for Alt-Svc to announce. This can happen if listening on a PacketConn without a port
   630  // (UNIX socket, for example) and no port is specified in Server.Port or Server.Addr.
   631  var ErrNoAltSvcPort = errors.New("no port can be announced, specify it explicitly using Server.Port or Server.Addr")
   632  
   633  // SetQUICHeaders can be used to set the proper headers that announce that this server supports HTTP/3.
   634  // The values set by default advertise all the ports the server is listening on, but can be
   635  // changed to a specific port by setting Server.Port before launching the server.
   636  // If no listener's Addr().String() returns an address with a valid port, Server.Addr will be used
   637  // to extract the port, if specified.
   638  // For example, a server launched using ListenAndServe on an address with port 443 would set:
   639  //
   640  //	Alt-Svc: h3=":443"; ma=2592000
   641  func (s *Server) SetQUICHeaders(hdr http.Header) error {
   642  	s.mutex.RLock()
   643  	defer s.mutex.RUnlock()
   644  
   645  	if s.altSvcHeader == "" {
   646  		return ErrNoAltSvcPort
   647  	}
   648  	// use the map directly to avoid constant canonicalization since the key is already canonicalized
   649  	hdr["Alt-Svc"] = append(hdr["Alt-Svc"], s.altSvcHeader)
   650  	return nil
   651  }
   652  
   653  // Deprecated: use SetQUICHeaders instead.
   654  func (s *Server) SetQuicHeaders(hdr http.Header) error {
   655  	return s.SetQUICHeaders(hdr)
   656  }
   657  
   658  // ListenAndServeQUIC listens on the UDP network address addr and calls the
   659  // handler for HTTP/3 requests on incoming connections. http.DefaultServeMux is
   660  // used when handler is nil.
   661  func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) error {
   662  	server := &Server{
   663  		Addr:    addr,
   664  		Handler: handler,
   665  	}
   666  	return server.ListenAndServeTLS(certFile, keyFile)
   667  }
   668  
   669  // Deprecated: use ListenAndServeTLS instead.
   670  func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error {
   671  	return ListenAndServeTLS(addr, certFile, keyFile, handler)
   672  }
   673  
   674  // ListenAndServeTLS listens on the given network address for both TLS/TCP and QUIC
   675  // connections in parallel. It returns if one of the two returns an error.
   676  // http.DefaultServeMux is used when handler is nil.
   677  // The correct Alt-Svc headers for QUIC are set.
   678  func ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler) error {
   679  	// Load certs
   680  	var err error
   681  	certs := make([]tls.Certificate, 1)
   682  	certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
   683  	if err != nil {
   684  		return err
   685  	}
   686  	// We currently only use the cert-related stuff from tls.Config,
   687  	// so we don't need to make a full copy.
   688  	config := &tls.Config{
   689  		Certificates: certs,
   690  	}
   691  
   692  	if addr == "" {
   693  		addr = ":https"
   694  	}
   695  
   696  	// Open the listeners
   697  	udpAddr, err := net.ResolveUDPAddr("udp", addr)
   698  	if err != nil {
   699  		return err
   700  	}
   701  	udpConn, err := net.ListenUDP("udp", udpAddr)
   702  	if err != nil {
   703  		return err
   704  	}
   705  	defer udpConn.Close()
   706  
   707  	if handler == nil {
   708  		handler = http.DefaultServeMux
   709  	}
   710  	// Start the servers
   711  	quicServer := &Server{
   712  		TLSConfig: config,
   713  		Handler:   handler,
   714  	}
   715  
   716  	hErr := make(chan error, 1)
   717  	qErr := make(chan error, 1)
   718  	go func() {
   719  		hErr <- http.ListenAndServeTLS(addr, certFile, keyFile, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   720  			quicServer.SetQUICHeaders(w.Header())
   721  			handler.ServeHTTP(w, r)
   722  		}))
   723  	}()
   724  	go func() {
   725  		qErr <- quicServer.Serve(udpConn)
   726  	}()
   727  
   728  	select {
   729  	case err := <-hErr:
   730  		quicServer.Close()
   731  		return err
   732  	case err := <-qErr:
   733  		// Cannot close the HTTP server or wait for requests to complete properly :/
   734  		return err
   735  	}
   736  }