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