// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. #include "pch.h" #include "HttpModule.h" #include #include #include using folly::dynamic; using std::function; using std::shared_ptr; using std::string; using std::weak_ptr; using winrt::Microsoft::ReactNative::IReactPropertyBag; using winrt::Microsoft::ReactNative::ReactNonAbiValue; using winrt::Microsoft::ReactNative::ReactPropertyBag; using winrt::Microsoft::ReactNative::ReactPropertyId; using winrt::Windows::Foundation::IInspectable; namespace msrn = winrt::Microsoft::ReactNative; namespace { using Microsoft::React::Modules::SendEvent; using Microsoft::React::Networking::IHttpResource; constexpr wchar_t s_moduleNameW[] = L"Networking"; // React event names constexpr char completedResponse[] = "didCompleteNetworkResponse"; constexpr char receivedResponse[] = "didReceiveNetworkResponse"; constexpr char sentData[] = "didSendNetworkData"; constexpr char receivedIncrementalData[] = "didReceiveNetworkIncrementalData"; constexpr char receivedDataProgress[] = "didReceiveNetworkDataProgress"; constexpr char receivedData[] = "didReceiveNetworkData"; constexpr wchar_t completedResponseW[] = L"didCompleteNetworkResponse"; constexpr wchar_t receivedResponseW[] = L"didReceiveNetworkResponse"; constexpr wchar_t sentDataW[] = L"didSendNetworkData"; constexpr wchar_t receivedIncrementalDataW[] = L"didReceiveNetworkIncrementalData"; constexpr wchar_t receivedDataProgressW[] = L"didReceiveNetworkDataProgress"; constexpr wchar_t receivedDataW[] = L"didReceiveNetworkData"; msrn::ReactModuleProvider s_moduleProvider = msrn::MakeTurboModuleProvider(); } // namespace namespace Microsoft::React { #pragma region HttpTurboModule void HttpTurboModule::Initialize(msrn::ReactContext const &reactContext) noexcept { m_context = reactContext; m_resource = IHttpResource::Make(m_context.Properties().Handle()); m_resource->SetOnRequestSuccess([context = m_context](int64_t requestId) { SendEvent(context, completedResponseW, msrn::JSValueArray{requestId}); }); m_resource->SetOnResponse([context = m_context](int64_t requestId, IHttpResource::Response &&response) { auto headers = msrn::JSValueObject{}; for (auto &header : response.Headers) { headers[header.first] = header.second; } // TODO: Test response content? auto args = msrn::JSValueArray{requestId, response.StatusCode, std::move(headers), response.Url}; SendEvent(context, receivedResponseW, std::move(args)); }); m_resource->SetOnData([context = m_context](int64_t requestId, string &&responseData) { SendEvent(context, receivedDataW, msrn::JSValueArray{requestId, std::move(responseData)}); }); // Explicitly declaring function type to avoid type inference ambiguity. function onDataObject = [context = m_context](int64_t requestId, msrn::JSValueObject &&responseData) { SendEvent(context, receivedDataW, msrn::JSValueArray{requestId, std::move(responseData)}); }; m_resource->SetOnData(std::move(onDataObject)); m_resource->SetOnIncrementalData( [context = m_context](int64_t requestId, string &&responseData, int64_t progress, int64_t total) { SendEvent( context, receivedIncrementalDataW, msrn::JSValueArray{requestId, std::move(responseData), progress, total}); }); m_resource->SetOnDataProgress([context = m_context](int64_t requestId, int64_t progress, int64_t total) { SendEvent(context, receivedDataProgressW, msrn::JSValueArray{requestId, progress, total}); }); m_resource->SetOnResponseComplete([context = m_context](int64_t requestId) { SendEvent(context, completedResponseW, msrn::JSValueArray{requestId}); }); m_resource->SetOnError([context = m_context](int64_t requestId, string &&message, bool isTimeout) { auto args = msrn::JSValueArray{requestId, std::move(message)}; if (isTimeout) { args.push_back(true); } SendEvent(context, completedResponseW, std::move(args)); }); } void HttpTurboModule::SendRequest( ReactNativeSpecs::NetworkingIOSSpec_sendRequest_query &&query, function const &callback) noexcept { m_requestId++; auto &headersObj = query.headers.AsObject(); IHttpResource::Headers headers; for (auto &entry : headersObj) { headers.emplace(entry.first, entry.second.AsString()); } m_resource->SendRequest( std::move(query.method), std::move(query.url), m_requestId, std::move(headers), query.data.MoveObject(), std::move(query.responseType), query.incrementalUpdates, static_cast(query.timeout), query.withCredentials, [&callback](int64_t requestId) { callback({static_cast(requestId)}); }); } void HttpTurboModule::AbortRequest(double requestId) noexcept { m_resource->AbortRequest(static_cast(requestId)); } void HttpTurboModule::ClearCookies(function const &callback) noexcept { m_resource->ClearCookies(); } void HttpTurboModule::AddListener(string &&eventName) noexcept { /*NOOP*/ } void HttpTurboModule::RemoveListeners(double count) noexcept { /*NOOP*/ } #pragma endregion HttpTurboModule /*extern*/ const wchar_t *GetHttpTurboModuleName() noexcept { return s_moduleNameW; } /*extern*/ const msrn::ReactModuleProvider &GetHttpModuleProvider() noexcept { return s_moduleProvider; } } // namespace Microsoft::React