#firefox #quic #ietf #mozilla #stream #server #http-3

mozilla/neqo-http3

Neqo,用 Rust 编写的 QUIC 实现

30 个版本

0.8.1 2024 年 7 月 22 日
0.7.9 2024 年 5 月 30 日
0.7.2 2024 年 3 月 13 日
0.6.8 2023 年 11 月 22 日
0.5.4 2021 年 11 月 29 日

#14 in #ietf

1,801 个星标 & 38 个关注者

MIT/Apache

740KB
16K SLoC

HTTP/3 协议

此软件包实现了 RFC9114

实现依赖于

功能

实现了客户端和服务器端的 HTTP/3 协议,尽管服务器端实现不适合用于生产,其主要目的是为了便于测试客户端代码。

WebTransport (草案版本 2) 支持,并且可以使用 Http3Parameters 启用。

与应用程序的交互

驱动 HTTP/3 会话

此软件包不会创建操作系统级别的 UDP 套接字,它生成,即编码,应该作为 UDP 数据包有效载荷发送的数据,并消耗从 UDP 套接字接收的数据。例如,可以使用 std::net::UdpSocketmio::net::UdpSocket 创建 UDP 套接字。

应用程序负责创建套接字,轮询套接字,并从套接字发送和接收数据。

除了接收数据外,HTTP/3会话的操作还可能在一定时间后触发,例如,在一段时间后,数据可能被视为丢失并需要重新传输,包速度控制需要计时器等。实现不使用计时器,而是当处理需要触发时通知应用程序。

驱动HTTP/3会话的核心功能是

  • 在客户端 :
  • process_output 用于生成UDP有效载荷。如果没有生成有效载荷,此函数将返回回调时间,例如process_output 应再次调用的时间。
  • process_input 用于消耗UDP有效载荷。
  • process 将这两个函数合并为一个,即当有UDP有效载荷可用时消耗它,并生成一些要发送的UDP有效载荷,或者返回一个回调时间。
  • 在服务器端 只提供process

与套接字的示例交互

let socket = match UdpSocket::bind(local_addr) {
Err(e) => {
eprintln!("Unable to bind UDP socket: {}", e);
}
Ok(s) => s,
};
let mut client = Http3Client::new(...);

...

// process_output can return 3 values, data to be sent, time duration when process_output should
// be called, and None when Http3Client is done.
match client.process_output(Instant::now()) {
Output::Datagram(dgram) => {
// Send dgram on a socket.
socket.send_to(&dgram[..], dgram.destination())

}
Output::Callback(duration) => {
// the client is idle for “duration”, set read timeout on the socket to this value and
// poll the socket for reading in the meantime.
socket.set_read_timeout(Some(duration)).unwrap();
}
Output::None => {
// client is done.
}
};

...

// Reading new data coming for the network.
match socket.recv_from(&mut buf[..]) {
Ok((sz, remote)) => {
let d = Datagram::new(remote, *local_addr, &buf[..sz]);
client.process_input(d, Instant::now());
}
Err(err) => {
eprintln!("UDP error: {}", err);
}
}

HTTP/3会话事件

Http3ClientHttp3Server 生成事件,可以通过调用 next_event 获取。事件类型分别为 Http3ClientEventHttp3ServerEvent。它们在连接状态改变时、在流上接收到新数据时等通知应用程序。

...

while let Some(event) = client.next_event() {
match event {
Http3ClientEvent::DataReadable { stream_id } => {
println!("New data available on stream {}", stream_id);
}
Http3ClientEvent::StateChange(Http3State::Connected) => {
println!("Http3 session is in state Connected now");
}
_ => {
println!("Unhandled event {:?}", event);
}
}
}

依赖项

~4.5MB
~106K SLoC