| 3780 | |
| 3781 | template <typename T, typename U> |
| 3782 | inline bool |
| 3783 | write_content_chunked(Stream &strm, const ContentProvider &content_provider, |
| 3784 | const T &is_shutting_down, U &compressor, Error &error) { |
| 3785 | size_t offset = 0; |
| 3786 | auto data_available = true; |
| 3787 | auto ok = true; |
| 3788 | DataSink data_sink; |
| 3789 | |
| 3790 | data_sink.write = [&](const char *d, size_t l) -> bool { |
| 3791 | if (ok) { |
| 3792 | data_available = l > 0; |
| 3793 | offset += l; |
| 3794 | |
| 3795 | std::string payload; |
| 3796 | if (compressor.compress(d, l, false, |
| 3797 | [&](const char *data, size_t data_len) { |
| 3798 | payload.append(data, data_len); |
| 3799 | return true; |
| 3800 | })) { |
| 3801 | if (!payload.empty()) { |
| 3802 | // Emit chunked response header and footer for each chunk |
| 3803 | auto chunk = |
| 3804 | from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n"; |
| 3805 | if (!strm.is_writable() || |
| 3806 | !write_data(strm, chunk.data(), chunk.size())) { |
| 3807 | ok = false; |
| 3808 | } |
| 3809 | } |
| 3810 | } else { |
| 3811 | ok = false; |
| 3812 | } |
| 3813 | } |
| 3814 | return ok; |
| 3815 | }; |
| 3816 | |
| 3817 | auto done_with_trailer = [&](const Headers *trailer) { |
| 3818 | if (!ok) { return; } |
| 3819 | |
| 3820 | data_available = false; |
| 3821 | |
| 3822 | std::string payload; |
| 3823 | if (!compressor.compress(nullptr, 0, true, |
| 3824 | [&](const char *data, size_t data_len) { |
| 3825 | payload.append(data, data_len); |
| 3826 | return true; |
| 3827 | })) { |
| 3828 | ok = false; |
| 3829 | return; |
| 3830 | } |
| 3831 | |
| 3832 | if (!payload.empty()) { |
| 3833 | // Emit chunked response header and footer for each chunk |
| 3834 | auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n"; |
| 3835 | if (!strm.is_writable() || |
| 3836 | !write_data(strm, chunk.data(), chunk.size())) { |
| 3837 | ok = false; |
| 3838 | return; |
| 3839 | } |
no test coverage detected