This commit is contained in:
Mateusz Gruszczyński committed 2026-10-04 09:29:10 +02:00
1 parent 2e4aa4df4d
commit 87e571c170
106 files changed
+17952 -6185

No files matched your search

+59 -21
View File
@@ -19,8 +19,8 @@ use http_body_util::BodyExt;
use hyper::upgrade::{OnUpgrade, Upgraded};
use hyper_util::rt::TokioIo;
use rand::{rngs::OsRng, RngCore};
use sha1::{Digest, Sha1};
use serde::Serialize;
use sha1::{Digest, Sha1};
use std::{
collections::BTreeMap,
future::Future,
@@ -288,8 +288,7 @@ pub fn validate_response(
"invalid upstream upgrade"
);
ensure!(
!headers.contains_key("transfer-encoding")
&& !headers.contains_key("content-length"),
!headers.contains_key("transfer-encoding") && !headers.contains_key("content-length"),
"101 response must not include body framing"
);
for value in headers.get_all("connection").iter() {
@@ -829,7 +828,11 @@ pub fn spawn_h2_idle_watch(state: Arc<App>, session: &Arc<TunnelSession>) {
return;
};
if session.inactive_for() >= idle {
session._active.exchange.failed.store(true, Ordering::Relaxed);
session
._active
.exchange
.failed
.store(true, Ordering::Relaxed);
session
._active
.exchange
@@ -858,7 +861,9 @@ pub fn bridge_h2_to_h1(
lease: Option<Arc<ConnectionLease>>,
stop: Option<ServerShutdown>,
) -> Body {
let stop = stop.map(|value| value.0).unwrap_or_else(|| state.shutdown.clone());
let stop = stop
.map(|value| value.0)
.unwrap_or_else(|| state.shutdown.clone());
let session = state.tunnel_registry.register(
exchange.clone(),
upstream_label,
@@ -919,7 +924,10 @@ pub fn bridge_h2_to_h1(
Ok(read) => {
buffer.truncate(read);
record_session_bytes(&exchange, &session, read as u64, false);
Some((Ok::<Bytes, io::Error>(Bytes::from(buffer)), (upstream_read, session, exchange)))
Some((
Ok::<Bytes, io::Error>(Bytes::from(buffer)),
(upstream_read, session, exchange),
))
}
Err(error) => Some((Err(error), (upstream_read, session, exchange))),
}
@@ -1061,21 +1069,32 @@ pub async fn run_h3(
let stop = stop.map(|v| v.0).unwrap_or_else(|| state.shutdown.clone());
let started = Instant::now();
let activity = Arc::new(AtomicU64::new(0));
let session = state.tunnel_registry.register(
exchange.clone(),
upstream_label,
"h3-rfc9220",
stop,
lease,
);
let session =
state
.tunnel_registry
.register(exchange.clone(), upstream_label, "h3-rfc9220", stop, lease);
let stop = session.cancellation();
let upstream = TokioIo::new(upstream);
let (mut upstream_read, mut upstream_write) = tokio::io::split(upstream);
let result = {
let copying = async {
tokio::try_join!(
h3_client_to_backend(receive, &mut upstream_write, &exchange, &activity, started, &session),
backend_to_h3(&mut upstream_read, send, &exchange, &activity, started, &session)
h3_client_to_backend(
receive,
&mut upstream_write,
&exchange,
&activity,
started,
&session
),
backend_to_h3(
&mut upstream_read,
send,
&exchange,
&activity,
started,
&session
)
)?;
Ok::<(), io::Error>(())
};
@@ -1312,22 +1331,41 @@ mod tests {
#[test]
fn rfc8441_h2_response_rejects_h1_framing_fields() {
let handshake = validate_h2(&h2_request()).unwrap();
for (name, value) in [("connection", "close"), ("upgrade", "websocket"), ("content-length", "0")] {
for (name, value) in [
("connection", "close"),
("upgrade", "websocket"),
("content-length", "0"),
] {
let mut headers = HeaderMap::new();
headers.insert(
http::header::HeaderName::from_bytes(name.as_bytes()).unwrap(),
value.parse().unwrap(),
);
assert!(validate_h2_response(&headers, &handshake).is_err(), "accepted forbidden response {name}");
assert!(
validate_h2_response(&headers, &handshake).is_err(),
"accepted forbidden response {name}"
);
}
}
#[test]
fn tunnel_transport_metrics_classify_frontend_protocol() {
assert!(matches!(TunnelTransport::from_protocol("h1-upgrade"), TunnelTransport::H1));
assert!(matches!(TunnelTransport::from_protocol("h2-rfc8441-h1-upstream"), TunnelTransport::H2));
assert!(matches!(TunnelTransport::from_protocol("h2-rfc8441-h2-upstream"), TunnelTransport::H2));
assert!(matches!(TunnelTransport::from_protocol("h3-rfc9220"), TunnelTransport::H3));
assert!(matches!(
TunnelTransport::from_protocol("h1-upgrade"),
TunnelTransport::H1
));
assert!(matches!(
TunnelTransport::from_protocol("h2-rfc8441-h1-upstream"),
TunnelTransport::H2
));
assert!(matches!(
TunnelTransport::from_protocol("h2-rfc8441-h2-upstream"),
TunnelTransport::H2
));
assert!(matches!(
TunnelTransport::from_protocol("h3-rfc9220"),
TunnelTransport::H3
));
}
#[test]