Compare commits

...

4 Commits

Author SHA1 Message Date
c63f6fcd5f v25.17.4
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-20 03:19:57 +00:00
f3cd4d193e fix(rustproxy-http): prevent HTTP/3 response body streaming from hanging on backend completion 2026-03-20 03:19:57 +00:00
81de611255 v25.17.3
Some checks failed
Default (tags) / security (push) Failing after 0s
Default (tags) / test (push) Failing after 0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-20 02:54:44 +00:00
91598b3be9 fix(repository): no changes detected 2026-03-20 02:54:44 +00:00
4 changed files with 54 additions and 6 deletions

View File

@@ -1,5 +1,16 @@
# Changelog
## 2026-03-20 - 25.17.4 - fix(rustproxy-http)
prevent HTTP/3 response body streaming from hanging on backend completion
- extract and track Content-Length before consuming the response body
- stop the HTTP/3 body loop when the stream reports end-of-stream or the expected byte count has been sent
- add a per-frame idle timeout to avoid indefinite waits on stalled or close-delimited backend bodies
## 2026-03-20 - 25.17.3 - fix(repository)
no changes detected
## 2026-03-20 - 25.17.2 - fix(rustproxy-http)
enable TLS connections for HTTP/3 upstream requests when backend re-encryption or TLS is configured

View File

@@ -1,6 +1,6 @@
{
"name": "@push.rocks/smartproxy",
"version": "25.17.2",
"version": "25.17.4",
"private": false,
"description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.",
"main": "dist_ts/index.js",

View File

@@ -259,6 +259,12 @@ async fn handle_h3_request(
h3_response = h3_response.header(name, value);
}
// Extract content-length for body loop termination (must be before into_body())
let content_length: Option<u64> = response.headers()
.get(hyper::header::CONTENT_LENGTH)
.and_then(|v| v.to_str().ok())
.and_then(|s| s.parse().ok());
// Add Alt-Svc for HTTP/3 advertisement
let alt_svc = route.action.udp.as_ref()
.and_then(|u| u.quic.as_ref())
@@ -279,21 +285,52 @@ async fn handle_h3_request(
// Stream response body back
use http_body_util::BodyExt;
use http_body::Body as _;
let mut body = response.into_body();
let mut total_bytes_out: u64 = 0;
while let Some(frame) = body.frame().await {
match frame {
Ok(frame) => {
// Per-frame idle timeout: if no frame arrives within this duration, assume
// the body is complete (or the backend has stalled). This prevents indefinite
// hangs on close-delimited bodies or when hyper's internal trailers oneshot
// never resolves after all data has been received.
const FRAME_IDLE_TIMEOUT: Duration = Duration::from_secs(30);
loop {
// Layer 1: If the body already knows it is finished (Content-Length
// bodies track remaining bytes internally), break immediately to
// avoid blocking on hyper's internal trailers oneshot.
if body.is_end_stream() {
break;
}
// Layer 3: Per-frame idle timeout safety net
match tokio::time::timeout(FRAME_IDLE_TIMEOUT, body.frame()).await {
Ok(Some(Ok(frame))) => {
if let Some(data) = frame.data_ref() {
total_bytes_out += data.len() as u64;
stream.send_data(Bytes::copy_from_slice(data)).await
.map_err(|e| anyhow::anyhow!("Failed to send H3 data: {}", e))?;
// Layer 2: Content-Length byte count check
if let Some(cl) = content_length {
if total_bytes_out >= cl {
break;
}
}
}
}
Err(e) => {
Ok(Some(Err(e))) => {
warn!("Backend body read error: {}", e);
break;
}
Ok(None) => break, // Body ended naturally
Err(_) => {
debug!(
"H3 body frame idle timeout ({:?}) after {} bytes; finishing stream",
FRAME_IDLE_TIMEOUT, total_bytes_out
);
break;
}
}
}

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartproxy',
version: '25.17.2',
version: '25.17.4',
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
}