void windows_request_context::async_process_response()

in Release/src/http/listener/http_server_httpsys.cpp [861:996]


void windows_request_context::async_process_response()
{
    auto* pServer = static_cast<http_windows_server*>(http_server_api::server_api());

    HTTP_RESPONSE win_api_response;
    ZeroMemory(&win_api_response, sizeof(win_api_response));
    win_api_response.StatusCode = m_response.status_code();
    const std::string reason = utf16_to_utf8(m_response.reason_phrase());
    win_api_response.pReason = reason.c_str();
    win_api_response.ReasonLength = (USHORT)reason.size();
    size_t content_length;

    if (m_compressor || m_response._get_impl()->compressor())
    {
        if (m_response.headers().has(header_names::content_length))
        {
            // Content-Length should not be sent with Transfer-Encoding
            m_response.headers().remove(header_names::content_length);
        }
        if (!m_response._get_impl()->compressor())
        {
            // Temporarily move the compressor to the response, so _get_content_length() will honor it
            m_response._get_impl()->set_compressor(std::move(m_compressor));
        } // else one was already set from a callback, and we'll (blindly) use it
        content_length = m_response._get_impl()->_get_content_length_and_set_compression();
        m_compressor = std::move(m_response._get_impl()->compressor());
        m_response._get_impl()->set_compressor(nullptr);
    }
    else
    {
        if (!m_decompress_header.empty())
        {
            auto factories = m_response._get_impl()->decompress_factories();
            try
            {
                m_decompressor = http::compression::details::get_decompressor_from_header(
                    m_decompress_header, m_decompress_header_type, factories);
                m_decompress_header.clear();
                if (!m_decompressor)
                {
                    http::status_code code = http::status_codes::NotImplemented;
                    if (m_decompress_header_type == http::compression::details::header_types::content_encoding)
                    {
                        code = status_codes::UnsupportedMediaType;
                    }
                    throw http_exception(code);
                }
            }
            catch (http_exception& e)
            {
                // No matching decompressor was supplied via callback
                CancelThreadpoolIo(pServer->m_threadpool_io);
                cancel_request(std::make_exception_ptr(e));
                return;
            }
        }
        content_length = m_response._get_impl()->_get_content_length();
    }

    m_headers = std::unique_ptr<HTTP_UNKNOWN_HEADER[]>(
        new HTTP_UNKNOWN_HEADER[msl::safeint3::SafeInt<size_t>(m_response.headers().size())]);
    m_headers_buffer.resize(msl::safeint3::SafeInt<size_t>(m_response.headers().size()) * 2);

    win_api_response.Headers.UnknownHeaderCount = (USHORT)m_response.headers().size();
    win_api_response.Headers.pUnknownHeaders = m_headers.get();
    int headerIndex = 0;
    for (auto iter = m_response.headers().begin(); iter != m_response.headers().end(); ++iter, ++headerIndex)
    {
        m_headers_buffer[headerIndex * 2] = utf16_to_utf8(iter->first);
        m_headers_buffer[headerIndex * 2 + 1] = utf16_to_utf8(iter->second);
        win_api_response.Headers.pUnknownHeaders[headerIndex].NameLength =
            (USHORT)m_headers_buffer[headerIndex * 2].size();
        win_api_response.Headers.pUnknownHeaders[headerIndex].pName = m_headers_buffer[headerIndex * 2].c_str();
        win_api_response.Headers.pUnknownHeaders[headerIndex].RawValueLength =
            (USHORT)m_headers_buffer[headerIndex * 2 + 1].size();
        win_api_response.Headers.pUnknownHeaders[headerIndex].pRawValue = m_headers_buffer[headerIndex * 2 + 1].c_str();
    }

    // Send response callback function
    m_overlapped.set_http_io_completion(
        [this](DWORD error, DWORD nBytes) { send_response_io_completion(error, nBytes); });

    // Figure out how to send the entity body of the message.
    if (content_length == 0)
    {
        // There's no data. This is easy!
        StartThreadpoolIo(pServer->m_threadpool_io);
        const unsigned long error_code = HttpSendHttpResponse(pServer->m_hRequestQueue,
                                                              m_request_id,
                                                              NULL,
                                                              &win_api_response,
                                                              NULL,
                                                              NULL,
                                                              NULL,
                                                              NULL,
                                                              &m_overlapped,
                                                              NULL);

        if (error_code != NO_ERROR && error_code != ERROR_IO_PENDING)
        {
            CancelThreadpoolIo(pServer->m_threadpool_io);
            cancel_request(std::make_exception_ptr(http_exception(error_code)));
        }

        return;
    }

    // OK, so we need to chunk it up.
    _ASSERTE(content_length > 0);
    m_sending_in_chunks = (content_length != (std::numeric_limits<size_t>::max)());
    m_transfer_encoding = (content_length == (std::numeric_limits<size_t>::max)());
    m_remaining_to_write = content_length;
    if (content_length == (std::numeric_limits<size_t>::max)())
    {
        // Attempt to figure out the remaining length of the input stream
        m_remaining_to_write = m_response._get_impl()->_get_stream_length();
    }

    StartThreadpoolIo(pServer->m_threadpool_io);
    const unsigned long error_code = HttpSendHttpResponse(pServer->m_hRequestQueue,
                                                          m_request_id,
                                                          HTTP_SEND_RESPONSE_FLAG_MORE_DATA,
                                                          &win_api_response,
                                                          NULL,
                                                          NULL,
                                                          NULL,
                                                          NULL,
                                                          &m_overlapped,
                                                          NULL);

    if (error_code != NO_ERROR && error_code != ERROR_IO_PENDING)
    {
        CancelThreadpoolIo(pServer->m_threadpool_io);
        cancel_request(std::make_exception_ptr(http_exception(error_code)));
    }
}