in Source/HTTP/WinHttp/winhttp_connection.cpp [1002:1155]
void CALLBACK WinHttpConnection::completion_callback(
HINTERNET hRequestHandle,
DWORD_PTR context,
DWORD statusCode,
_In_ void* statusInfo,
DWORD statusInfoLength)
{
// Callback used with WinHTTP to listen for async completions.
UNREFERENCED_PARAMETER(statusInfoLength);
WinHttpCallbackContext* callbackContext = reinterpret_cast<WinHttpCallbackContext*>(context);
WinHttpConnection* pRequestContext = callbackContext->winHttpConnection.get();
try
{
switch (statusCode)
{
case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
{
callback_status_request_error(hRequestHandle, pRequestContext, statusInfo);
break;
}
#if HC_PLATFORM == HC_PLATFORM_GDK
case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
{
callback_status_sending_request(hRequestHandle, pRequestContext, statusInfo);
break;
}
#endif // HC_PLATFORM_GDK
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
{
callback_status_sendrequest_complete(hRequestHandle, pRequestContext, statusInfo);
break;
}
case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
{
if (pRequestContext->m_websocketHandle)
{
callback_websocket_status_headers_available(hRequestHandle, callbackContext);
}
else
{
callback_status_headers_available(hRequestHandle, pRequestContext, statusInfo);
}
break;
}
case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
{
callback_status_data_available(hRequestHandle, pRequestContext, statusInfo);
break;
}
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
{
if (pRequestContext->m_websocketHandle)
{
callback_websocket_status_read_complete(pRequestContext, statusInfo);
}
else
{
callback_status_read_complete(hRequestHandle, pRequestContext, statusInfoLength);
}
break;
}
case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
{
if (pRequestContext->m_websocketHandle)
{
callback_websocket_status_write_complete(pRequestContext);
}
else
{
callback_status_write_complete(hRequestHandle, pRequestContext, statusInfo);
}
break;
}
case WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE:
{
if (pRequestContext->m_websocketHandle)
{
assert(pRequestContext->m_winHttpWebSocketExports.queryCloseStatus);
USHORT closeReason = 0;
DWORD dwReasonLengthConsumed = 0;
pRequestContext->m_winHttpWebSocketExports.queryCloseStatus(pRequestContext->m_hRequest, &closeReason, nullptr, 0, &dwReasonLengthConsumed);
pRequestContext->on_websocket_disconnected(closeReason);
}
break;
}
case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
{
callback_status_secure_failure(hRequestHandle, pRequestContext, statusInfo);
break;
}
case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
{
// For WebSocket, we will also get a notification when the original request handle is closed. We have no action to take in that case
if (hRequestHandle == pRequestContext->m_hRequest)
{
HC_TRACE_VERBOSE(HTTPCLIENT, "WinHttpConnection [ID %llu] [TID %ul] WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING", TO_ULL(HCHttpCallGetId(pRequestContext->m_call)), GetCurrentThreadId());
// WinHttp Shutdown complete. WinHttp guarantees we will get no more callbacks for this request so we can safely cleanup context.
// Ensure WinHttpCallbackContext is cleaned before invoking callback in case this is happening during HCCleanup
HC_UNIQUE_PTR<WinHttpCallbackContext> reclaim{ callbackContext };
ConnectionClosedCallback connectionClosedCallback{};
{
win32_cs_autolock cs{ &pRequestContext->m_lock };
pRequestContext->m_hRequest = nullptr;
connectionClosedCallback = std::move(pRequestContext->m_connectionClosedCallback);
pRequestContext->m_state = ConnectionState::Closed;
}
reclaim.reset();
if (connectionClosedCallback)
{
connectionClosedCallback();
}
}
break;
}
default:
{
HC_TRACE_VERBOSE(HTTPCLIENT, "WinHttpConnection WinHttp callback statusCode=%ul", statusCode);
break;
}
}
}
catch (std::bad_alloc const& e)
{
HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [%d] std::bad_alloc in completion_callback: %s", E_OUTOFMEMORY, e.what());
pRequestContext->complete_task(E_OUTOFMEMORY);
}
catch (std::exception const& e)
{
HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [%d] std::exception in completion_callback: %s", E_FAIL, e.what());
pRequestContext->complete_task(E_FAIL);
}
catch (...)
{
HC_TRACE_ERROR(HTTPCLIENT, "WinHttpConnection [%d] unknown exception in completion_callback", E_FAIL);
pRequestContext->complete_task(E_FAIL);
}
}