in Release/src/http/client/http_client_asio.cpp [1717:1853]
void handle_read_content(const boost::system::error_code& ec)
{
auto writeBuffer = _get_writebuffer();
if (ec)
{
if (ec == boost::asio::error::eof && m_content_length == (std::numeric_limits<size_t>::max)())
{
m_content_length = m_downloaded + m_body_buf.size();
}
else
{
report_error("Failed to read response body", ec, httpclient_errorcode_context::readbody);
return;
}
}
m_timer.reset();
const auto& progress = m_request._get_impl()->_progress_handler();
if (progress)
{
try
{
(*progress)(message_direction::download, m_downloaded);
}
catch (...)
{
report_exception(std::current_exception());
return;
}
}
if (m_downloaded < m_content_length)
{
// more data need to be read
const auto this_request = shared_from_this();
auto read_size = static_cast<size_t>(
(std::min)(static_cast<uint64_t>(m_body_buf.size()), m_content_length - m_downloaded));
if (m_decompressor)
{
std::vector<uint8_t> decompressed;
bool boo =
decompress(boost::asio::buffer_cast<const uint8_t*>(m_body_buf.data()), read_size, decompressed);
if (!boo)
{
this_request->report_exception(std::runtime_error("Failed to decompress the response body"));
return;
}
// It is valid for the decompressor to sometimes return an empty output for a given chunk, the data will
// be flushed when the next chunk is received
if (decompressed.empty())
{
try
{
this_request->m_downloaded += static_cast<uint64_t>(read_size);
this_request->async_read_until_buffersize(
static_cast<size_t>((std::min)(
static_cast<uint64_t>(this_request->m_http_client->client_config().chunksize()),
this_request->m_content_length - this_request->m_downloaded)),
boost::bind(
&asio_context::handle_read_content, this_request, boost::asio::placeholders::error));
}
catch (...)
{
this_request->report_exception(std::current_exception());
return;
}
}
else
{
// Move the decompressed buffer into a shared_ptr to keep it alive until putn_nocopy completes.
// When VS 2013 support is dropped, this should be changed to a unique_ptr plus a move capture.
auto shared_decompressed = std::make_shared<std::vector<uint8_t>>(std::move(decompressed));
writeBuffer.putn_nocopy(shared_decompressed->data(), shared_decompressed->size())
.then([this_request, read_size, shared_decompressed AND_CAPTURE_MEMBER_FUNCTION_POINTERS](
pplx::task<size_t> op) {
size_t writtenSize = 0;
(void)writtenSize;
try
{
writtenSize = op.get();
this_request->m_downloaded += static_cast<uint64_t>(read_size);
this_request->m_body_buf.consume(read_size);
this_request->async_read_until_buffersize(
static_cast<size_t>((std::min)(
static_cast<uint64_t>(this_request->m_http_client->client_config().chunksize()),
this_request->m_content_length - this_request->m_downloaded)),
boost::bind(&asio_context::handle_read_content,
this_request,
boost::asio::placeholders::error));
}
catch (...)
{
this_request->report_exception(std::current_exception());
return;
}
});
}
}
else
{
writeBuffer.putn_nocopy(boost::asio::buffer_cast<const uint8_t*>(m_body_buf.data()), read_size)
.then([this_request AND_CAPTURE_MEMBER_FUNCTION_POINTERS](pplx::task<size_t> op) {
size_t writtenSize = 0;
try
{
writtenSize = op.get();
this_request->m_downloaded += static_cast<uint64_t>(writtenSize);
this_request->m_body_buf.consume(writtenSize);
this_request->async_read_until_buffersize(
static_cast<size_t>((std::min)(
static_cast<uint64_t>(this_request->m_http_client->client_config().chunksize()),
this_request->m_content_length - this_request->m_downloaded)),
boost::bind(&asio_context::handle_read_content,
this_request,
boost::asio::placeholders::error));
}
catch (...)
{
this_request->report_exception(std::current_exception());
return;
}
});
}
}
else
{
// Request is complete no more data to read.
complete_request(m_downloaded);
}
}