http3

package
v0.0.0-...-6bbe979 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 24, 2024 License: MIT Imports: 25 Imported by: 0

README

HTTP/3

PkgGoDev

This package implements HTTP/3 (RFC 9114), including QPACK (RFC 9204). It aims to provide feature parity with the standard library's HTTP/1.1 and HTTP/2 implementation.

Serving HTTP/3

The easiest way to start an HTTP/3 server is using

mux := http.NewServeMux()
// ... add HTTP handlers to mux ...
// If mux is nil, the http.DefaultServeMux is used.
http3.ListenAndServeQUIC("0.0.0.0:443", "/path/to/cert", "/path/to/key", mux)

ListenAndServeQUIC is a convenience function. For more configurability, set up an http3.Server explicitly:

server := http3.Server{
	Handler:    mux,
	Addr:       "0.0.0.0:443",
	TLSConfig:  http3.ConfigureTLSConfig(&tls.Config{}), // use your tls.Config here
	QuicConfig: &quic.Config{},
}
err := server.ListenAndServe()

The http3.Server provides a number of configuration options, please refer to the documentation for a complete list. The QuicConfig is used to configure the underlying QUIC connection. More details can be found in the documentation of the QUIC package.

It is also possible to manually set up a quic.Transport, and then pass the listener to the server. This is useful when you want to set configuration options on the quic.Transport.

tr := quic.Transport{Conn: conn}
tlsConf := http3.ConfigureTLSConfig(&tls.Config{})  // use your tls.Config here
quicConf := &quic.Config{} // QUIC connection options
server := http3.Server{}
ln, _ := tr.ListenEarly(tlsConf, quicConf)
server.ServeListener(ln)

Alternatively, it is also possible to pass fully established QUIC connections to the HTTP/3 server. This is useful if the QUIC server offers multiple ALPNs (via NextProtos in the tls.Config).

tr := quic.Transport{Conn: conn}
tlsConf := http3.ConfigureTLSConfig(&tls.Config{})  // use your tls.Config here
quicConf := &quic.Config{} // QUIC connection options
server := http3.Server{}
// alternatively, use tr.ListenEarly to accept 0-RTT connections
ln, _ := tr.Listen(tlsConf, quicConf)
for {
	c, _ := ln.Accept()
	switch c.ConnectionState().TLS.NegotiatedProtocol {
	case http3.NextProtoH3:
		go server.ServeQUICConn(c) 
        // ... handle other protocols ...  
	}
}

Dialing HTTP/3

This package provides a http.RoundTripper implementation that can be used on the http.Client:

&http3.RoundTripper{
	TLSClientConfig: &tls.Config{},  // set a TLS client config, if desired
	QuicConfig:      &quic.Config{}, // QUIC connection options
}
defer roundTripper.Close()
client := &http.Client{
	Transport: roundTripper,
}

The http3.RoundTripper provides a number of configuration options, please refer to the documentation for a complete list.

To use a custom quic.Transport, the function used to dial new QUIC connections can be configured:

tr := quic.Transport{}
roundTripper := &http3.RoundTripper{
	TLSClientConfig: &tls.Config{},  // set a TLS client config, if desired 
	QuicConfig:      &quic.Config{}, // QUIC connection options 
	Dial: func(ctx context.Context, addr string, tlsConf *tls.Config, quicConf *quic.Config) (quic.EarlyConnection, error) {
		a, err := net.ResolveUDPAddr("udp", addr)
		if err != nil {
			return nil, err
		}
		return tr.DialEarly(ctx, a, tlsConf, quicConf)
	},
}

Using the same UDP Socket for Server and Roundtripper

Since QUIC demultiplexes packets based on their connection IDs, it is possible allows running a QUIC server and client on the same UDP socket. This also works when using HTTP/3: HTTP requests can be sent from the same socket that a server is listening on.

