v0.25.0
This commit is contained in:
1 parent
2e4aa4df4d
commit
87e571c170
106 files changed
+17952
-6185
No files matched your search
+59
-21
@@ -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]
|
||||
|
||||
Reference in new issue
Block a user