Streaming & large transfers
Nothing about a large upload or download is a special code path in ngstone — both proxies are plain io.Copy loops over flow-controlled yamux streams, so the same machinery that handles a tiny JSON response also handles a gigabyte download.
Backpressure and flow control#
A slow browser backpressures all the way down to the app's socket writes. When the reader on one end stops draining, the yamux stream's window fills, the writer blocks, and that block propagates straight back through the tunnel — there is no application-level buffering anywhere in the path.
Constant memory#
Constant-memory forwarding isn't just a design goal — it's asserted in CI. A 1 GiB download and a 100 MB streamed body both run under a runtime.MemStats check that fails the build if memory grows with transfer size instead of staying flat.
1 GiB download ──► constant memory (CI-asserted)100 MB streamed body ──► constant memory (CI-asserted)Body size limits#
The edge caps request bodies at 256 MiB. There are two enforcement paths, because the obvious single-path implementation returns the wrong status code:
- A declared
Content-Lengthover the cap is rejected before the request is proxied — a real413, nothing crosses the tunnel. - A chunked or unknown-length body is enforced with
MaxBytesReader, which also synthesizes a413once the cap is hit.
A chunked 413 may ship a partial body
413to the client. Well-behaved clients never hit this; it only matters if you're debugging a truncated request on the app side.Timeouts on slow apps#
ResponseHeaderTimeout gives your local app 30 seconds to start responding before the edge gives up and returns 504. Once headers arrive, though, there is no duration limit — downloads and SSE streams can run as long as the client stays interested, bounded only by client patience and flow control.
Under the hood, each yamux stream carries a 1 MiB receive window, and peak tunnel buffering across all concurrent streams tops out at 64 × 1 MiB = 64 MiB per side — the largest single buffer in the system. See Limits & timeouts for the full table.