Skip to content

perf(http): parse buffered headers without whole-line strings - #604

Open
mizchi wants to merge 1 commit into
moonbitlang:mainfrom
mizchi:perf/http-buffered-header-parser
Open

perf(http): parse buffered headers without whole-line strings#604
mizchi wants to merge 1 commit into
moonbitlang:mainfrom
mizchi:perf/http-buffered-header-parser

Conversation

@mizchi

@mizchi mizchi commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Header lines already present in the transport buffer currently go through async read_until and a whole-line UTF-8 String before the field name and value are copied out. This adds per-header work even when no I/O is needed.

This change adds an internal ReaderBuffer::take_buffered_until helper and a synchronous ASCII header parser. Buffered ASCII lines decode only the name and value; incomplete lines and non-ASCII text retain the existing paths. The borrowed view is consumed before the next read can mutate its buffer. Request-line parsing, cookies, duplicate-header rules, and body framing remain unchanged.

I collected these measurements while benchmarking Mars, my web server implementation. See this report for the methodology, tradeoffs, reproduction commands, harness, and raw data.

  • Native Mars, 64 additional request headers: server instructions/request 593,563 → 415,189 (−30.1%). Standard request headers: −5.8%.
  • Parsing 64 headers with 40-byte values: requested allocation 62,654 → 28,130 bytes (−55%), median time 17.313 → 10.669 µs.
  • With 7-byte input fragments, the fast-path check adds about 1% allocation and was 2.4% slower in the microbenchmark. The benefit is concentrated in already buffered lines.

Measurements use independent native release builds based on upstream 43e41261f99261f4030efbed1970388930229baa, five timing/three allocation rounds and three network rounds. These are short runs on a shared developer machine, not a production throughput claim. This PR is independent of #603.

Validation on macOS:

  • 115 native release tests across HTTP, io, read-buffer, coroutine, and event-loop packages; 104 native debug HTTP/io tests; 52 JS HTTP/io tests.
  • Workspace-wide moon check --deny-warn passes for native, JS, Wasm, and Wasm-GC; formatting and generated interfaces updated.
  • Tests cover fully buffered and 1/7-byte fragmented input, Unicode, invalid UTF-8, duplicate framing headers, repeated header names, and pipelined requests.
  • Mars native tests: 92/92 on baseline and this patch; Mars JS suite: 331/331.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant