Skip to content

Commit ca24ebd

Browse files
therealalephclaude
andcommitted
chore(release): v1.9.23 — stream large range-parallel downloads (#1042, #1085)
Bumps Cargo.toml v1.9.22 → v1.9.23. Ships @dazzling-no-more's PR #1085 which converts relay_parallel_range into a writer-based API that streams files >50 MiB chunk-by-chunk instead of trying to buffer the whole response and hitting Apps Script's body ceiling. Four-way dispatch (Buffered / Stream / FallbackSingleGet / RejectTooLarge) with O(1) memory range planning + a 16 GiB hostile-origin guard. 209 → 227 lib tests (+18 new). Unblocks GitHub releases / large CDN binaries through apps_script mode without needing Full mode or external mirrors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent aa16abc commit ca24ebd

3 files changed

Lines changed: 27 additions & 2 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mhrv-rs"
3-
version = "1.9.22"
3+
version = "1.9.23"
44
edition = "2021"
55
description = "Rust port of MasterHttpRelayVPN -- DPI bypass via Google Apps Script relay with domain fronting"
66
license = "MIT"

docs/changelog/v1.9.23.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!-- see docs/changelog/v1.1.0.md for the file format: Persian, then `---`, then English. -->
2+
• **Fix: stream range-parallel downloads larger than Apps Script's 50 MiB cap** ([#1042](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/1042) + [PR #1085](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/pull/1085) by @dazzling-no-more). دانلودهای range-capable بزرگ‌تر از ~۵۰ MiB از طریق Apps Script relay با \`504 Relay timeout — Apps Script unresponsive\` fail می‌شد. v2rayN DMG 104 MiB در reported logs canonical repro بود. روت کاز: \`relay_parallel_range\` در 64 MiB ceiling داشت و برای بالاتر به single \`relay()\` fallback می‌کرد که از 50 MiB Apps Script ceiling عبور می‌کرد، Apps Script script رو mid-execution می‌کشت، و 25s timeout. Fix: \`relay_parallel_range\` به writer-based API تبدیل شد که large files رو chunk-by-chunk (هر chunk ≤256 KiB، خوب زیر 50 MiB cap) به client socket stream می‌کنه. ۴-way dispatch: Buffered (≤40 MiB)، Stream (40 MiB-16 GiB)، FallbackSingleGet (wrapper 40-64 MiB)، RejectTooLarge (>16 GiB، quota guard). Lazy range planning با \`saturating_*\` — O(1) memory حتی برای \`u64::MAX\` total (قبل ~6 GB Vec allocation می‌داد). MITM HTTPS + plain HTTP call sites + CORS-aware \`transform_head\` همه updated. ۲۰۹ → **۲۲۷ lib test** (+۱۸ new: dispatch enum، lazy planning، head assembly، head transform، streaming writer، flush behavior، CORS-into-streaming integration).
3+
---
4+
**Fix: stream range-parallel downloads larger than Apps Script's 50 MiB cap** ([#1042](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/issues/1042) + [PR #1085](https://github.com/therealaleph/MasterHttpRelayVPN-RUST/pull/1085) by @dazzling-no-more).
5+
6+
Range-capable downloads larger than ~50 MiB through the Apps Script relay returned `504 Relay timeout — Apps Script unresponsive` instead of the file. The 104 MiB v2rayN DMG in the reported logs was the canonical repro (also fixes @Paymanonline's #1077 report).
7+
8+
**Root cause**: `relay_parallel_range` capped the stitched response at 64 MiB and fell back to a single `relay()` for anything larger. Single-GET routes through Apps Script's ~50 MiB response ceiling, so Apps Script killed the script mid-execution and we hung for the full 25s relay timeout before returning 504.
9+
10+
**Fix**: convert `relay_parallel_range` into a writer-based API that streams large files chunk-by-chunk to the client socket. Each chunk is still one ≤256 KiB Apps Script call (well under the 50 MiB cap); only the host-side buffering changes. Backward-compatible `Vec<u8>` wrapper preserves the pre-v1.9.23 API surface for external library consumers.
11+
12+
Three-way dispatch via `RangeDispatch { Buffered, Stream, FallbackSingleGet, RejectTooLarge }` and the pure `dispatch_range_response(total, streaming_allowed)` predicate:
13+
14+
- **`Buffered`**`total ≤ APPS_SCRIPT_BODY_MAX_BYTES` (40 MiB) on either surface. Existing stitch + single-GET fallback path; fully recovers on chunk failure.
15+
- **`Stream`** — writer API above 40 MiB. Streams; chunk failure flushes the committed prefix and returns `Err` so the `Content-Length` mismatch tells download clients to resume via `Range`.
16+
- **`FallbackSingleGet`** — wrapper above 64 MiB. Falls back to `self.relay()`, matching the pre-v1.9.23 cliff for external library consumers stuck on the old API.
17+
- **`RejectTooLarge`** — writer API above 16 GiB. Refuses with 502; bounds worst-case Apps Script quota drain from a hostile origin advertising an absurd `Content-Range` total.
18+
19+
**Memory bounds**: Lazy `plan_remaining_ranges` via `std::iter::from_fn` + `saturating_*`. Range planning is `O(1)` memory regardless of advertised total — even a `u64::MAX` total no longer drives a ~6 GB `Vec<(u64, u64)>` allocation.
20+
21+
**CORS interaction**: MITM HTTPS and plain-HTTP call sites updated to use `relay_parallel_range_to` with a CORS-aware `transform_head` closure. New `inject_cors_into_head` (head-only variant of `inject_cors_response_headers`) lets the streaming path rewrite ACL headers before the body has been assembled.
22+
23+
209 → **227 lib tests** (+18 new: `RangeDispatch` enum coverage, lazy range planning under `u64::MAX`, `assemble_200_head` correctness, `transform_head` closure invocation, streaming writer chunk-by-chunk semantics, head-then-flush-before-body ordering, CORS-into-streaming cross-module integration).
24+
25+
**User impact**: GitHub release downloads, large CDN binaries, ROM-hack distributions, anything in the 50 MiB – 16 GiB range now downloads successfully through apps_script mode. Previously these required Full mode, an Iran-mirror proxy (#1077), or a friend-with-VPS workaround.

0 commit comments

Comments
 (0)