HRESULT WebsocketConnectDoWork()

in Source/WebSocket/WinRT/winrt_websocket.cpp [176:308]


HRESULT WebsocketConnectDoWork(
    _Inout_ XAsyncBlock* asyncBlock,
    _In_opt_ void* executionRoutineContext
    )
try
{
    HCWebsocketHandle websocket = static_cast<HCWebsocketHandle>(executionRoutineContext);
    HC_TRACE_INFORMATION(WEBSOCKET, "Websocket [ID %llu]: Connect executing", TO_ULL(websocket->id));
    std::shared_ptr<winrt_websocket_impl> websocketTask = std::dynamic_pointer_cast<winrt_websocket_impl>(websocket->impl);

    try
    {
        websocketTask->m_connectClosing = false;
        websocketTask->m_messageWebSocket = ref new MessageWebSocket();

        uint32_t numHeaders = 0;
        HCWebSocketGetNumHeaders(websocket, &numHeaders);

        http_internal_string protocolHeader("Sec-WebSocket-Protocol");
        for (uint32_t i = 0; i < numHeaders; i++)
        {
            const char* headerName;
            const char* headerValue;
            HCWebSocketGetHeaderAtIndex(websocket, i, &headerName, &headerValue);

            // The MessageWebSocket API throws a COMException if you try to set the
            // 'Sec-WebSocket-Protocol' header here. It requires you to go through their API instead.
            if (headerName != nullptr && headerValue != nullptr && !str_icmp(headerName, protocolHeader.c_str()))
            {
                http_internal_wstring wHeaderName = utf16_from_utf8(headerName);
                http_internal_wstring wHeaderValue = utf16_from_utf8(headerValue);
                websocketTask->m_messageWebSocket->SetRequestHeader(
                    Platform::StringReference(wHeaderName.c_str()),
                    Platform::StringReference(wHeaderValue.c_str()));
                HC_TRACE_INFORMATION(WEBSOCKET, "Websocket [ID %llu]: Header %d [%s: %s]", TO_ULL(websocket->id), i, headerName, headerValue);
            }
        }

        auto protocols = parse_subprotocols(websocket->SubProtocol());
        for (const auto& value : protocols)
        {
            websocketTask->m_messageWebSocket->Control->SupportedProtocols->Append(Platform::StringReference(value.c_str()));
            HC_TRACE_INFORMATION(WEBSOCKET, "Websocket [ID %llu]: Protocol [%S]", TO_ULL(websocket->id), value.c_str());
        }

        websocketTask->m_context = ref new ReceiveContext();
        websocketTask->m_context->m_websocket = websocket;

        http_internal_wstring aUrl = utf16_from_utf8(websocket->Uri());
        const auto cxUri = ref new Windows::Foundation::Uri(Platform::StringReference(aUrl.c_str()));

        websocketTask->m_messageWebSocket->MessageReceived += ref new TypedEventHandler<MessageWebSocket^, MessageWebSocketMessageReceivedEventArgs^>(websocketTask->m_context, &ReceiveContext::OnReceive);
        websocketTask->m_messageWebSocket->Closed += ref new TypedEventHandler<IWebSocket^, WebSocketClosedEventArgs^>(websocketTask->m_context, &ReceiveContext::OnClosed);

        HC_TRACE_INFORMATION(WEBSOCKET, "Websocket [ID %llu]: connecting to %s", TO_ULL(websocket->id), websocket->Uri().c_str());

        websocketTask->m_connectAsyncOp = websocketTask->m_messageWebSocket->ConnectAsync(cxUri);

        websocketTask->m_connectAsyncOp->Completed = ref new AsyncActionCompletedHandler(
            [websocket, websocketTask, asyncBlock](
                Windows::Foundation::IAsyncAction^ asyncOp,
                Windows::Foundation::AsyncStatus status)
        {
            UNREFERENCED_PARAMETER(status);
            try
            {
                websocketTask->m_messageDataWriter = ref new DataWriter(websocketTask->m_messageWebSocket->OutputStream);
                if (status == Windows::Foundation::AsyncStatus::Error)
                {
                    websocketTask->m_connectAsyncOpResult = E_FAIL;
                }
                else
                {
                    websocketTask->m_connectAsyncOpResult = S_OK;
                }
            }
            catch (Platform::Exception^ e)
            {
                websocketTask->m_connectAsyncOpResult = e->HResult;
            }
            catch (...)
            {
                websocketTask->m_connectAsyncOpResult = E_FAIL;
            }

            if (FAILED(websocketTask->m_connectAsyncOpResult))
            {
                HC_TRACE_ERROR(WEBSOCKET, "Websocket [ID %llu]: connect failed 0x%0.8x", TO_ULL(websocket->id), websocketTask->m_connectAsyncOpResult);

                try
                {
                    // Cleaning up the websocket state
                    websocketTask->m_connectClosing = true;
                    if (websocketTask->m_messageWebSocket != nullptr)
                    {
                        websocketTask->m_messageWebSocket->Close(static_cast<unsigned short>(HCWebSocketCloseStatus::Normal), "");
                        websocketTask->m_messageWebSocket = nullptr;
                    }
                }
                catch (...)
                {
                }
            }
            else
            {
                HC_TRACE_INFORMATION(WEBSOCKET, "Websocket [ID %llu] connect complete", TO_ULL(websocket->id));
            }

            XAsyncComplete(asyncBlock, S_OK, sizeof(WebSocketCompletionResult));
        });
    }
    catch (Platform::Exception^ e)
    {
        try
        {
            // Cleaning up the websocket state
            websocketTask->m_connectClosing = true;
            if (websocketTask->m_messageWebSocket != nullptr)
            {
                websocketTask->m_messageWebSocket->Close(static_cast<unsigned short>(HCWebSocketCloseStatus::Normal), "");
                websocketTask->m_messageWebSocket = nullptr;
            }
        }
        catch (...)
        {
        }

        HC_TRACE_ERROR(WEBSOCKET, "Websocket [ID %llu]: ConnectAsync failed = 0x%0.8x", TO_ULL(websocketTask->m_websocketHandle->id), e->HResult);
        return e->HResult;
    }

    return E_PENDING;
}