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§
- An HTTP/3 error.
- An HTTP/3 connection event.
- HTTP/3 error codes sent on the wire.
Constants§
- List of ALPN tokens of supported HTTP/3 versions.
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.