mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-09-03 07:13:48 +00:00
DataSink has four callbacks, but only write is assigned by every writer that hands a sink to a content provider: write_content_with_progress() write, is_writable write_content_without_length() write, is_writable, done write_content_chunked() all four send_with_content_provider...() write get_multipart_content_provider() write, done (cur_sink) A provider that calls one of the unassigned ones invokes an empty std::function and throws std::bad_function_call. Nothing on that path catches it, so it unwinds out of the thread running the provider and terminates the process. The README's own idiom is enough to hit it: sink.done() is documented for the without-length overload, but a provider registered through set_content_provider() with a length gets a sink where done is empty. Default the three optional callbacks instead. A sink is writable unless a writer says otherwise, and a sink that cannot carry trailers still has to finish, so done_with_trailer() falls back to done(). Capturing this for that is safe because DataSink is neither copyable nor movable. A no-op done() alone would only trade the crash for a hang on the two length-framed paths: both loop until offset reaches the promised length, so a provider that reports itself done without writing would be called again immediately, forever. Both now record that the provider finished and stop, and the short body is reported as a write error. The client path gains that check for the compressor-failure exit as well, which used to send a truncated request body without reporting anything. cur_sink in get_multipart_content_provider() now forwards is_writable from the outer sink, so a provider item asking whether it may keep going gets the stream's answer rather than the default.