1package http3
2
3import (
4	"bytes"
5	"context"
6	"crypto/tls"
7	"errors"
8	"fmt"
9	"io"
10	"net"
11	"net/http"
12	"runtime"
13	"strings"
14	"sync"
15	"sync/atomic"
16	"time"
17
18	"github.com/lucas-clemente/quic-go"
19	"github.com/lucas-clemente/quic-go/internal/handshake"
20	"github.com/lucas-clemente/quic-go/internal/protocol"
21	"github.com/lucas-clemente/quic-go/internal/utils"
22	"github.com/lucas-clemente/quic-go/quicvarint"
23	"github.com/marten-seemann/qpack"
24)
25
26// allows mocking of quic.Listen and quic.ListenAddr
27var (
28	quicListen     = quic.ListenEarly
29	quicListenAddr = quic.ListenAddrEarly
30)
31
32const (
33	nextProtoH3Draft29 = "h3-29"
34	nextProtoH3        = "h3"
35)
36
37const (
38	streamTypeControlStream      = 0
39	streamTypePushStream         = 1
40	streamTypeQPACKEncoderStream = 2
41	streamTypeQPACKDecoderStream = 3
42)
43
44func versionToALPN(v protocol.VersionNumber) string {
45	if v == protocol.Version1 {
46		return nextProtoH3
47	}
48	if v == protocol.VersionTLS || v == protocol.VersionDraft29 {
49		return nextProtoH3Draft29
50	}
51	return ""
52}
53
54// contextKey is a value for use with context.WithValue. It's used as
55// a pointer so it fits in an interface{} without allocation.
56type contextKey struct {
57	name string
58}
59
60func (k *contextKey) String() string { return "quic-go/http3 context value " + k.name }
61
62// ServerContextKey is a context key. It can be used in HTTP
63// handlers with Context.Value to access the server that
64// started the handler. The associated value will be of
65// type *http3.Server.
66var ServerContextKey = &contextKey{"http3-server"}
67
68type requestError struct {
69	err       error
70	streamErr errorCode
71	connErr   errorCode
72}
73
74func newStreamError(code errorCode, err error) requestError {
75	return requestError{err: err, streamErr: code}
76}
77
78func newConnError(code errorCode, err error) requestError {
79	return requestError{err: err, connErr: code}
80}
81
82// Server is a HTTP/3 server.
83type Server struct {
84	*http.Server
85
86	// By providing a quic.Config, it is possible to set parameters of the QUIC connection.
87	// If nil, it uses reasonable default values.
88	QuicConfig *quic.Config
89
90	// Enable support for HTTP/3 datagrams.
91	// If set to true, QuicConfig.EnableDatagram will be set.
92	// See https://www.ietf.org/archive/id/draft-schinazi-masque-h3-datagram-02.html.
93	EnableDatagrams bool
94
95	port uint32 // used atomically
96
97	mutex     sync.Mutex
98	listeners map[*quic.EarlyListener]struct{}
99	closed    utils.AtomicBool
100
101	loggerOnce sync.Once
102	logger     utils.Logger
103}
104
105// ListenAndServe listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.
106func (s *Server) ListenAndServe() error {
107	if s.Server == nil {
108		return errors.New("use of http3.Server without http.Server")
109	}
110	return s.serveImpl(s.TLSConfig, nil)
111}
112
113// ListenAndServeTLS listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.
114func (s *Server) ListenAndServeTLS(certFile, keyFile string) error {
115	var err error
116	certs := make([]tls.Certificate, 1)
117	certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
118	if err != nil {
119		return err
120	}
121	// We currently only use the cert-related stuff from tls.Config,
122	// so we don't need to make a full copy.
123	config := &tls.Config{
124		Certificates: certs,
125	}
126	return s.serveImpl(config, nil)
127}
128
129// Serve an existing UDP connection.
130// It is possible to reuse the same connection for outgoing connections.
131// Closing the server does not close the packet conn.
132func (s *Server) Serve(conn net.PacketConn) error {
133	return s.serveImpl(s.TLSConfig, conn)
134}
135
136func (s *Server) serveImpl(tlsConf *tls.Config, conn net.PacketConn) error {
137	if s.closed.Get() {
138		return http.ErrServerClosed
139	}
140	if s.Server == nil {
141		return errors.New("use of http3.Server without http.Server")
142	}
143	s.loggerOnce.Do(func() {
144		s.logger = utils.DefaultLogger.WithPrefix("server")
145	})
146
147	// The tls.Config we pass to Listen needs to have the GetConfigForClient callback set.
148	// That way, we can get the QUIC version and set the correct ALPN value.
149	baseConf := &tls.Config{
150		GetConfigForClient: func(ch *tls.ClientHelloInfo) (*tls.Config, error) {
151			// determine the ALPN from the QUIC version used
152			proto := nextProtoH3Draft29
153			if qconn, ok := ch.Conn.(handshake.ConnWithVersion); ok {
154				if qconn.GetQUICVersion() == protocol.Version1 {
155					proto = nextProtoH3
156				}
157			}
158			config := tlsConf
159			if tlsConf.GetConfigForClient != nil {
160				getConfigForClient := tlsConf.GetConfigForClient
161				var err error
162				conf, err := getConfigForClient(ch)
163				if err != nil {
164					return nil, err
165				}
166				if conf != nil {
167					config = conf
168				}
169			}
170			if config == nil {
171				return nil, nil
172			}
173			config = config.Clone()
174			config.NextProtos = []string{proto}
175			return config, nil
176		},
177	}
178
179	var ln quic.EarlyListener
180	var err error
181	quicConf := s.QuicConfig
182	if quicConf == nil {
183		quicConf = &quic.Config{}
184	} else {
185		quicConf = s.QuicConfig.Clone()
186	}
187	if s.EnableDatagrams {
188		quicConf.EnableDatagrams = true
189	}
190	if conn == nil {
191		ln, err = quicListenAddr(s.Addr, baseConf, quicConf)
192	} else {
193		ln, err = quicListen(conn, baseConf, quicConf)
194	}
195	if err != nil {
196		return err
197	}
198	s.addListener(&ln)
199	defer s.removeListener(&ln)
200
201	for {
202		sess, err := ln.Accept(context.Background())
203		if err != nil {
204			return err
205		}
206		go s.handleConn(sess)
207	}
208}
209
210// We store a pointer to interface in the map set. This is safe because we only
211// call trackListener via Serve and can track+defer untrack the same pointer to
212// local variable there. We never need to compare a Listener from another caller.
213func (s *Server) addListener(l *quic.EarlyListener) {
214	s.mutex.Lock()
215	if s.listeners == nil {
216		s.listeners = make(map[*quic.EarlyListener]struct{})
217	}
218	s.listeners[l] = struct{}{}
219	s.mutex.Unlock()
220}
221
222func (s *Server) removeListener(l *quic.EarlyListener) {
223	s.mutex.Lock()
224	delete(s.listeners, l)
225	s.mutex.Unlock()
226}
227
228func (s *Server) handleConn(sess quic.EarlySession) {
229	decoder := qpack.NewDecoder(nil)
230
231	// send a SETTINGS frame
232	str, err := sess.OpenUniStream()
233	if err != nil {
234		s.logger.Debugf("Opening the control stream failed.")
235		return
236	}
237	buf := &bytes.Buffer{}
238	quicvarint.Write(buf, streamTypeControlStream) // stream type
239	(&settingsFrame{Datagram: s.EnableDatagrams}).Write(buf)
240	str.Write(buf.Bytes())
241
242	go s.handleUnidirectionalStreams(sess)
243
244	// Process all requests immediately.
245	// It's the client's responsibility to decide which requests are eligible for 0-RTT.
246	for {
247		str, err := sess.AcceptStream(context.Background())
248		if err != nil {
249			s.logger.Debugf("Accepting stream failed: %s", err)
250			return
251		}
252		go func() {
253			rerr := s.handleRequest(sess, str, decoder, func() {
254				sess.CloseWithError(quic.ApplicationErrorCode(errorFrameUnexpected), "")
255			})
256			if rerr.err != nil || rerr.streamErr != 0 || rerr.connErr != 0 {
257				s.logger.Debugf("Handling request failed: %s", err)
258				if rerr.streamErr != 0 {
259					str.CancelWrite(quic.StreamErrorCode(rerr.streamErr))
260				}
261				if rerr.connErr != 0 {
262					var reason string
263					if rerr.err != nil {
264						reason = rerr.err.Error()
265					}
266					sess.CloseWithError(quic.ApplicationErrorCode(rerr.connErr), reason)
267				}
268				return
269			}
270			str.Close()
271		}()
272	}
273}
274
275func (s *Server) handleUnidirectionalStreams(sess quic.EarlySession) {
276	for {
277		str, err := sess.AcceptUniStream(context.Background())
278		if err != nil {
279			s.logger.Debugf("accepting unidirectional stream failed: %s", err)
280			return
281		}
282
283		go func(str quic.ReceiveStream) {
284			streamType, err := quicvarint.Read(&byteReaderImpl{str})
285			if err != nil {
286				s.logger.Debugf("reading stream type on stream %d failed: %s", str.StreamID(), err)
287				return
288			}
289			// We're only interested in the control stream here.
290			switch streamType {
291			case streamTypeControlStream:
292			case streamTypeQPACKEncoderStream, streamTypeQPACKDecoderStream:
293				// Our QPACK implementation doesn't use the dynamic table yet.
294				// TODO: check that only one stream of each type is opened.
295				return
296			case streamTypePushStream: // only the server can push
297				sess.CloseWithError(quic.ApplicationErrorCode(errorStreamCreationError), "")
298				return
299			default:
300				str.CancelRead(quic.StreamErrorCode(errorStreamCreationError))
301				return
302			}
303			f, err := parseNextFrame(str)
304			if err != nil {
305				sess.CloseWithError(quic.ApplicationErrorCode(errorFrameError), "")
306				return
307			}
308			sf, ok := f.(*settingsFrame)
309			if !ok {
310				sess.CloseWithError(quic.ApplicationErrorCode(errorMissingSettings), "")
311				return
312			}
313			if !sf.Datagram {
314				return
315			}
316			// If datagram support was enabled on our side as well as on the client side,
317			// we can expect it to have been negotiated both on the transport and on the HTTP/3 layer.
318			// Note: ConnectionState() will block until the handshake is complete (relevant when using 0-RTT).
319			if s.EnableDatagrams && !sess.ConnectionState().SupportsDatagrams {
320				sess.CloseWithError(quic.ApplicationErrorCode(errorSettingsError), "missing QUIC Datagram support")
321			}
322		}(str)
323	}
324}
325
326func (s *Server) maxHeaderBytes() uint64 {
327	if s.Server.MaxHeaderBytes <= 0 {
328		return http.DefaultMaxHeaderBytes
329	}
330	return uint64(s.Server.MaxHeaderBytes)
331}
332
333func (s *Server) handleRequest(sess quic.Session, str quic.Stream, decoder *qpack.Decoder, onFrameError func()) requestError {
334	frame, err := parseNextFrame(str)
335	if err != nil {
336		return newStreamError(errorRequestIncomplete, err)
337	}
338	hf, ok := frame.(*headersFrame)
339	if !ok {
340		return newConnError(errorFrameUnexpected, errors.New("expected first frame to be a HEADERS frame"))
341	}
342	if hf.Length > s.maxHeaderBytes() {
343		return newStreamError(errorFrameError, fmt.Errorf("HEADERS frame too large: %d bytes (max: %d)", hf.Length, s.maxHeaderBytes()))
344	}
345	headerBlock := make([]byte, hf.Length)
346	if _, err := io.ReadFull(str, headerBlock); err != nil {
347		return newStreamError(errorRequestIncomplete, err)
348	}
349	hfs, err := decoder.DecodeFull(headerBlock)
350	if err != nil {
351		// TODO: use the right error code
352		return newConnError(errorGeneralProtocolError, err)
353	}
354	req, err := requestFromHeaders(hfs)
355	if err != nil {
356		// TODO: use the right error code
357		return newStreamError(errorGeneralProtocolError, err)
358	}
359
360	req.RemoteAddr = sess.RemoteAddr().String()
361	req.Body = newRequestBody(str, onFrameError)
362
363	if s.logger.Debug() {
364		s.logger.Infof("%s %s%s, on stream %d", req.Method, req.Host, req.RequestURI, str.StreamID())
365	} else {
366		s.logger.Infof("%s %s%s", req.Method, req.Host, req.RequestURI)
367	}
368
369	ctx := str.Context()
370	ctx = context.WithValue(ctx, ServerContextKey, s)
371	ctx = context.WithValue(ctx, http.LocalAddrContextKey, sess.LocalAddr())
372	req = req.WithContext(ctx)
373	r := newResponseWriter(str, s.logger)
374	defer func() {
375		if !r.usedDataStream() {
376			r.Flush()
377		}
378	}()
379	handler := s.Handler
380	if handler == nil {
381		handler = http.DefaultServeMux
382	}
383
384	var panicked bool
385	func() {
386		defer func() {
387			if p := recover(); p != nil {
388				// Copied from net/http/server.go
389				const size = 64 << 10
390				buf := make([]byte, size)
391				buf = buf[:runtime.Stack(buf, false)]
392				s.logger.Errorf("http: panic serving: %v\n%s", p, buf)
393				panicked = true
394			}
395		}()
396		handler.ServeHTTP(r, req)
397	}()
398
399	if !r.usedDataStream() {
400		if panicked {
401			r.WriteHeader(500)
402		} else {
403			r.WriteHeader(200)
404		}
405		// If the EOF was read by the handler, CancelRead() is a no-op.
406		str.CancelRead(quic.StreamErrorCode(errorNoError))
407	}
408	return requestError{}
409}
410
411// Close the server immediately, aborting requests and sending CONNECTION_CLOSE frames to connected clients.
412// Close in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.
413func (s *Server) Close() error {
414	s.closed.Set(true)
415
416	s.mutex.Lock()
417	defer s.mutex.Unlock()
418
419	var err error
420	for ln := range s.listeners {
421		if cerr := (*ln).Close(); cerr != nil && err == nil {
422			err = cerr
423		}
424	}
425	return err
426}
427
428// 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.
429// CloseGracefully in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.
430func (s *Server) CloseGracefully(timeout time.Duration) error {
431	// TODO: implement
432	return nil
433}
434
435// SetQuicHeaders can be used to set the proper headers that announce that this server supports QUIC.
436// The values that are set depend on the port information from s.Server.Addr, and currently look like this (if Addr has port 443):
437//  Alt-Svc: quic=":443"; ma=2592000; v="33,32,31,30"
438func (s *Server) SetQuicHeaders(hdr http.Header) error {
439	port := atomic.LoadUint32(&s.port)
440
441	if port == 0 {
442		// Extract port from s.Server.Addr
443		_, portStr, err := net.SplitHostPort(s.Server.Addr)
444		if err != nil {
445			return err
446		}
447		portInt, err := net.LookupPort("tcp", portStr)
448		if err != nil {
449			return err
450		}
451		port = uint32(portInt)
452		atomic.StoreUint32(&s.port, port)
453	}
454
455	// This code assumes that we will use protocol.SupportedVersions if no quic.Config is passed.
456	supportedVersions := protocol.SupportedVersions
457	if s.QuicConfig != nil && len(s.QuicConfig.Versions) > 0 {
458		supportedVersions = s.QuicConfig.Versions
459	}
460	altSvc := make([]string, 0, len(supportedVersions))
461	for _, version := range supportedVersions {
462		v := versionToALPN(version)
463		if len(v) > 0 {
464			altSvc = append(altSvc, fmt.Sprintf(`%s=":%d"; ma=2592000`, v, port))
465		}
466	}
467	hdr.Add("Alt-Svc", strings.Join(altSvc, ","))
468	return nil
469}
470
471// ListenAndServeQUIC listens on the UDP network address addr and calls the
472// handler for HTTP/3 requests on incoming connections. http.DefaultServeMux is
473// used when handler is nil.
474func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) error {
475	server := &Server{
476		Server: &http.Server{
477			Addr:    addr,
478			Handler: handler,
479		},
480	}
481	return server.ListenAndServeTLS(certFile, keyFile)
482}
483
484// ListenAndServe listens on the given network address for both, TLS and QUIC
485// connetions in parallel. It returns if one of the two returns an error.
486// http.DefaultServeMux is used when handler is nil.
487// The correct Alt-Svc headers for QUIC are set.
488func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error {
489	// Load certs
490	var err error
491	certs := make([]tls.Certificate, 1)
492	certs[0], err = tls.LoadX509KeyPair(certFile, keyFile)
493	if err != nil {
494		return err
495	}
496	// We currently only use the cert-related stuff from tls.Config,
497	// so we don't need to make a full copy.
498	config := &tls.Config{
499		Certificates: certs,
500	}
501
502	// Open the listeners
503	udpAddr, err := net.ResolveUDPAddr("udp", addr)
504	if err != nil {
505		return err
506	}
507	udpConn, err := net.ListenUDP("udp", udpAddr)
508	if err != nil {
509		return err
510	}
511	defer udpConn.Close()
512
513	tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
514	if err != nil {
515		return err
516	}
517	tcpConn, err := net.ListenTCP("tcp", tcpAddr)
518	if err != nil {
519		return err
520	}
521	defer tcpConn.Close()
522
523	tlsConn := tls.NewListener(tcpConn, config)
524	defer tlsConn.Close()
525
526	// Start the servers
527	httpServer := &http.Server{
528		Addr:      addr,
529		TLSConfig: config,
530	}
531
532	quicServer := &Server{
533		Server: httpServer,
534	}
535
536	if handler == nil {
537		handler = http.DefaultServeMux
538	}
539	httpServer.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
540		quicServer.SetQuicHeaders(w.Header())
541		handler.ServeHTTP(w, r)
542	})
543
544	hErr := make(chan error)
545	qErr := make(chan error)
546	go func() {
547		hErr <- httpServer.Serve(tlsConn)
548	}()
549	go func() {
550		qErr <- quicServer.Serve(udpConn)
551	}()
552
553	select {
554	case err := <-hErr:
555		quicServer.Close()
556		return err
557	case err := <-qErr:
558		// Cannot close the HTTP server or wait for requests to complete properly :/
559		return err
560	}
561}
562