fix: skip H2 for tunnel_request (single ops) — completes #1040 (#1041)

Completes [#1040](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/pull/1040) (v1.9.21). #1040 skipped H2 for `tunnel_batch_request_to` but missed `tunnel_request` — the single-op path used for plain `connect` ops. The 16-17s long-poll stalls persisted on full-tunnel sessions that go through the single-op path; this PR closes that gap.

Same fix shape: remove the H2 try/fallback/NonRetryable block from `tunnel_request`, go straight to H1 pool `acquire()`. H2 remains active for relay-mode paths (`do_relay_once_with`, exit-node `relay()`).

## All h2_relay_request call sites audited

| Call site | Function | Mode | H2 skipped? |
|---|---|---|---|
| `do_relay_once_with` | relay | Relay | No (correct — relay benefits from H2) |
| `relay()` exit-node | relay | Relay | No (correct) |
| `tunnel_request` | tunnel single op | Full tunnel | **YES — this PR** |
| `tunnel_batch_request_to` | tunnel batch | Full tunnel | Yes (PR #1040) |
| `tunnel_batch_request_with_timeout` | tunnel batch | Full tunnel | Yes (PR #1040) |

No other full-tunnel paths use H2 after this fix.

## Verified locally on top of v1.9.21

- `cargo test --lib --release`: 209/209 
- `cargo build --release --features ui --bin mhrv-rs-ui`: clean 

Reviewed via Anthropic Claude.

Co-Authored-By: yyoyoian-pixel <noreply@github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
yyoyoian-pixel
2026-05-11 15:04:15 +02:00
committed by GitHub
parent b259dd0df1
commit 2d5bd340c6
+3 -44
View File
@@ -2653,50 +2653,9 @@ impl DomainFronter {
let script_id = self.next_script_id();
let path = format!("/macros/s/{}/exec", script_id);
// h2 fast path. Tunnel ops are stateful — a `connect` may
// have opened an upstream socket; a `data` op may have
// forwarded bytes. Replaying on h1 after the op reached
// Apps Script can corrupt the tunnel session. Only fall back
// when h2 definitely never sent.
// Use the user-configured batch_timeout so Full-mode tuning
// (`request_timeout_secs`) is honored — a fixed cap would let
// legitimately slow batches incorrectly trip strike counters
// on healthy deployments at tunnel_client::fire_batch.
match self
.h2_relay_request(&path, payload.clone(), self.batch_timeout)
.await
{
Ok((status, _hdrs, _resp_body)) if is_h2_fronting_refusal_status(status) => {
// Edge rejected the fronted h2 request. Safe to fall
// back to h1 — the tunnel op never executed because
// Apps Script never received the request.
self.sticky_disable_h2_for_fronting_refusal(
status,
&format!("tunnel op {}", op),
)
.await;
// fall through to h1
}
Ok((status, _hdrs, resp_body)) => {
return self.finalize_tunnel_response(&script_id, status, resp_body);
}
Err((e, RequestSent::No)) => {
tracing::debug!(
"h2 tunnel request pre-send failure: {} — falling back to h1",
e
);
}
Err((e, RequestSent::Maybe)) => {
tracing::warn!(
"h2 tunnel request post-send failure (op={}): {} — \
not replaying on h1 to avoid corrupting the tunnel session",
op,
e
);
return Err(e);
}
}
// Skip h2 for tunnel ops — same rationale as tunnel_batch_request_to
// (PR #1040): tunnel ops are already single HTTP requests, h2
// multiplexing adds no benefit and causes 16-17s long-poll stalls.
let mut entry = self.acquire().await?;
let req_head = format!(