To achieve this using this package, first initialize a single quic.Transport, and pass a quic.EarlyListner obtained from that transport to http3.Server.ServeListener, and use the DialEarly function of the transport as the Dial function for the http3.RoundTripper.

QPACK

HTTP/3 utilizes QPACK (RFC 9204) for efficient HTTP header field compression. Our implementation, available atquic-go/qpack, provides a minimal implementation of the protocol.

While the current implementation is a fully interoperable implementation of the QPACK protocol, it only uses the static compression table. The dynamic table would allow for more effective compression of frequently transmitted header fields. This can be particularly beneficial in scenarios where headers have considerable redundancy or in high-throughput environments.

If you think that your application would benefit from higher compression efficiency, or if you're interested in contributing improvements here, please let us know in #2424.

Documentation

Index

Constants

View Source
const MethodGet0RTT = "GET_0RTT"

MethodGet0RTT allows a GET request to be sent using 0-RTT. Note that 0-RTT data doesn't provide replay protection.

View Source
const NextProtoH3 = "h3"

NextProtoH3 is the ALPN protocol negotiated during the TLS handshake, for QUIC v1 and v2.

Variables

View Source
var ErrNoAltSvcPort = errors.New("no port can be announced, specify it explicitly using Server.Port or Server.Addr")

ErrNoAltSvcPort is the error returned by SetQuicHeaders when no port was found for Alt-Svc to announce. This can happen if listening on a PacketConn without a port (UNIX socket, for example) and no port is specified in Server.Port or Server.Addr.

View Source
var ErrNoCachedConn = errors.New("http3: no cached connection was available")

ErrNoCachedConn is returned when RoundTripper.OnlyCachedConn is set

View Source
var RemoteAddrContextKey = &contextKey{"remote-addr"}

RemoteAddrContextKey is a context key. It can be used in HTTP handlers with Context.Value to access the remote address of the connection. The associated value will be of type net.Addr.

Use this value instead of http.Request.RemoteAddr if you require access to the remote address of the connection rather than its string representation.

View Source
var ServerContextKey = &contextKey{"http3-server"}

ServerContextKey is a context key. It can be used in HTTP handlers with Context.Value to access the server that started the handler. The associated value will be of type *http3.Server.

Functions

func ConfigureTLSConfig

func ConfigureTLSConfig(tlsConf *tls.Config) *tls.Config

ConfigureTLSConfig creates a new tls.Config which can be used to create a quic.Listener meant for serving http3. The created tls.Config adds the functionality of detecting the used QUIC version in order to set the correct ALPN value for the http3 connection.

func ListenAndServe

func ListenAndServe(addr, certFile, keyFile string, handler http.Handler) error

ListenAndServe listens on the given network address for both TLS/TCP and QUIC connections in parallel. It returns if one of the two returns an error. http.DefaultServeMux is used when handler is nil. The correct Alt-Svc headers for QUIC are set.

func ListenAndServeQUIC

func ListenAndServeQUIC(addr, certFile, keyFile string, handler http.Handler) error

ListenAndServeQUIC listens on the UDP network address addr and calls the handler for HTTP/3 requests on incoming connections. http.DefaultServeMux is used when handler is nil.

func WriteCapsule

func WriteCapsule(w quicvarint.Writer, ct CapsuleType, value []byte) error

WriteCapsule writes a capsule

Types

type CapsuleType

type CapsuleType uint64

CapsuleType is the type of the capsule.

func ParseCapsule

func ParseCapsule(r quicvarint.Reader) (CapsuleType, io.Reader, error)

ParseCapsule parses the header of a Capsule. It returns an io.LimitedReader that can be used to read the Capsule value. The Capsule value must be read entirely (i.e. until the io.EOF) before using r again.

type ErrCode

