feat: std.http read buffers grow on demand toward read_buf_cap

read_buf_cap is now the per-request LIMIT, not a preallocation: slots
start at 16K, double when full (one-step sizing when a Content-Length
declares the body), and keep their grown capacity for slot reuse. At
the limit the refusal distinguishes oversized headers (431) from an
oversized body (413). Unblocks A1: distd accepts multi-hundred-MB
artifact uploads — preallocating that per slot was never an option.
examples/1633 adds a body past the initial capacity echoing intact.
This commit is contained in:
agra
2026-06-12 21:29:13 +03:00
parent 3a97019aa7
commit 8641441fad
40 changed files with 13450 additions and 13109 deletions

View File

@@ -155,6 +155,34 @@ main :: () -> i32 {
socket.close(c2);
print("404 routing ok\n");
// ── 5b. a body past READ_BUF_INITIAL forces the buffer to grow ────
big_n := 50000;
payload : [*]u8 = xx context.allocator.alloc_bytes(xx big_n);
f := 0;
while f < big_n { payload[f] = 97 + cast(u8)(f % 26); f += 1; }
breq := concat("POST /echo HTTP/1.1\r\nHost: t\r\nContent-Length: ", concat(int_to_string(big_n), "\r\n\r\n"));
breq = concat(breq, string.{ ptr = payload, len = xx big_n });
c2b := dial();
if c2b < 0 { print("dial2b failed\n"); return 1; }
bigbuf : [*]u8 = xx context.allocator.alloc_bytes(xx (big_n + 4096));
socket.write(c2b, breq.ptr, xx breq.len);
btotal : i64 = 0;
btries := 0;
while btries < 2000 {
srv.tick(5) catch {};
bn, bre := socket.read_nb(c2b, @bigbuf[btotal], xx (big_n + 4096 - btotal));
if !bre { btotal += bn; }
else if bre == error.Closed { break; }
if resp_complete(bigbuf, btotal) { break; }
btries += 1;
}
bresp := string.{ ptr = bigbuf, len = xx btotal };
if !contains(bresp, "HTTP/1.1 200 OK") { print("case5b: big echo not 200\n"); return 1; }
if !contains(bresp, concat("Content-Length: ", int_to_string(big_n))) { print("case5b: wrong echo length\n"); return 1; }
if bigbuf[btotal - 1] != 97 + cast(u8)((big_n - 1) % 26) { print("case5b: tail byte wrong\n"); return 1; }
socket.close(c2b);
print("big body grows the buffer and echoes intact\n");
// ── 6. half a header is evicted at the request deadline, while a
// healthy client keeps being served ──────────────────────────
c3 := dial();