Skip to content

Add streamed response callback with chunked transfer support#1151

Open
Kirpatik wants to merge 1 commit intoCrowCpp:masterfrom
Kirpatik:feature/streamed-response-chunked-send
Open

Add streamed response callback with chunked transfer support#1151
Kirpatik wants to merge 1 commit intoCrowCpp:masterfrom
Kirpatik:feature/streamed-response-chunked-send

Conversation

@Kirpatik
Copy link
Copy Markdown

Summary

This PR adds explicit streamed response sending via callback, including support for unknown total size responses.

Added API

  • Known-length streaming:
    • 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)
  • Unknown-length streaming:
    • set_streamed_body(std::function<size_t(void*, size_t)> reader, std::string content_type = "", size_t chunk_size = 16 * 1024)

Callback contract:

  • Crow provides (buffer, max_size)
  • callback writes up to max_size bytes
  • callback returns written size
  • callback returns 0 to indicate end-of-stream

Behavior

  • HTTP/1.1+ unknown-size responses are sent using Transfer-Encoding: chunked.
  • HTTP/1.0 falls back to connection-close delimited streaming (no chunked encoding).
  • chunk_size is configurable per response; default remains 16KB.
  • HEAD with known-length streamed responses sends headers only and preserves Content-Length.

Implementation Notes

  • Streaming logic is handled in Connection::do_write_streamed().
  • Response metadata now stores stream mode and chunk size.
  • Existing non-streaming behavior is unchanged.

Tests

Added/updated tests:

  • streamed_response
  • streamed_response_unknown_size_chunked
  • streamed_response_unknown_size_http10_fallback
  • streamed_response_head_known_length_no_body

@gittiver
Copy link
Copy Markdown
Member

Sounds great. :)

@gittiver
Copy link
Copy Markdown
Member

The current implementation would block one working thread per running client request, right?

@Kirpatik
Copy link
Copy Markdown
Author

Kirpatik commented Mar 2, 2026

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.

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.

2 participants