type ErrCode quic.ApplicationErrorCode
const (
	ErrCodeNoError              ErrCode = 0x100
	ErrCodeGeneralProtocolError ErrCode = 0x101
	ErrCodeInternalError        ErrCode = 0x102
	ErrCodeStreamCreationError  ErrCode = 0x103
	ErrCodeClosedCriticalStream ErrCode = 0x104
	ErrCodeFrameUnexpected      ErrCode = 0x105
	ErrCodeFrameError           ErrCode = 0x106
	ErrCodeExcessiveLoad        ErrCode = 0x107
	ErrCodeIDError              ErrCode = 0x108
	ErrCodeSettingsError        ErrCode = 0x109
	ErrCodeMissingSettings      ErrCode = 0x10a
	ErrCodeRequestRejected      ErrCode = 0x10b
	ErrCodeRequestCanceled      ErrCode = 0x10c
	ErrCodeRequestIncomplete    ErrCode = 0x10d
	ErrCodeMessageError         ErrCode = 0x10e
	ErrCodeConnectError         ErrCode = 0x10f
	ErrCodeVersionFallback      ErrCode = 0x110
	ErrCodeDatagramError        ErrCode = 0x33
)

func (ErrCode) String

func (e ErrCode) String() string

type Error

type Error struct {
	Remote       bool
	ErrorCode    ErrCode
	ErrorMessage string
}

Error is returned from the round tripper (for HTTP clients) and inside the HTTP handler (for HTTP servers) if an HTTP/3 error occurs. See section 8 of RFC 9114.

func (*Error) Error

func (e *Error) Error() string

type FrameType

type FrameType uint64

FrameType is the frame type of a HTTP/3 frame

type HTTPStreamer

type HTTPStreamer interface {
	HTTPStream() Stream
}

The HTTPStreamer allows taking over a HTTP/3 stream. The interface is implemented by: * for the server: the http.Request.Body * for the client: the http.Response.Body On the client side, the stream will be closed for writing, unless the DontCloseRequestStream RoundTripOpt was set. When a stream is taken over, it's the caller's responsibility to close the stream.

type Hijacker

type Hijacker interface {
	StreamCreator() StreamCreator
}

A Hijacker allows hijacking of the stream creating part of a quic.Session from a http.Response.Body. It is used by WebTransport to create WebTransport streams after a session has been established.

type QUICEarlyListener

type QUICEarlyListener interface {
	Accept(context.Context) (quic.EarlyConnection, error)
	Addr() net.Addr
	io.Closer
}

A QUICEarlyListener listens for incoming QUIC connections.

type RoundTripOpt

type RoundTripOpt struct {
	// OnlyCachedConn controls whether the RoundTripper may create a new QUIC connection.
	// If set true and no cached connection is available, RoundTripOpt will return ErrNoCachedConn.
	OnlyCachedConn bool
	// DontCloseRequestStream controls whether the request stream is closed after sending the request.
	// If set, context cancellations have no effect after the response headers are received.
	DontCloseRequestStream bool
}

RoundTripOpt are options for the Transport.RoundTripOpt method.

type RoundTripper

