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