void xmlhttp_http_task::perform_async()

in Source/HTTP/XMLHttp/xmlhttp_http_task.cpp [50:207]


void xmlhttp_http_task::perform_async(
    _Inout_ XAsyncBlock* asyncBlock,
    _In_ HCCallHandle call
    )
{
    try
    {
        const char* url = nullptr;
        const char* method = nullptr;
        HCHttpCallRequestBodyReadFunction requestBodyReadFunction = nullptr;
        size_t requestBodySize = 0;
        void* context = nullptr;
        HCHttpCallRequestGetUrl(call, &method, &url);
        HCHttpCallRequestGetRequestBodyReadFunction(call, &requestBodyReadFunction, &requestBodySize, &context);

        uint32_t numHeaders = 0;
        HCHttpCallRequestGetNumHeaders(call, &numHeaders);

        uint32_t timeoutInSeconds = 0;
        HCHttpCallRequestGetTimeout(call, &timeoutInSeconds);

        HRESULT hr = CoCreateInstance(
            __uuidof(FreeThreadedXMLHTTP60),
            nullptr,
#if HC_XDK_API
            CLSCTX_SERVER,
#else
            CLSCTX_INPROC,
#endif
            __uuidof(IXMLHTTPRequest2),
            reinterpret_cast<void**>(m_hRequest.GetAddressOf()));
        if (FAILED(hr))
        {
            HC_TRACE_ERROR(HTTPCLIENT, "Failure to create IXMLHTTPRequest2 instance 0x%0.8x", hr);
            HCHttpCallResponseSetNetworkErrorCode(call, hr, hr);
            XAsyncComplete(asyncBlock, S_OK, 0);
            return;
        }

        std::shared_ptr<hc_task> httpTask2 = shared_from_this();
        std::shared_ptr<xmlhttp_http_task> httpTask = std::dynamic_pointer_cast<xmlhttp_http_task>(httpTask2);

        http_internal_wstring wMethod = utf16_from_utf8(method);
        http_internal_wstring wUrl = utf16_from_utf8(url);
        hr = m_hRequest->Open(
            wMethod.c_str(),
            wUrl.c_str(),
            Microsoft::WRL::Make<http_request_callback>(httpTask).Get(),
            nullptr,
            nullptr,
            nullptr,
            nullptr);
        if (FAILED(hr))
        {
            HC_TRACE_ERROR(HTTPCLIENT, "Failure to open HTTP request 0x%0.8x", hr);
            HCHttpCallResponseSetNetworkErrorCode(call, hr, hr);
            XAsyncComplete(asyncBlock, S_OK, 0);
            return;
        }

        m_hRequest->SetProperty(XHR_PROP_NO_CRED_PROMPT, TRUE);

        ULONGLONG timeout = static_cast<ULONGLONG>(timeoutInSeconds * 1000);
        m_hRequest->SetProperty(XHR_PROP_TIMEOUT, timeout);

#ifdef XHR_PROP_ONDATA_NEVER
        m_hRequest->SetProperty(XHR_PROP_ONDATA_THRESHOLD, XHR_PROP_ONDATA_NEVER);
#endif

        bool userAgentSet = false;
        for (uint32_t i = 0; i < numHeaders; i++)
        {
            const char* iHeaderName;
            const char* iHeaderValue;
            HCHttpCallRequestGetHeaderAtIndex(call, i, &iHeaderName, &iHeaderValue);
            if (iHeaderName != nullptr && iHeaderValue != nullptr)
            {
                if (xbox::httpclient::str_icmp(iHeaderName, "User-Agent") == 0)
                {
                    userAgentSet = true;
                }

                hr = m_hRequest->SetRequestHeader(utf16_from_utf8(iHeaderName).c_str(), utf16_from_utf8(iHeaderValue).c_str());
            }
        }

        if (!userAgentSet)
        {
            m_hRequest->SetRequestHeader(L"User-Agent", L"libHttpClient/1.0.0.0");
        }

        hr = m_hRequest->SetCustomResponseStream(Microsoft::WRL::Make<http_response_stream>(httpTask).Get());
        if (FAILED(hr))
        {
            HC_TRACE_ERROR(HTTPCLIENT, "Failure to set HTTP response stream 0x%0.8x", hr);
            HCHttpCallResponseSetNetworkErrorCode(call, hr, hr);
            XAsyncComplete(asyncBlock, S_OK, 0);
            return;
        }

        if (requestBodySize > 0 && requestBodyReadFunction != nullptr)
        {
            auto requestStream = Microsoft::WRL::Make<http_request_stream>();
            if (requestStream != nullptr)
            {
                hr = requestStream->init(call);
            }
            else
            {
                hr = E_OUTOFMEMORY;
            }

            if (FAILED(hr))
            {
                HC_TRACE_ERROR(HTTPCLIENT, "[%d] http_request_stream failed in xmlhttp_http_task.", hr);
                HCHttpCallResponseSetNetworkErrorCode(call, E_FAIL, static_cast<uint32_t>(hr));
                XAsyncComplete(asyncBlock, S_OK, 0);
                return;
            }

            hr = m_hRequest->Send(requestStream.Get(), requestBodySize);
        }
        else
        {
            hr = m_hRequest->Send(nullptr, 0);
        }

        if (FAILED(hr))
        {
            HC_TRACE_ERROR(HTTPCLIENT, "Failure to send HTTP request 0x%0.8x", hr);
            HCHttpCallResponseSetNetworkErrorCode(call, hr, hr);
            XAsyncComplete(asyncBlock, S_OK, 0);
            return;
        }
        // If there were no errors so far, HCTaskSetCompleted is called later 
        // http_request_callback::OnResponseReceived 
        // or 
        // http_request_callback::OnError
    }
    catch (std::bad_alloc const& e)
    {
        HC_TRACE_ERROR(HTTPCLIENT, "[%d] std::bad_alloc in xmlhttp_http_task: %s", E_OUTOFMEMORY, e.what());
        HCHttpCallResponseSetNetworkErrorCode(call, E_OUTOFMEMORY, static_cast<uint32_t>(E_OUTOFMEMORY));
        XAsyncComplete(asyncBlock, E_OUTOFMEMORY, 0);
    }
    catch (std::exception const& e)
    {
        HC_TRACE_ERROR(HTTPCLIENT, "[%d] std::exception in xmlhttp_http_task: %s", E_FAIL, e.what());
        HCHttpCallResponseSetNetworkErrorCode(call, E_FAIL, static_cast<uint32_t>(E_FAIL));
        XAsyncComplete(asyncBlock, E_FAIL, 0);
    }
    catch (...)
    {
        HC_TRACE_ERROR(HTTPCLIENT, "[%d] unknown exception in xmlhttp_http_task", E_FAIL);
        HCHttpCallResponseSetNetworkErrorCode(call, E_FAIL, static_cast<uint32_t>(E_FAIL));
        XAsyncComplete(asyncBlock, E_FAIL, 0);
    }
}