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