void handle_read_content()

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);
        }
    }