Skip to content

Commit 4647fd0

Browse files
enghitaloclaude
andcommitted
vanilla-epoll: answer /upload by Content-Length (engine drains large bodies)
The lib now streams (drains) request bodies larger than 1 MiB instead of buffering them, so for a large upload req.body is empty — but the byte count the upload profile wants is the declared Content-Length. Answer by req.content_length() (falls back to the buffered body length when absent, which also covers small bodies that still take the buffered path). Depends on enghitalo/vanilla#31 (adds HttpRequest.content_length() + the engine drain); the Dockerfile clones lib main, so that PR must merge before this builds. Local (source-built V 0.5.1): upload single-conn 45 req/s/907 MB/s = zix; 32c 303 req/s/6.1 GB/s ~ zix 336/6.7; RSS 14 MB (was ~1 GB buffering). epoll only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5e6b913 commit 4647fd0

1 file changed

Lines changed: 7 additions & 1 deletion

File tree

  • frameworks/vanilla-epoll

frameworks/vanilla-epoll/main.v

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,13 @@ fn handle(req_buffer []u8, _fd int, mut out []u8, mut sh Shared) ! {
145145
}
146146
write_resp(mut out, 'text/plain', sum.str())
147147
} else if route == '/upload' {
148-
write_resp(mut out, 'text/plain', req.body.len.str())
148+
// Answer by Content-Length: the engine streams (drains) large bodies
149+
// instead of buffering them, so req.body may be empty — but the declared
150+
// length is what the upload profile asks for. Falls back to the buffered
151+
// body length when no Content-Length is present (small/bufferable bodies).
152+
cl := req.content_length()
153+
n := if cl >= 0 { i64(cl) } else { i64(req.body.len) }
154+
write_resp(mut out, 'text/plain', n.str())
149155
} else if route.starts_with('/json/') {
150156
count := clamp_count(parse_u_at(route, 6), sh.dataset.len)
151157
mut m := qint(req, qk_m)

0 commit comments

Comments
 (0)