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