type RoundTripper struct {

	// DisableCompression, if true, prevents the Transport from
	// requesting compression with an "Accept-Encoding: gzip"
	// request header when the Request contains no existing
	// Accept-Encoding value. If the Transport requests gzip on
	// its own and gets a gzipped response, it's transparently
	// decoded in the Response.Body. However, if the user
	// explicitly requested gzip it is not automatically
	// uncompressed.
	DisableCompression bool

	// TLSClientConfig specifies the TLS configuration to use with
	// tls.Client. If nil, the default configuration is used.
	TLSClientConfig *tls.Config

	// QuicConfig is the quic.Config used for dialing new connections.
	// If nil, reasonable default values will be used.
	QuicConfig *quic.Config

	// Enable support for HTTP/3 datagrams.
	// If set to true, QuicConfig.EnableDatagram will be set.
	// See https://datatracker.ietf.org/doc/html/rfc9297.
	EnableDatagrams bool

	// Additional HTTP/3 settings.
	// It is invalid to specify any settings defined by the HTTP/3 draft and the datagram draft.
	AdditionalSettings map[uint64]uint64

	// When set, this callback is called for the first unknown frame parsed on a bidirectional stream.
	// It is called right after parsing the frame type.
	// If parsing the frame type fails, the error is passed to the callback.
	// In that case, the frame type will not be set.
	// Callers can either ignore the frame and return control of the stream back to HTTP/3
	// (by returning hijacked false).
	// Alternatively, callers can take over the QUIC stream (by returning hijacked true).
	StreamHijacker func(FrameType, quic.Connection, quic.Stream, error) (hijacked bool, err error)

	// When set, this callback is called for unknown unidirectional stream of unknown stream type.
	// If parsing the stream type fails, the error is passed to the callback.
	// In that case, the stream type will not be set.
	UniStreamHijacker func(StreamType, quic.Connection, quic.ReceiveStream, error) (hijacked bool)

	// Dial specifies an optional dial function for creating QUIC
	// connections for requests.
	// If Dial is nil, a UDPConn will be created at the first request
	// and will be reused for subsequent connections to other servers.
	Dial func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error)

	// MaxResponseHeaderBytes specifies a limit on how many response bytes are
	// allowed in the server's response header.
	// Zero means to use a default limit.
	MaxResponseHeaderBytes int64
	// contains filtered or unexported fields
}

RoundTripper implements the http.RoundTripper interface

func (*RoundTripper) Close

func (r *RoundTripper) Close() error

Close closes the QUIC connections that this RoundTripper has used. It also closes the underlying UDPConn if it is not nil.

func (*RoundTripper) CloseIdleConnections

func (r *RoundTripper) CloseIdleConnections()

func (*RoundTripper) RoundTrip

func (r *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip does a round trip.

func (*RoundTripper) RoundTripOpt

func (r *RoundTripper) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Response, error)

RoundTripOpt is like RoundTrip, but takes options.

type Server

type Server struct {
	// Addr optionally specifies the UDP address for the server to listen on,
	// in the form "host:port".
	//
	// When used by ListenAndServe and ListenAndServeTLS methods, if empty,
	// ":https" (port 443) is used. See net.Dial for details of the address
	// format.
	//
	// Otherwise, if Port is not set and underlying QUIC listeners do not
	// have valid port numbers, the port part is used in Alt-Svc headers set
	// with SetQuicHeaders.
	Addr string

	// Port is used in Alt-Svc response headers set with SetQuicHeaders. If
	// needed Port can be manually set when the Server is created.
	//
	// This is useful when a Layer 4 firewall is redirecting UDP traffic and
	// clients must use a port different from the port the Server is
	// listening on.
	Port int

	// TLSConfig provides a TLS configuration for use by server. It must be
	// set for ListenAndServe and Serve methods.
	TLSConfig *tls.Config

	// QuicConfig provides the parameters for QUIC connection created with
	// Serve. If nil, it uses reasonable default values.
	//
	// Configured versions are also used in Alt-Svc response header set with
	// SetQuicHeaders.
	QuicConfig *quic.Config

	// Handler is the HTTP request handler to use. If not set, defaults to
	// http.NotFound.
	Handler http.Handler

	// EnableDatagrams enables support for HTTP/3 datagrams.
	// If set to true, QuicConfig.EnableDatagram will be set.
	// See https://datatracker.ietf.org/doc/html/rfc9297.
	EnableDatagrams bool

	// MaxHeaderBytes controls the maximum number of bytes the server will
	// read parsing the request HEADERS frame. It does not limit the size of
	// the request body. If zero or negative, http.DefaultMaxHeaderBytes is
	// used.
	MaxHeaderBytes int

	// AdditionalSettings specifies additional HTTP/3 settings.
	// It is invalid to specify any settings defined by the HTTP/3 draft and the datagram draft.
	AdditionalSettings map[uint64]uint64

	// StreamHijacker, when set, is called for the first unknown frame parsed on a bidirectional stream.
	// It is called right after parsing the frame type.
	// If parsing the frame type fails, the error is passed to the callback.
	// In that case, the frame type will not be set.
	// Callers can either ignore the frame and return control of the stream back to HTTP/3
	// (by returning hijacked false).
	// Alternatively, callers can take over the QUIC stream (by returning hijacked true).
	StreamHijacker func(FrameType, quic.Connection, quic.Stream, error) (hijacked bool, err error)

	// UniStreamHijacker, when set, is called for unknown unidirectional stream of unknown stream type.
	// If parsing the stream type fails, the error is passed to the callback.
	// In that case, the stream type will not be set.
	UniStreamHijacker func(StreamType, quic.Connection, quic.ReceiveStream, error) (hijacked bool)

	// ConnContext optionally specifies a function that modifies
	// the context used for a new connection c. The provided ctx
	// has a ServerContextKey value.
	ConnContext func(ctx context.Context, c quic.Connection) context.Context
	// contains filtered or unexported fields
}

