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