Add streamed response callback with chunked transfer support - #1151
Add streamed response callback with chunked transfer support#1151Kirpatik wants to merge 1 commit into
Conversation
|
Sounds great. :) |
|
The current implementation would block one working thread per running client request, right? |
Yes. do_write_streamed() is called synchronously from complete_request() and performs blocking asio::write calls in a loop, so one worker thread stays occupied by that request until the stream finishes. |
|
We have a concrete use case for this feature in a C++ real-time imaging application. Our HTTP server exposes a long-lived MJPEG endpoint using: Each connected client waits for a newly produced JPEG frame and then sends the multipart header and image bytes. We currently use cpp-httplib because its chunked content provider supports this model. We evaluated Crow 1.3.3, but response::write() buffers data until response::end(), so it cannot implement this endpoint. The unknown-length set_streamed_body() API proposed here appears to provide exactly the missing functionality. For our expected deployment, the blocking implementation may be acceptable because the number of simultaneous MJPEG viewers is small. However, cancellation when a client disconnects and clean server shutdown are important to us. Is this API still being considered for Crow? We would also be interested in testing the branch with our MJPEG workload and reporting the results. |
|
Somebody has to implement the non blocking approach then it will be merged into Crow. The approach here is Ok but blocking. Therefore I did not merge it as it is not ready for common use cases. |
|
Hi @draminski and @Kirpatik, Thank you for documenting the MJPEG use case and the earlier streaming proposal. PR #1213 now provides non-blocking, unknown-length HTTP/1.1 response streaming. It builds on the provider direction from this PR and addresses the worker-blocking, disconnect, and shutdown concerns raised here. The new asynchronous provider is demand-driven: Crow requests one chunk, waits without occupying the worker, writes that chunk, and only then requests another. Provider results can be completed from another thread and are published onto the connection executor. If you still have access to the MJPEG workload, would you be willing to try the branch and share a short report? The most useful observations would be:
Known-length incremental bodies remain outside this pull request, so feedback on whether that part of #1151 is still needed would also be valuable. Even a brief result with platform, Crow configuration, client count, duration, and pass or failure observations would give the maintainers useful independent evidence. Thank you. |
Summary
This PR adds explicit streamed response sending via callback, including support for unknown total size responses.
Added API
set_streamed_body(std::function<size_t(void*, size_t)> reader, size_t content_length, std::string content_type = "", size_t chunk_size = 16 * 1024)set_streamed_body(std::function<size_t(void*, size_t)> reader, std::string content_type = "", size_t chunk_size = 16 * 1024)Callback contract:
(buffer, max_size)max_sizebytes0to indicate end-of-streamBehavior
Transfer-Encoding: chunked.chunk_sizeis configurable per response; default remains 16KB.HEADwith known-length streamed responses sends headers only and preservesContent-Length.Implementation Notes
Connection::do_write_streamed().Tests
Added/updated tests:
streamed_responsestreamed_response_unknown_size_chunkedstreamed_response_unknown_size_http10_fallbackstreamed_response_head_known_length_no_body