v0.34.3
This commit is contained in:
1 parent
8c0de520d7
commit
8f41b39c26
32 files changed
+934
-128
No files matched your search
@@ -7,6 +7,10 @@ pub struct Settings {
|
||||
pub max_concurrent_unistream: u32,
|
||||
/// QUIC idle timeout in seconds; zero disables the transport idle timeout.
|
||||
pub max_idle_timeout: u64,
|
||||
/// Desired effective UDP socket receive buffer (bytes). 0 = OS default.
|
||||
pub udp_receive_buffer_bytes: u32,
|
||||
/// Desired effective UDP socket send buffer (bytes). 0 = OS default.
|
||||
pub udp_send_buffer_bytes: u32,
|
||||
}
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
@@ -16,6 +20,8 @@ impl Default for Settings {
|
||||
max_concurrent_bidistream: 100,
|
||||
max_concurrent_unistream: 100,
|
||||
max_idle_timeout: 10,
|
||||
udp_receive_buffer_bytes: 4 * 1024 * 1024,
|
||||
udp_send_buffer_bytes: 4 * 1024 * 1024,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +44,15 @@ impl Settings {
|
||||
self.max_idle_timeout <= 86400,
|
||||
"HTTP/3 idle timeout must be 0..86400 seconds"
|
||||
);
|
||||
for (name, value) in [
|
||||
("receive", self.udp_receive_buffer_bytes),
|
||||
("send", self.udp_send_buffer_bytes),
|
||||
] {
|
||||
ensure!(
|
||||
value == 0 || (64 * 1024..=16 * 1024 * 1024).contains(&value),
|
||||
"HTTP/3 UDP {name} buffer must be 0 or 65536..16777216 bytes"
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn transport(&self) -> Result<quinn::TransportConfig> {
|
||||
|
||||
+107
-9
@@ -41,9 +41,15 @@ mod tests {
|
||||
}
|
||||
.validate()
|
||||
.is_err());
|
||||
assert!(Settings { udp_receive_buffer_bytes: 1, ..Default::default() }
|
||||
.validate().is_err());
|
||||
assert!(Settings { udp_send_buffer_bytes: 16 * 1024 * 1024 + 1, ..Default::default() }
|
||||
.validate().is_err());
|
||||
assert!(Settings { udp_send_buffer_bytes: 0, ..Default::default() }
|
||||
.validate().is_ok());
|
||||
}
|
||||
#[test]
|
||||
fn alt_svc_only_for_actual_tls_udp_listener() {
|
||||
fn alt_svc_uses_latest_committed_lifetime_and_only_bound_udp() {
|
||||
let binding = Listener {
|
||||
address: "127.0.0.1:8443".parse().unwrap(),
|
||||
tls: true,
|
||||
@@ -52,19 +58,111 @@ mod tests {
|
||||
h2c: false,
|
||||
http3: Some(Settings::default()),
|
||||
};
|
||||
let active = [binding];
|
||||
let mut h = HeaderMap::new();
|
||||
h.insert("alt-svc", "h3=\":9999\"".parse().unwrap());
|
||||
advertise(&mut h, Some(binding.address), true, &[binding]);
|
||||
advertise(&mut h, Some(binding.address), true, &active, &active, true);
|
||||
assert_eq!(h["alt-svc"], "h3=\":8443\"; ma=3600");
|
||||
advertise(&mut h, Some(binding.address), false, &[binding]);
|
||||
|
||||
let mut updated = binding;
|
||||
updated.http3.as_mut().unwrap().alt_svc_max_age = 19;
|
||||
advertise(&mut h, Some(binding.address), true, &active, &[updated], true);
|
||||
assert_eq!(h["alt-svc"], "h3=\":8443\"; ma=19");
|
||||
|
||||
advertise(&mut h, Some(binding.address), false, &active, &[updated], true);
|
||||
assert!(!h.contains_key("alt-svc"));
|
||||
advertise(
|
||||
&mut h,
|
||||
Some("127.0.0.2:8443".parse().unwrap()),
|
||||
true,
|
||||
&[binding],
|
||||
);
|
||||
advertise(&mut h, Some("127.0.0.2:8443".parse().unwrap()), true, &active, &[updated], true);
|
||||
assert!(!h.contains_key("alt-svc"));
|
||||
|
||||
// An intended but not bound H3 socket MUST NOT be advertised.
|
||||
let mut previously_h2_only = binding;
|
||||
previously_h2_only.http3 = None;
|
||||
advertise(&mut h, Some(binding.address), true, &[previously_h2_only], &[updated], true);
|
||||
assert!(!h.contains_key("alt-svc"));
|
||||
}
|
||||
#[test]
|
||||
fn disabling_h3_withdraws_cached_advertisement() {
|
||||
let binding = Listener {
|
||||
address: "0.0.0.0:443".parse().unwrap(),
|
||||
tls: true,
|
||||
http2: true,
|
||||
http2_settings: None,
|
||||
h2c: false,
|
||||
http3: Some(Settings::default()),
|
||||
};
|
||||
let local = Some("192.0.2.2:443".parse().unwrap());
|
||||
let mut h = HeaderMap::new();
|
||||
// Vhost opt-out: immediate Alt-Svc: clear without affecting another host.
|
||||
advertise(&mut h, local, true, &[binding], &[binding], false);
|
||||
assert_eq!(h["alt-svc"], "clear");
|
||||
// Listener opt-out: listener removal requires restart but the header
|
||||
// is withdrawn immediately, while existing H3 sessions may survive.
|
||||
let mut disabled = binding;
|
||||
disabled.http3 = None;
|
||||
advertise(&mut h, local, true, &[binding], &[disabled], true);
|
||||
assert_eq!(h["alt-svc"], "clear");
|
||||
advertise(&mut h, local, true, &[binding], &[], true);
|
||||
assert_eq!(h["alt-svc"], "clear");
|
||||
withdraw_advertisement(&mut h, local, true, &[binding]);
|
||||
assert_eq!(h["alt-svc"], "clear");
|
||||
withdraw_advertisement(&mut h, local, false, &[binding]);
|
||||
assert!(!h.contains_key("alt-svc"));
|
||||
}
|
||||
#[test]
|
||||
fn h3_hot_changes_do_not_misreport_restart() {
|
||||
let active = Listener {
|
||||
address: "127.0.0.1:8443".parse().unwrap(),
|
||||
tls: true,
|
||||
http2: true,
|
||||
http2_settings: Some(crate::settings::Http2Connections::default()),
|
||||
h2c: false,
|
||||
http3: Some(Settings::default()),
|
||||
};
|
||||
assert!(!listeners_require_restart(&[active], &[active]));
|
||||
let mut next = active;
|
||||
let h3 = next.http3.as_mut().unwrap();
|
||||
h3.alt_svc_max_age = 0;
|
||||
h3.max_concurrent_connections = 40;
|
||||
h3.max_concurrent_bidistream = 20;
|
||||
h3.max_concurrent_unistream = 30;
|
||||
h3.max_idle_timeout = 90;
|
||||
assert!(!listeners_require_restart(&[active], &[next]));
|
||||
// A capacity increase above the startup socket/permit cap needs restart.
|
||||
next.http3.as_mut().unwrap().max_concurrent_connections = 513;
|
||||
assert!(listeners_require_restart(&[active], &[next]));
|
||||
next = active;
|
||||
next.http3.as_mut().unwrap().udp_receive_buffer_bytes = 8 * 1024 * 1024;
|
||||
assert!(listeners_require_restart(&[active], &[next]));
|
||||
next = active;
|
||||
next.http3.as_mut().unwrap().udp_send_buffer_bytes = 8 * 1024 * 1024;
|
||||
assert!(listeners_require_restart(&[active], &[next]));
|
||||
next = active;
|
||||
next.http3 = None;
|
||||
assert!(listeners_require_restart(&[active], &[next]));
|
||||
next = active;
|
||||
next.address = "127.0.0.1:9443".parse().unwrap();
|
||||
assert!(listeners_require_restart(&[active], &[next]));
|
||||
next = active;
|
||||
next.http2 = false;
|
||||
assert!(listeners_require_restart(&[active], &[next]));
|
||||
assert!(listeners_require_restart(&[active], &[]));
|
||||
}
|
||||
#[test]
|
||||
fn udp_buffers_keep_legacy_config_compatible() {
|
||||
let old = r#"{"alt_svc_max_age":3600,"max_concurrent_connections":512,"max_concurrent_bidistream":100,"max_concurrent_unistream":100,"max_idle_timeout":10}"#;
|
||||
let settings: Settings = serde_json::from_str(old).unwrap();
|
||||
assert_eq!(settings.udp_receive_buffer_bytes, 4 * 1024 * 1024);
|
||||
assert_eq!(settings.udp_send_buffer_bytes, 4 * 1024 * 1024);
|
||||
assert_eq!(serde_json::from_str::<Settings>(&serde_json::to_string(&settings).unwrap()).unwrap(), settings);
|
||||
}
|
||||
#[test]
|
||||
fn udp_socket_tuning_produces_readable_socket_options() {
|
||||
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
|
||||
let address = socket.local_addr().unwrap();
|
||||
configure_udp_socket(&socket, address, Settings::default());
|
||||
let socket = socket2::SockRef::from(&socket);
|
||||
assert!(socket.recv_buffer_size().unwrap() > 0);
|
||||
assert!(socket.send_buffer_size().unwrap() > 0);
|
||||
}
|
||||
#[test]
|
||||
fn client_cancellation_is_a_stream_event_not_an_http_400() {
|
||||
|
||||
Reference in new issue
Block a user