This commit is contained in:
Mateusz Gruszczyński committed 2026-10-11 22:12:27 +02:00
1 parent 75104f87ba
commit 4cc994b3bc
86 files changed
+942 -223

No files matched your search

+37 -4
View File
@@ -342,8 +342,24 @@ async fn empty_for_cache(request: &mut Request) -> Result<bool, axum::Error> {
return Ok(false);
}
// Multiplexed transports may end a body with an empty DATA frame.
// On H3 document GET/HEAD, waiting without a bound can stall the entire
// cache/404-routing stage before proxy forwarding even starts. A timed
// probe that finds no FIN conservatively bypasses caching; it never drops
// or consumes a nonempty request body.
let bounded_h3_navigation = request.version() == Version::HTTP_3
&& (request.method() == Method::GET || request.method() == Method::HEAD);
for _ in 0..8 {
match request.body_mut().frame().await {
let next = if bounded_h3_navigation {
match tokio::time::timeout(
std::time::Duration::from_millis(35), request.body_mut().frame(),
).await {
Ok(frame) => frame,
Err(_) => return Ok(false),
}
} else {
request.body_mut().frame().await
};
match next {
None => {
*request.body_mut() = Body::empty();
return Ok(true);
@@ -381,8 +397,6 @@ async fn normalize_h3_h1_unknown_body(
let method = request.method();
if request.version() != Version::HTTP_3
|| upstream_version != Version::HTTP_11
|| method == Method::GET
|| method == Method::HEAD
|| method == Method::CONNECT
|| request.headers().contains_key(http::header::CONTENT_LENGTH)
|| request.body().size_hint().exact().is_some()
@@ -393,8 +407,27 @@ async fn normalize_h3_h1_unknown_body(
// Ignore a small number of empty DATA frames while looking for either the
// stream end or the first frame that carries request semantics. The body
// idle timer in MeteredBody still bounds a stalled peer.
// A full page navigation (e.g. clicking the RustProxy logo) is a GET.
// H3 HEADERS can precede FIN on a document GET. Resolve the receive half
// when FIN arrives promptly, before handing the request to an H1 origin.
// Hyper already special-cases GET/HEAD H1 encoding; this probe targets
// receive-stream completion, not a presumed chunked GET on the wire.
// When the peer is slow or sends a real request body, retain streaming and
// do not delay navigation by the general upload/body-idle deadline.
let navigation_method = method == Method::GET || method == Method::HEAD;
for _ in 0..8 {
match request.body_mut().frame().await {
let next = if navigation_method {
match tokio::time::timeout(
std::time::Duration::from_millis(35),
request.body_mut().frame(),
).await {
Ok(frame) => frame,
Err(_) => return Ok(()),
}
} else {
request.body_mut().frame().await
};
match next {
None => {
*request.body_mut() = Body::empty();
return Ok(());