quiche

Module h3

Source
Expand description

HTTP/3 wire protocol and QPACK implementation.

This module provides a high level API for sending and receiving HTTP/3 requests and responses on top of the QUIC transport protocol.

§Connection setup

HTTP/3 connections require a QUIC transport-layer connection, see Connection setup for a full description of the setup process.

To use HTTP/3, the QUIC connection must be configured with a suitable Application Layer Protocol Negotiation (ALPN) Protocol ID:

let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
config.set_application_protos(quiche::h3::APPLICATION_PROTOCOL)?;

The QUIC handshake is driven by sending and receiving QUIC packets.

Once the handshake has completed, the first step in establishing an HTTP/3 connection is creating its configuration object:

let h3_config = quiche::h3::Config::new()?;

HTTP/3 client and server connections are both created using the with_transport() function, the role is inferred from the type of QUIC connection:

let h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;

§Sending a request

An HTTP/3 client can send a request by using the connection’s send_request() method to queue request headers; sending QUIC packets causes the requests to get sent to the peer:

let req = vec![
    quiche::h3::Header::new(b":method", b"GET"),
    quiche::h3::Header::new(b":scheme", b"https"),
    quiche::h3::Header::new(b":authority", b"quic.tech"),
    quiche::h3::Header::new(b":path", b"/"),
    quiche::h3::Header::new(b"user-agent", b"quiche"),
];

h3_conn.send_request(&mut conn, &req, true)?;

An HTTP/3 client can send a request with additional body data by using the connection’s send_body() method:

let req = vec![
    quiche::h3::Header::new(b":method", b"GET"),
    quiche::h3::Header::new(b":scheme", b"https"),
    quiche::h3::Header::new(b":authority", b"quic.tech"),
    quiche::h3::Header::new(b":path", b"/"),
    quiche::h3::Header::new(b"user-agent", b"quiche"),
];

let stream_id = h3_conn.send_request(&mut conn, &req, false)?;
h3_conn.send_body(&mut conn, stream_id, b"Hello World!", true)?;

§Handling requests and responses

After receiving QUIC packets, HTTP/3 data is processed using the connection’s poll() method. On success, this returns an Event object and an ID corresponding to the stream where the Event originated.

An HTTP/3 server uses poll() to read requests and responds to them using send_response() and send_body():

use quiche::h3::NameValue;

loop {
    match h3_conn.poll(&mut conn) {
        Ok((stream_id, quiche::h3::Event::Headers{list, more_frames})) => {
            let mut headers = list.into_iter();

            // Look for the request's method.
            let method = headers.find(|h| h.name() == b":method").unwrap();

            // Look for the request's path.
            let path = headers.find(|h| h.name() == b":path").unwrap();

            if method.value() == b"GET" && path.value() == b"/" {
                let resp = vec![
                    quiche::h3::Header::new(b":status", 200.to_string().as_bytes()),
                    quiche::h3::Header::new(b"server", b"quiche"),
                ];

                h3_conn.send_response(&mut conn, stream_id, &resp, false)?;
                h3_conn.send_body(&mut conn, stream_id, b"Hello World!", true)?;
            }
        },

        Ok((stream_id, quiche::h3::Event::Data)) => {
            // Request body data, handle it.
        },

        Ok((stream_id, quiche::h3::Event::Finished)) => {
            // Peer terminated stream, handle it.
        },

        Ok((stream_id, quiche::h3::Event::Reset(err))) => {
            // Peer reset the stream, handle it.
        },

        Ok((_flow_id, quiche::h3::Event::PriorityUpdate)) => (),

        Ok((goaway_id, quiche::h3::Event::GoAway)) => {
             // Peer signalled it is going away, handle it.
        },

        Err(quiche::h3::Error::Done) => {
            // Done reading.
            break;
        },

        Err(e) => {
            // An error occurred, handle it.
            break;
        },
    }
}

An HTTP/3 client uses poll() to read responses:

use quiche::h3::NameValue;

loop {
    match h3_conn.poll(&mut conn) {
        Ok((stream_id, quiche::h3::Event::Headers{list, more_frames})) => {
            let status = list.iter().find(|h| h.name() == b":status").unwrap();
            println!("Received {} response on stream {}",
                     std::str::from_utf8(status.value()).unwrap(),
                     stream_id);
        },

        Ok((stream_id, quiche::h3::Event::Data)) => {
            let mut body = vec![0; 4096];

            // Consume all body data received on the stream.
            while let Ok(read) =
                h3_conn.recv_body(&mut conn, stream_id, &mut body)
            {
                println!("Received {} bytes of payload on stream {}",
                         read, stream_id);
            }
        },

        Ok((stream_id, quiche::h3::Event::Finished)) => {
            // Peer terminated stream, handle it.
        },

        Ok((stream_id, quiche::h3::Event::Reset(err))) => {
            // Peer reset the stream, handle it.
        },

        Ok((_prioritized_element_id, quiche::h3::Event::PriorityUpdate)) => (),

        Ok((goaway_id, quiche::h3::Event::GoAway)) => {
             // Peer signalled it is going away, handle it.
        },

        Err(quiche::h3::Error::Done) => {
            // Done reading.
            break;
        },

        Err(e) => {
            // An error occurred, handle it.
            break;
        },
    }
}

§Detecting end of request or response

A single HTTP/3 request or response may consist of several HEADERS and DATA frames; it is finished when the QUIC stream is closed. Calling poll() repeatedly will generate an Event for each of these. The application may use these event to do additional HTTP semantic validation.

§HTTP/3 protocol errors

Quiche is responsible for managing the HTTP/3 connection, ensuring it is in a correct state and validating all messages received by a peer. This mainly takes place in the poll() method. If an HTTP/3 error occurs, quiche will close the connection and send an appropriate CONNECTION_CLOSE frame to the peer. An Error is returned to the application so that it can perform any required tidy up such as closing sockets.

Structs§

  • An HTTP/3 configuration.
  • An HTTP/3 connection.
  • An owned name-value pair representing a raw HTTP header.
  • A non-owned name-value pair representing a raw HTTP header.
  • Extensible Priorities parameters.
  • Statistics about the connection.

Enums§

Constants§

Traits§

  • A trait for types with associated string name and value.

Functions§

  • Generates an HTTP/3 GREASE variable length integer.

Type Aliases§

  • A specialized Result type for quiche HTTP/3 operations.