feat(httpd): lazy streaming response body (ILO-482)#784
Merged
Conversation
Add LazyLines enum wrapping StdinLinesHandle/HttpLinesHandle behind a single next_line() interface. Extend handle_http_connection to detect LazyHttpLines/LazyStdinLines as the body value and stream each line as its own chunk, flushed immediately - no full-body buffering. Client disconnect mid-stream exits the thread cleanly instead of panicking. Eager string and list bodies are unchanged.
Add httpd_streaming integration tests: - lazy_body_streams_incrementally: proves a get-stream proxy body emits chunks as the upstream produces them (pads events past 16 KiB to force one line per read and avoid minreq buffer-granularity masking) - eager_list_body_still_works: regression guard for the List body path - client_disconnect_midstream_is_clean: server keeps accepting after a mid-stream client hangup Add examples/httpd-stream.ilo showing the handler pattern.
Update SPEC.md with LazyHttpLines/LazyStdinLines body shape and note that get-stream returns a lazy iterator. Update ai.txt alias line. Add docs/streaming.md covering the lazy body mechanics, the PAD workaround for minreq's read-buffer granularity, and the ILO-488 tail-file follow-up. Add CHANGELOG entry.
…ng upstream (ILO-482) the spawn_httpd readiness probe did a raw TcpStream::connect, which httpd accepts as a real connection and dispatches to a handler thread. for the streaming test that handler proxies an upstream via get-stream, so the probe consumed the upstream's single accept() before the real test request arrived and the test saw an empty body. wait for the "listening on" line on the child's stderr instead, so the handler never runs during startup. apply the same fix to tests/httpd_imports.rs, whose identical probe was the source of the ILO-505 single_file_handler coverage flake. closes ILO-505.
build.rs regenerates ai.txt from SPEC.md; pick up the richer response body comment (t buffered / L t eager chunked / lazy iterator) that the conflict resolution had left on the older one-line form. satisfies the CI ai.txt drift guard.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
An
ilo httpdhandler can now return a lazy response body (aLazyHttpLines/LazyStdinLinesline iterator fromget-stream/pst-streamorfor-line stdin) and httpd streams it chunk-by-chunk: each line the iterator yields is written and flushed as its own chunked-transfer chunk, with no full-body buffering. The connection can stay open indefinitely (SSE, long-poll, tailing a growing source). A client disconnecting mid-stream exits the connection thread cleanly instead of panicking. Eagert(plain string,Content-Length) andL t(eager chunked list) bodies are unchanged.Motivation: crew's
/events/streamlive SSE. Note: the held-open file-tail source is the separate ILO-488 tail-file follow-up; this PR is the response-body plumbing that consumes any lazy line source.Repro before/after
Handler:
rsp status:200 body:(get-stream "http://upstream/")proxying a slow upstream that emits one event every 200ms.handle_http_connectionmaterialised the whole body before writing the first byte, so the client got all events at once at the end (no streaming).event-0well before the upstream has produced all events.What blocked this, and why it's unblocked
The end-to-end streaming test was flaky (~50%). I first suspected
get-streambatching, fixed by ILO-489 (merged), and rebased onto it. The test still flaked after the rebase. Root cause turned out to be a test-harness race, not the implementation:spawn_httpd's readiness probe did a rawTcpStream::connect, which httpd accepts as a real connection and dispatches to a handler thread. For the streaming test that startup handler ranget-streamand consumed the single-serve upstream's oneaccept()before the real test request arrived, so the test saw an empty body. The same probe pattern intests/httpd_imports.rswas the source of the ILO-505 coverage flake.Fix: wait for the
ilo httpd listening online on the child's stderr instead of probing the port, so the handler never runs during startup. Applied to both test files. After the fix,lazy_body_streams_incrementallypassed 10/10 runs deterministically (~1.0s each; failures previously finished in ~0.63s with an empty first chunk).What's in the diff (per commit)
feat(httpd): stream lazy response body chunk-by-chunk-LazyLinesenum +BodyShape::Lazystreaming path inhandle_http_connectiontest(httpd): cover incremental lazy-body streaming- three integration tests +examples/httpd-stream.ilodocs(httpd): document lazy streaming response body- SPEC.md, ai.txt, docs/streaming.md, CHANGELOGtest(httpd): wait for listening line, not tcp probe- the harness deflake; also closes ILO-505docs(httpd): regenerate ai.txt from SPEC.md- picks up the richer body comment, satisfies the CI drift guardTest plan
lazy_body_streams_incrementally10/10 deterministic after the harness fixhttpd_streamingandhttpd_importssuites greencargo fmtcleancargo clippy --release --all-targets --features cranelift -- -D warningscleancargo test --release --features craneliftgreen except the two known baseline doctests (src/pkg.rs, src/verify.rs)Follow-ups