Skip to content

Add a Sink seam so another protocol engine can serve the same router - #269

Open
xuckless wants to merge 1 commit into
lalinsky:mainfrom
xuckless:response-sink
Open

xuckless wants to merge 1 commit into
lalinsky:mainfrom
xuckless:response-sink

Conversation

@xuckless

Copy link
Copy Markdown
Contributor

The h2-engine sketch (#137) notes it is blocked on a protocol-neutral Response backend. This is a proposal for that seam, kept additive so the HTTP/1.x paths and the ~100 tests that build a Response over a Connection are untouched.

Response

  • Sink (new src/sink.zig): head(status, headers, content_length), interim(status) for 100 Continue, body() writer for unframed bytes, end(trailers), writeError() and peerGone().
  • Response.initSink(arena, io, sink, max_headers). With a sink, sendHeader hands over the head instead of printing a status line, stream sets neither chunked nor the HTTP/1.0 mode (the protocol frames), body bytes go to sink.body(), and the end of the message is sink.end(trailers) (from write, sendBody, the file path and StreamingBodyWriter.end). resolve asks the sink for the cause of a failed write.
  • Response.trailer(name, value): trailer fields, carried by a sink (gRPC status over HTTP/2); dropped over HTTP/1.x.
  • Response.peerGone(), used by the middleware executor instead of res.conn.peerGone().
  • upgradeWebSocket returns null on a sink (HTTP/2 has RFC 8441 instead).
  • Response.io replaces conn.io for files.

Request

  • Request.body_source: ?BodySource (reader + error accessor). BodyReader.streamFramed reads from it when set, so content decoding, body(), forms and multipart work unchanged. 100 Continue goes through sink.interim when the response has a sink.
  • Request.applyEntityHeaders(), factored out of the parser's onHeadersComplete, so an engine fills content_type/content_encoding/content_length the same way.

Server

  • Server.dispatch(req, res): router lookup (400 for an unparseable URL) and the middleware executor, for an engine with its own request loop. handleRequests is not changed to use it, to keep this diff small.

Tests: six Response sink tests (buffered body with length, streamed body unframed and ended once, trailers, HEAD, 204, no WebSocket upgrade), three for Request (body source, gzip through a body source, 100 Continue through the sink), and Server.dispatch routing a request over a sink through the middleware to a handler that sets a trailer. ./check.sh passes on 0.16; build and tests pass on 0.17.

I'm using this from an nghttp2 server engine in my fork; happy to reshape the seam to whatever fits the design you have in mind for #137.

Response writes HTTP/1.x straight to the connection, which leaves an
HTTP/2 engine no way to reuse the router, middleware and handlers.

- Sink (src/sink.zig): head, interim (100 Continue), body writer, end
  with trailers, writeError, peerGone.
- Response.initSink: a response whose head, body bytes and end go to a
  sink; Response.trailer for trailer fields; Response.peerGone. The
  HTTP/1.x paths are unchanged.
- Request.body_source: a body that arrives unframed (HTTP/2 DATA),
  decoded like any other; Request.applyEntityHeaders, factored out of
  the parser.
- Server.dispatch: routes a request through the middleware to its
  handler, for an engine with its own request loop.
@coderabbitai

coderabbitai Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: lalinsky/dusty/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 60cad4a0-42df-4f3f-b2c8-7305b9e30a1f
📥 Commits

Reviewing files that changed from the base of the PR and between d3cb485 and 60a6d30.

📒 Files selected for processing: 9
  • CHANGELOG.md
  • src/middleware.zig
  • src/parser.zig
  • src/request.zig
  • src/response.zig
  • src/root.zig
  • src/server.zig
  • src/server_test.zig
  • src/sink.zig
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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