Server is a HTTP/3 server.

func (*Server) Close

func (s *Server) Close() error

Close the server immediately, aborting requests and sending CONNECTION_CLOSE frames to connected clients. Close in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.

func (*Server) CloseGracefully

func (s *Server) CloseGracefully(timeout time.Duration) error

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. CloseGracefully in combination with ListenAndServe() (instead of Serve()) may race if it is called before a UDP socket is established.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.

If s.Addr is blank, ":https" is used.

func (*Server) ListenAndServeTLS

func (s *Server) ListenAndServeTLS(certFile, keyFile string) error

ListenAndServeTLS listens on the UDP address s.Addr and calls s.Handler to handle HTTP/3 requests on incoming connections.

If s.Addr is blank, ":https" is used.

func (*Server) Serve

func (s *Server) Serve(conn net.PacketConn) error

Serve an existing UDP connection. It is possible to reuse the same connection for outgoing connections. Closing the server does not close the connection.

func (*Server) ServeListener

func (s *Server) ServeListener(ln QUICEarlyListener) error

ServeListener serves an existing QUIC listener. Make sure you use http3.ConfigureTLSConfig to configure a tls.Config and use it to construct a http3-friendly QUIC listener. Closing the server does close the listener. ServeListener always returns a non-nil error. After Shutdown or Close, the returned error is http.ErrServerClosed.

func (*Server) ServeQUICConn

func (s *Server) ServeQUICConn(conn quic.Connection) error

ServeQUICConn serves a single QUIC connection.

func (*Server) SetQuicHeaders

func (s *Server) SetQuicHeaders(hdr http.Header) error

SetQuicHeaders can be used to set the proper headers that announce that this server supports HTTP/3. The values set by default advertise all of the ports the server is listening on, but can be changed to a specific port by setting Server.Port before launching the serverr. If no listener's Addr().String() returns an address with a valid port, Server.Addr will be used to extract the port, if specified. For example, a server launched using ListenAndServe on an address with port 443 would set:

Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

type Stream

type Stream quic.Stream

A Stream is a HTTP/3 stream. When writing to and reading from the stream, data is framed in HTTP/3 DATA frames.

type StreamCreator

type StreamCreator interface {
	// Context returns a context that is cancelled when the underlying connection is closed.
	Context() context.Context
	OpenStream() (quic.Stream, error)
	OpenStreamSync(context.Context) (quic.Stream, error)
	OpenUniStream() (quic.SendStream, error)
	OpenUniStreamSync(context.Context) (quic.SendStream, error)
	LocalAddr() net.Addr
	RemoteAddr() net.Addr
	ConnectionState() quic.ConnectionState
}

type StreamType

type StreamType uint64

StreamType is the stream type of a unidirectional stream.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL