From d97a14ee45d2e43615aeb17db221b8072cabb9c4 Mon Sep 17 00:00:00 2001 From: Jason Sandlin Date: Fri, 8 Aug 2025 13:35:43 -0700 Subject: [PATCH 1/3] Making XCurl be delay-loaded --- .../libHttpClient.GDK.Shared.vcxitems | 2 + Build/libHttpClient.GDK.props | 1 + .../libHttpClient.GDK.vcxproj | 2 +- Include/httpClient/pal.h | 1 + Source/HTTP/Curl/CurlDynamicLoader.cpp | 129 ++++++++++++++++++ Source/HTTP/Curl/CurlDynamicLoader.h | 85 ++++++++++++ Source/HTTP/Curl/CurlEasyRequest.cpp | 39 ++++++ Source/HTTP/Curl/CurlEasyRequest.h | 10 +- Source/HTTP/Curl/CurlMulti.cpp | 63 ++++++++- Source/HTTP/Curl/CurlProvider.cpp | 32 ++++- Source/HTTP/Curl/CurlProvider.h | 10 ++ 11 files changed, 368 insertions(+), 6 deletions(-) create mode 100644 Source/HTTP/Curl/CurlDynamicLoader.cpp create mode 100644 Source/HTTP/Curl/CurlDynamicLoader.h diff --git a/Build/libHttpClient.GDK.Shared/libHttpClient.GDK.Shared.vcxitems b/Build/libHttpClient.GDK.Shared/libHttpClient.GDK.Shared.vcxitems index 9f2f9e16..a67a6db5 100644 --- a/Build/libHttpClient.GDK.Shared/libHttpClient.GDK.Shared.vcxitems +++ b/Build/libHttpClient.GDK.Shared/libHttpClient.GDK.Shared.vcxitems @@ -15,6 +15,7 @@ + @@ -25,6 +26,7 @@ + diff --git a/Build/libHttpClient.GDK.props b/Build/libHttpClient.GDK.props index 705f9f29..9dced8ab 100644 --- a/Build/libHttpClient.GDK.props +++ b/Build/libHttpClient.GDK.props @@ -65,6 +65,7 @@ false ProgramDatabase __WRL_NO_DEFAULT_LIB__;_LIB;$(libHttpClientDefine);%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories);$(GameDKLatest)GRDK\ExtensionLibraries\Xbox.XCurl.API\Include /bigobj %(AdditionalOptions) stdcpp17 diff --git a/Build/libHttpClient.GDK/libHttpClient.GDK.vcxproj b/Build/libHttpClient.GDK/libHttpClient.GDK.vcxproj index be66a8be..aa312804 100644 --- a/Build/libHttpClient.GDK/libHttpClient.GDK.vcxproj +++ b/Build/libHttpClient.GDK/libHttpClient.GDK.vcxproj @@ -3,7 +3,7 @@ {A5A6E02A-21BA-4D55-9FB9-7B24DEDD3743} DynamicLibrary - Xbox.XCurl.API + ; v140 v141 v142 diff --git a/Include/httpClient/pal.h b/Include/httpClient/pal.h index 09e4275a..824fa601 100644 --- a/Include/httpClient/pal.h +++ b/Include/httpClient/pal.h @@ -461,6 +461,7 @@ typedef struct _LIST_ENTRY { #define E_HC_NETWORK_NOT_INITIALIZED MAKE_E_HC(0x5007) // 0x89235007 #define E_HC_INTERNAL_STILLINUSE MAKE_E_HC(0x5008) // 0x89235008 #define E_HC_COMPRESSION_ENABLED MAKE_E_HC(0x5009) // 0x89235009 +#define E_HC_XCURL_REQUIRED MAKE_E_HC(0x500A) // 0x8923500A typedef uint32_t HCMemoryType; typedef struct HC_WEBSOCKET_OBSERVER* HCWebsocketHandle; diff --git a/Source/HTTP/Curl/CurlDynamicLoader.cpp b/Source/HTTP/Curl/CurlDynamicLoader.cpp new file mode 100644 index 00000000..7ea4cd0d --- /dev/null +++ b/Source/HTTP/Curl/CurlDynamicLoader.cpp @@ -0,0 +1,129 @@ +#include "pch.h" +#include "CurlDynamicLoader.h" + +#if HC_PLATFORM == HC_PLATFORM_GDK + +#include +#include + +namespace xbox +{ +namespace httpclient +{ + +std::mutex CurlDynamicLoader::s_initMutex; +HC_UNIQUE_PTR CurlDynamicLoader::s_instance; + +CurlDynamicLoader& CurlDynamicLoader::GetInstance() +{ + std::lock_guard lock(s_initMutex); + if (!s_instance) + { + HC_TRACE_VERBOSE(HTTPCLIENT, "Creating CurlDynamicLoader instance"); + s_instance = HC_UNIQUE_PTR(new CurlDynamicLoader()); + } + return *s_instance; +} + +CurlDynamicLoader::~CurlDynamicLoader() +{ + Cleanup(); +} + +bool CurlDynamicLoader::Initialize() +{ + if (m_curlLibrary != nullptr) + { + HC_TRACE_VERBOSE(HTTPCLIENT, "XCurl.dll already loaded"); + return true; // Already loaded + } + + HC_TRACE_INFORMATION(HTTPCLIENT, "Attempting to load XCurl.dll"); + + // Try to load XCurl.dll + m_curlLibrary = LoadLibraryA("XCurl.dll"); + if (m_curlLibrary == nullptr) + { + DWORD error = GetLastError(); + HC_TRACE_ERROR(HTTPCLIENT, "Failed to load XCurl.dll. Error code: %lu", error); + return false; + } + + // Load all required functions + bool success = true; + + success &= LoadFunction(reinterpret_cast(curl_global_init_fn), "curl_global_init"); + success &= LoadFunction(reinterpret_cast(curl_global_cleanup_fn), "curl_global_cleanup"); + success &= LoadFunction(reinterpret_cast(curl_easy_init_fn), "curl_easy_init"); + success &= LoadFunction(reinterpret_cast(curl_easy_cleanup_fn), "curl_easy_cleanup"); + success &= LoadFunction(reinterpret_cast(curl_easy_setopt_fn), "curl_easy_setopt"); + success &= LoadFunction(reinterpret_cast(curl_easy_getinfo_fn), "curl_easy_getinfo"); + success &= LoadFunction(reinterpret_cast(curl_easy_strerror_fn), "curl_easy_strerror"); + success &= LoadFunction(reinterpret_cast(curl_slist_append_fn), "curl_slist_append"); + success &= LoadFunction(reinterpret_cast(curl_slist_free_all_fn), "curl_slist_free_all"); + success &= LoadFunction(reinterpret_cast(curl_multi_init_fn), "curl_multi_init"); + success &= LoadFunction(reinterpret_cast(curl_multi_cleanup_fn), "curl_multi_cleanup"); + success &= LoadFunction(reinterpret_cast(curl_multi_add_handle_fn), "curl_multi_add_handle"); + success &= LoadFunction(reinterpret_cast(curl_multi_remove_handle_fn), "curl_multi_remove_handle"); + success &= LoadFunction(reinterpret_cast(curl_multi_perform_fn), "curl_multi_perform"); + success &= LoadFunction(reinterpret_cast(curl_multi_info_read_fn), "curl_multi_info_read"); + + // Note: curl_multi_poll might not be available in older versions, so we make it optional + LoadFunction(reinterpret_cast(curl_multi_poll_fn), "curl_multi_poll"); + success &= LoadFunction(reinterpret_cast(curl_multi_wait_fn), "curl_multi_wait"); + + if (!success) + { + Cleanup(); + return false; + } + + HC_TRACE_INFORMATION(HTTPCLIENT, "XCurl.dll loaded successfully"); + return true; +} + +void CurlDynamicLoader::Cleanup() +{ + if (m_curlLibrary != nullptr) + { + HC_TRACE_INFORMATION(HTTPCLIENT, "Unloading XCurl.dll"); + FreeLibrary(m_curlLibrary); + m_curlLibrary = nullptr; + } + + // Reset all function pointers + curl_global_init_fn = nullptr; + curl_global_cleanup_fn = nullptr; + curl_easy_init_fn = nullptr; + curl_easy_cleanup_fn = nullptr; + curl_easy_setopt_fn = nullptr; + curl_easy_getinfo_fn = nullptr; + curl_easy_strerror_fn = nullptr; + curl_slist_append_fn = nullptr; + curl_slist_free_all_fn = nullptr; + curl_multi_init_fn = nullptr; + curl_multi_cleanup_fn = nullptr; + curl_multi_add_handle_fn = nullptr; + curl_multi_remove_handle_fn = nullptr; + curl_multi_perform_fn = nullptr; + curl_multi_info_read_fn = nullptr; + curl_multi_poll_fn = nullptr; + curl_multi_wait_fn = nullptr; +} + +bool CurlDynamicLoader::LoadFunction(FARPROC& funcPtr, const char* functionName) +{ + funcPtr = GetProcAddress(m_curlLibrary, functionName); + if (funcPtr == nullptr) + { + DWORD error = GetLastError(); + HC_TRACE_ERROR(HTTPCLIENT, "Failed to load function: %s. Error code: %lu", functionName, error); + return false; + } + return true; +} + +} // httpclient +} // xbox + +#endif // HC_PLATFORM == HC_PLATFORM_GDK diff --git a/Source/HTTP/Curl/CurlDynamicLoader.h b/Source/HTTP/Curl/CurlDynamicLoader.h new file mode 100644 index 00000000..fb782a5a --- /dev/null +++ b/Source/HTTP/Curl/CurlDynamicLoader.h @@ -0,0 +1,85 @@ +#pragma once + +#if HC_PLATFORM == HC_PLATFORM_GDK + +#include +#include +#include +#include + +namespace xbox +{ +namespace httpclient +{ + +// Dynamic curl function pointers +class CurlDynamicLoader +{ +public: + // Initialization/Cleanup functions + using curl_global_init_ptr = CURLcode(*)(long flags); + using curl_global_cleanup_ptr = void(*)(); + + // Easy interface functions + using curl_easy_init_ptr = CURL*(*)(); + using curl_easy_cleanup_ptr = void(*)(CURL* curl); + using curl_easy_setopt_ptr = CURLcode(*)(CURL* curl, CURLoption option, ...); + using curl_easy_getinfo_ptr = CURLcode(*)(CURL* curl, CURLINFO info, ...); + using curl_easy_strerror_ptr = const char*(*)(CURLcode code); + + // String list functions + using curl_slist_append_ptr = struct curl_slist*(*)(struct curl_slist* list, const char* string); + using curl_slist_free_all_ptr = void(*)(struct curl_slist* list); + + // Multi interface functions + using curl_multi_init_ptr = CURLM*(*)(); + using curl_multi_cleanup_ptr = CURLMcode(*)(CURLM* multi_handle); + using curl_multi_add_handle_ptr = CURLMcode(*)(CURLM* multi_handle, CURL* curl_handle); + using curl_multi_remove_handle_ptr = CURLMcode(*)(CURLM* multi_handle, CURL* curl_handle); + using curl_multi_perform_ptr = CURLMcode(*)(CURLM* multi_handle, int* running_handles); + using curl_multi_info_read_ptr = CURLMsg*(*)(CURLM* multi_handle, int* msgs_in_queue); + using curl_multi_poll_ptr = CURLMcode(*)(CURLM* multi_handle, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int* ret); + using curl_multi_wait_ptr = CURLMcode(*)(CURLM* multi_handle, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int* numfds); + + // Function pointers + curl_global_init_ptr curl_global_init_fn = nullptr; + curl_global_cleanup_ptr curl_global_cleanup_fn = nullptr; + curl_easy_init_ptr curl_easy_init_fn = nullptr; + curl_easy_cleanup_ptr curl_easy_cleanup_fn = nullptr; + curl_easy_setopt_ptr curl_easy_setopt_fn = nullptr; + curl_easy_getinfo_ptr curl_easy_getinfo_fn = nullptr; + curl_easy_strerror_ptr curl_easy_strerror_fn = nullptr; + curl_slist_append_ptr curl_slist_append_fn = nullptr; + curl_slist_free_all_ptr curl_slist_free_all_fn = nullptr; + curl_multi_init_ptr curl_multi_init_fn = nullptr; + curl_multi_cleanup_ptr curl_multi_cleanup_fn = nullptr; + curl_multi_add_handle_ptr curl_multi_add_handle_fn = nullptr; + curl_multi_remove_handle_ptr curl_multi_remove_handle_fn = nullptr; + curl_multi_perform_ptr curl_multi_perform_fn = nullptr; + curl_multi_info_read_ptr curl_multi_info_read_fn = nullptr; + curl_multi_poll_ptr curl_multi_poll_fn = nullptr; + curl_multi_wait_ptr curl_multi_wait_fn = nullptr; + + static CurlDynamicLoader& GetInstance(); + ~CurlDynamicLoader(); + + bool Initialize(); + void Cleanup(); + bool IsLoaded() const { return m_curlLibrary != nullptr; } + +private: + CurlDynamicLoader() = default; + + bool LoadFunction(FARPROC& funcPtr, const char* functionName); + + HMODULE m_curlLibrary = nullptr; + + // Thread safety + static std::mutex s_initMutex; + static HC_UNIQUE_PTR s_instance; +}; + +} // httpclient +} // xbox + +#endif // HC_PLATFORM == HC_PLATFORM_GDK diff --git a/Source/HTTP/Curl/CurlEasyRequest.cpp b/Source/HTTP/Curl/CurlEasyRequest.cpp index 56fa6a8d..c32d7adf 100644 --- a/Source/HTTP/Curl/CurlEasyRequest.cpp +++ b/Source/HTTP/Curl/CurlEasyRequest.cpp @@ -18,13 +18,32 @@ CurlEasyRequest::CurlEasyRequest(CURL* curlEasyHandle, HCCallHandle hcCall, XAsy CurlEasyRequest::~CurlEasyRequest() { +#if HC_PLATFORM == HC_PLATFORM_GDK + if (CurlDynamicLoader::GetInstance().IsLoaded()) + { + CURL_CALL(curl_easy_cleanup)(m_curlEasyHandle); + CURL_CALL(curl_slist_free_all)(m_headers); + } +#else curl_easy_cleanup(m_curlEasyHandle); curl_slist_free_all(m_headers); +#endif } Result> CurlEasyRequest::Initialize(HCCallHandle hcCall, XAsyncBlock* async) { +#if HC_PLATFORM == HC_PLATFORM_GDK + // Ensure curl is loaded + if (!CurlDynamicLoader::GetInstance().IsLoaded()) + { + HC_TRACE_ERROR(HTTPCLIENT, "CurlEasyRequest::Initialize: XCurl.dll not available"); + return E_HC_XCURL_REQUIRED; + } + + CURL* curlEasyHandle{ CURL_CALL(curl_easy_init)() }; +#else CURL* curlEasyHandle{ curl_easy_init() }; +#endif if (!curlEasyHandle) { HC_TRACE_ERROR(HTTPCLIENT, "CurlEasyRequest::Initialize:: curl_easy_init failed"); @@ -175,7 +194,11 @@ void CurlEasyRequest::Complete(CURLcode result) HC_TRACE_INFORMATION(HTTPCLIENT, "CurlEasyRequest::m_errorBuffer='%s'", m_errorBuffer); long platformError = 0; +#if HC_PLATFORM == HC_PLATFORM_GDK + auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError); +#else auto curle = curl_easy_getinfo(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError); +#endif if (curle != CURLE_OK) { return Fail(HrFromCurle(curle)); @@ -184,13 +207,21 @@ void CurlEasyRequest::Complete(CURLcode result) HRESULT hr = HCHttpCallResponseSetNetworkErrorCode(m_hcCallHandle, E_FAIL, static_cast(platformError)); assert(SUCCEEDED(hr)); +#if HC_PLATFORM == HC_PLATFORM_GDK + hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, CURL_CALL(curl_easy_strerror)(result)); +#else hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, curl_easy_strerror(result)); +#endif assert(SUCCEEDED(hr)); } else { long httpStatus = 0; +#if HC_PLATFORM == HC_PLATFORM_GDK + auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus); +#else auto curle = curl_easy_getinfo(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus); +#endif if (curle != CURLE_OK) { return Fail(HrFromCurle(curle)); @@ -224,7 +255,11 @@ HRESULT CurlEasyRequest::AddHeader(char const* name, char const* value) noexcept assert(written == required); (void)written; +#if HC_PLATFORM == HC_PLATFORM_GDK + m_headers = CURL_CALL(curl_slist_append)(m_headers, header.c_str()); +#else m_headers = curl_slist_append(m_headers, header.c_str()); +#endif return S_OK; } @@ -368,7 +403,11 @@ size_t CurlEasyRequest::WriteHeaderCallback(char* buffer, size_t size, size_t ni size_t CurlEasyRequest::GetResponseContentLength(CURL* curlHandle) { curl_off_t contentLength = 0; +#if HC_PLATFORM == HC_PLATFORM_GDK + CURL_CALL(curl_easy_getinfo)(curlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &contentLength); +#else curl_easy_getinfo(curlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &contentLength); +#endif return contentLength; } diff --git a/Source/HTTP/Curl/CurlEasyRequest.h b/Source/HTTP/Curl/CurlEasyRequest.h index b5ad642a..a5b837da 100644 --- a/Source/HTTP/Curl/CurlEasyRequest.h +++ b/Source/HTTP/Curl/CurlEasyRequest.h @@ -1,13 +1,15 @@ #pragma once - #if HC_PLATFORM == HC_PLATFORM_GDK // When developing titles for Xbox consoles, you must use WinHTTP or xCurl. // See https://docs.microsoft.com/en-us/gaming/gdk/_content/gc/networking/overviews/web-requests/http-networking for detail #include +#include "CurlDynamicLoader.h" +#define CURL_CALL(func_name) CurlDynamicLoader::GetInstance().func_name##_fn #else -// This path is untested, but this http provider should work with other curl implementations as well. +// Http provider should work with other curl implementations as well. // The logic in CurlMulti::Perform is optimized for XCurl, but should work on any curl implementation. #include +#define CURL_CALL(func_name) func_name #endif #include "Result.h" @@ -79,7 +81,11 @@ class CurlEasyRequest template HRESULT CurlEasyRequest::SetOpt(CURLoption option, typename OptType::type v) noexcept { +#if HC_PLATFORM == HC_PLATFORM_GDK + CURLcode result = CURL_CALL(curl_easy_setopt)(m_curlEasyHandle, option, v); +#else CURLcode result = curl_easy_setopt(m_curlEasyHandle, option, v); +#endif if (result != CURLE_OK) { HC_TRACE_ERROR(HTTPCLIENT, "curl_easy_setopt(request, %d, value) failed with %d", option, result); diff --git a/Source/HTTP/Curl/CurlMulti.cpp b/Source/HTTP/Curl/CurlMulti.cpp index 9236be72..c78e7909 100644 --- a/Source/HTTP/Curl/CurlMulti.cpp +++ b/Source/HTTP/Curl/CurlMulti.cpp @@ -15,10 +15,23 @@ Result> CurlMulti::Initialize(XTaskQueuePortHandle work { assert(workPort); +#if HC_PLATFORM == HC_PLATFORM_GDK + // Ensure curl is loaded + if (!CurlDynamicLoader::GetInstance().IsLoaded()) + { + HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Initialize: XCurl.dll not available"); + return E_HC_XCURL_REQUIRED; + } +#endif + http_stl_allocator a{}; HC_UNIQUE_PTR multi{ new (a.allocate(1)) CurlMulti }; +#if HC_PLATFORM == HC_PLATFORM_GDK + multi->m_curlMultiHandle = CURL_CALL(curl_multi_init)(); +#else multi->m_curlMultiHandle = curl_multi_init(); +#endif if (!multi->m_curlMultiHandle) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Initialize: curl_multi_init failed"); @@ -45,7 +58,14 @@ CurlMulti::~CurlMulti() if (m_curlMultiHandle) { +#if HC_PLATFORM == HC_PLATFORM_GDK + if (CurlDynamicLoader::GetInstance().IsLoaded()) + { + CURL_CALL(curl_multi_cleanup)(m_curlMultiHandle); + } +#else curl_multi_cleanup(m_curlMultiHandle); +#endif } } @@ -59,7 +79,11 @@ HRESULT CurlMulti::AddRequest(HC_UNIQUE_PTR easyRequest) return E_FAIL; } +#if HC_PLATFORM == HC_PLATFORM_GDK + auto result = CURL_CALL(curl_multi_add_handle)(m_curlMultiHandle, easyRequest->Handle()); +#else auto result = curl_multi_add_handle(m_curlMultiHandle, easyRequest->Handle()); +#endif if (result != CURLM_OK) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::AddRequest: curl_multi_add_handle failed with CURLCode=%u", result); @@ -201,7 +225,11 @@ HRESULT CurlMulti::Perform() noexcept std::unique_lock lock{ m_mutex }; int runningRequests{ 0 }; +#if HC_PLATFORM == HC_PLATFORM_GDK + CURLMcode result = CURL_CALL(curl_multi_perform)(m_curlMultiHandle, &runningRequests); +#else CURLMcode result = curl_multi_perform(m_curlMultiHandle, &runningRequests); +#endif if (result != CURLM_OK) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Perform: curl_multi_perform failed with CURLCode=%u", result); @@ -211,7 +239,11 @@ HRESULT CurlMulti::Perform() noexcept int remainingMessages{ 1 }; // assume there is at least 1 message so loop is always entered while (remainingMessages) { +#if HC_PLATFORM == HC_PLATFORM_GDK + CURLMsg* message = CURL_CALL(curl_multi_info_read)(m_curlMultiHandle, &remainingMessages); +#else CURLMsg* message = curl_multi_info_read(m_curlMultiHandle, &remainingMessages); +#endif if (message) { switch (message->msg) @@ -221,7 +253,11 @@ HRESULT CurlMulti::Perform() noexcept auto requestIter = m_easyRequests.find(message->easy_handle); assert(requestIter != m_easyRequests.end()); +#if HC_PLATFORM == HC_PLATFORM_GDK + result = CURL_CALL(curl_multi_remove_handle)(m_curlMultiHandle, message->easy_handle); +#else result = curl_multi_remove_handle(m_curlMultiHandle, message->easy_handle); +#endif if (result != CURLM_OK) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Perform: curl_multi_remove_handle failed with CURLCode=%u", result); @@ -247,15 +283,27 @@ HRESULT CurlMulti::Perform() noexcept { // Reschedule Perform if there are still running requests int workAvailable{ 0 }; -#if HC_PLATFORM == HC_PLATFORM_GDK || CURL_AT_LEAST_VERSION(7,66,0) +#if HC_PLATFORM == HC_PLATFORM_GDK + // Try curl_multi_poll first, fall back to curl_multi_wait if not available + if (CURL_CALL(curl_multi_poll)) + { + result = CURL_CALL(curl_multi_poll)(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); + } + else + { + result = CURL_CALL(curl_multi_wait)(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); + } +#else +#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7,66,0) result = curl_multi_poll(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); #else result = curl_multi_wait(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); +#endif #endif if (result != CURLM_OK) { - HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Perform: curl_multi_poll failed with CURLCode=%u", result); + HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Perform: curl_multi_poll/wait failed with CURLCode=%u", result); return HrFromCurlm(result); } @@ -274,11 +322,22 @@ void CurlMulti::FailAllRequests(HRESULT hr) noexcept { for (auto& pair : m_easyRequests) { +#if HC_PLATFORM == HC_PLATFORM_GDK + if (CurlDynamicLoader::GetInstance().IsLoaded()) + { + auto result = CURL_CALL(curl_multi_remove_handle)(m_curlMultiHandle, pair.first); + if (FAILED(HrFromCurlm(result))) + { + HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::FailAllRequests: curl_multi_remove_handle failed with CURLCode=%u", result); + } + } +#else auto result = curl_multi_remove_handle(m_curlMultiHandle, pair.first); if (FAILED(HrFromCurlm(result))) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::FailAllRequests: curl_multi_remove_handle failed with CURLCode=%u", result); } +#endif pair.second->Fail(hr); } m_easyRequests.clear(); diff --git a/Source/HTTP/Curl/CurlProvider.cpp b/Source/HTTP/Curl/CurlProvider.cpp index b43b4369..c912c685 100644 --- a/Source/HTTP/Curl/CurlProvider.cpp +++ b/Source/HTTP/Curl/CurlProvider.cpp @@ -22,7 +22,9 @@ HRESULT HrFromCurlm(CURLMcode c) noexcept switch (c) { case CURLMcode::CURLM_OK: return S_OK; -#if HC_PLATFORM == HC_PLATFORM_GDK || CURL_AT_LEAST_VERSION(7,69,0) +#if HC_PLATFORM == HC_PLATFORM_GDK + case CURLMcode::CURLM_BAD_FUNCTION_ARGUMENT: assert(false); return E_INVALIDARG; +#elif defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7,69,0) case CURLMcode::CURLM_BAD_FUNCTION_ARGUMENT: assert(false); return E_INVALIDARG; #endif default: return E_FAIL; @@ -31,7 +33,19 @@ HRESULT HrFromCurlm(CURLMcode c) noexcept Result> CurlProvider::Initialize() { +#if HC_PLATFORM == HC_PLATFORM_GDK + // Initialize dynamic curl loader first + auto& loader = CurlDynamicLoader::GetInstance(); + if (!loader.Initialize()) + { + HC_TRACE_ERROR(HTTPCLIENT, "CurlProvider::Initialize: Failed to load XCurl.dll"); + return E_FAIL; + } + + CURLcode initRes = CURL_CALL(curl_global_init)(CURL_GLOBAL_ALL); +#else CURLcode initRes = curl_global_init(CURL_GLOBAL_ALL); +#endif RETURN_IF_FAILED(HrFromCurle(initRes)); http_stl_allocator a{}; @@ -53,11 +67,27 @@ CurlProvider::~CurlProvider() // make sure XCurlMultis are cleaned up before curl_global_cleanup m_curlMultis.clear(); +#if HC_PLATFORM == HC_PLATFORM_GDK + if (CurlDynamicLoader::GetInstance().IsLoaded()) + { + CURL_CALL(curl_global_cleanup)(); + } +#else curl_global_cleanup(); +#endif } HRESULT CurlProvider::PerformAsync(HCCallHandle hcCall, XAsyncBlock* async) noexcept { +#if HC_PLATFORM == HC_PLATFORM_GDK + // Check if curl is available before proceeding + if (!CurlDynamicLoader::GetInstance().IsLoaded()) + { + HC_TRACE_ERROR(HTTPCLIENT, "CurlProvider::PerformAsync: XCurl.dll not available"); + return E_HC_XCURL_REQUIRED; + } +#endif + XTaskQueuePortHandle workPort{ nullptr }; RETURN_IF_FAILED(XTaskQueueGetPort(async->queue, XTaskQueuePort::Work, &workPort)); diff --git a/Source/HTTP/Curl/CurlProvider.h b/Source/HTTP/Curl/CurlProvider.h index e4120527..438e753d 100644 --- a/Source/HTTP/Curl/CurlProvider.h +++ b/Source/HTTP/Curl/CurlProvider.h @@ -3,6 +3,16 @@ #include "Platform/IHttpProvider.h" #include "CurlMulti.h" #include "Result.h" +#if HC_PLATFORM == HC_PLATFORM_GDK +// When developing titles for Xbox consoles, you must use WinHTTP or xCurl. +// See https://docs.microsoft.com/en-us/gaming/gdk/_content/gc/networking/overviews/web-requests/http-networking for detail +#include +#include "CurlDynamicLoader.h" +#else +// This http provider should work with other curl implementations as well. +// The logic in CurlMulti::Perform is optimized for XCurl, but should work on any curl implementation. +#include +#endif namespace xbox { From 19fc98fc21fb7327ab54aea79a701fd4b6ba2f20 Mon Sep 17 00:00:00 2001 From: Jason Sandlin Date: Mon, 11 Aug 2025 13:46:19 -0700 Subject: [PATCH 2/3] PR feedback --- Source/HTTP/Curl/CurlDynamicLoader.cpp | 15 ++++++- Source/HTTP/Curl/CurlDynamicLoader.h | 25 ++++++++++++ Source/HTTP/Curl/CurlEasyRequest.cpp | 43 +++----------------- Source/HTTP/Curl/CurlEasyRequest.h | 13 +------ Source/HTTP/Curl/CurlMulti.cpp | 54 +++----------------------- Source/HTTP/Curl/CurlProvider.cpp | 18 +++++++-- 6 files changed, 67 insertions(+), 101 deletions(-) diff --git a/Source/HTTP/Curl/CurlDynamicLoader.cpp b/Source/HTTP/Curl/CurlDynamicLoader.cpp index 7ea4cd0d..1621e8ed 100644 --- a/Source/HTTP/Curl/CurlDynamicLoader.cpp +++ b/Source/HTTP/Curl/CurlDynamicLoader.cpp @@ -20,11 +20,24 @@ CurlDynamicLoader& CurlDynamicLoader::GetInstance() if (!s_instance) { HC_TRACE_VERBOSE(HTTPCLIENT, "Creating CurlDynamicLoader instance"); - s_instance = HC_UNIQUE_PTR(new CurlDynamicLoader()); + + // Use libHttpClient custom allocator hooks while staying within class access to private ctor + http_stl_allocator a{}; + s_instance = HC_UNIQUE_PTR{ new (a.allocate(1)) CurlDynamicLoader }; } return *s_instance; } +void CurlDynamicLoader::DestroyInstance() +{ + std::lock_guard lock(s_initMutex); + if (s_instance) + { + // Unique ptr with http_alloc_deleter ensures custom free hooks are used + s_instance.reset(); + } +} + CurlDynamicLoader::~CurlDynamicLoader() { Cleanup(); diff --git a/Source/HTTP/Curl/CurlDynamicLoader.h b/Source/HTTP/Curl/CurlDynamicLoader.h index fb782a5a..821cede4 100644 --- a/Source/HTTP/Curl/CurlDynamicLoader.h +++ b/Source/HTTP/Curl/CurlDynamicLoader.h @@ -1,5 +1,11 @@ #pragma once +// +// This header is always includable across platforms. On non-GDK platforms, +// the macros are defined as direct calls and the dynamic loader class is absent. +// On GDK, the dynamic loader class is available and macros route through it. +// + #if HC_PLATFORM == HC_PLATFORM_GDK #include @@ -61,6 +67,8 @@ class CurlDynamicLoader curl_multi_wait_ptr curl_multi_wait_fn = nullptr; static CurlDynamicLoader& GetInstance(); + // Frees the singleton instance and unloads XCurl.dll (via destructor -> Cleanup) + static void DestroyInstance(); ~CurlDynamicLoader(); bool Initialize(); @@ -82,4 +90,21 @@ class CurlDynamicLoader } // httpclient } // xbox +// GDK macro variants: route through dynamic loader and provide default returns when not loaded +#define CURL_CALL(func_name) ::xbox::httpclient::CurlDynamicLoader::GetInstance().func_name##_fn +#define CURL_INVOKE_OR(defaultRet, func, ...) \ + ((::xbox::httpclient::CurlDynamicLoader::GetInstance().IsLoaded()) ? \ + (::xbox::httpclient::CurlDynamicLoader::GetInstance().func##_fn(__VA_ARGS__)) : \ + (defaultRet)) +// Convenience when defaultRet == 0 (common for void-calls or zero-initialized return types) +#define CURL_INVOKE(func, ...) CURL_INVOKE_OR(0, func, __VA_ARGS__) + +#else // non-GDK + +// Non-GDK macro variants: call directly +#define CURL_CALL(func_name) func_name +#define CURL_INVOKE_OR(defaultRet, func, ...) func(__VA_ARGS__) +// Convenience when defaultRet == 0 +#define CURL_INVOKE(func, ...) func(__VA_ARGS__) + #endif // HC_PLATFORM == HC_PLATFORM_GDK diff --git a/Source/HTTP/Curl/CurlEasyRequest.cpp b/Source/HTTP/Curl/CurlEasyRequest.cpp index c32d7adf..9d92e57d 100644 --- a/Source/HTTP/Curl/CurlEasyRequest.cpp +++ b/Source/HTTP/Curl/CurlEasyRequest.cpp @@ -18,16 +18,8 @@ CurlEasyRequest::CurlEasyRequest(CURL* curlEasyHandle, HCCallHandle hcCall, XAsy CurlEasyRequest::~CurlEasyRequest() { -#if HC_PLATFORM == HC_PLATFORM_GDK - if (CurlDynamicLoader::GetInstance().IsLoaded()) - { - CURL_CALL(curl_easy_cleanup)(m_curlEasyHandle); - CURL_CALL(curl_slist_free_all)(m_headers); - } -#else - curl_easy_cleanup(m_curlEasyHandle); - curl_slist_free_all(m_headers); -#endif + (void)CURL_INVOKE(curl_easy_cleanup, m_curlEasyHandle); + (void)CURL_INVOKE(curl_slist_free_all, m_headers); } Result> CurlEasyRequest::Initialize(HCCallHandle hcCall, XAsyncBlock* async) @@ -39,11 +31,8 @@ Result> CurlEasyRequest::Initialize(HCCallHandle HC_TRACE_ERROR(HTTPCLIENT, "CurlEasyRequest::Initialize: XCurl.dll not available"); return E_HC_XCURL_REQUIRED; } - - CURL* curlEasyHandle{ CURL_CALL(curl_easy_init)() }; -#else - CURL* curlEasyHandle{ curl_easy_init() }; #endif + CURL* curlEasyHandle{ CURL_CALL(curl_easy_init)() }; if (!curlEasyHandle) { HC_TRACE_ERROR(HTTPCLIENT, "CurlEasyRequest::Initialize:: curl_easy_init failed"); @@ -194,11 +183,7 @@ void CurlEasyRequest::Complete(CURLcode result) HC_TRACE_INFORMATION(HTTPCLIENT, "CurlEasyRequest::m_errorBuffer='%s'", m_errorBuffer); long platformError = 0; -#if HC_PLATFORM == HC_PLATFORM_GDK - auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError); -#else - auto curle = curl_easy_getinfo(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError); -#endif + auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError); if (curle != CURLE_OK) { return Fail(HrFromCurle(curle)); @@ -207,21 +192,13 @@ void CurlEasyRequest::Complete(CURLcode result) HRESULT hr = HCHttpCallResponseSetNetworkErrorCode(m_hcCallHandle, E_FAIL, static_cast(platformError)); assert(SUCCEEDED(hr)); -#if HC_PLATFORM == HC_PLATFORM_GDK - hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, CURL_CALL(curl_easy_strerror)(result)); -#else - hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, curl_easy_strerror(result)); -#endif + hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, CURL_CALL(curl_easy_strerror)(result)); assert(SUCCEEDED(hr)); } else { long httpStatus = 0; -#if HC_PLATFORM == HC_PLATFORM_GDK - auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus); -#else - auto curle = curl_easy_getinfo(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus); -#endif + auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus); if (curle != CURLE_OK) { return Fail(HrFromCurle(curle)); @@ -255,11 +232,7 @@ HRESULT CurlEasyRequest::AddHeader(char const* name, char const* value) noexcept assert(written == required); (void)written; -#if HC_PLATFORM == HC_PLATFORM_GDK m_headers = CURL_CALL(curl_slist_append)(m_headers, header.c_str()); -#else - m_headers = curl_slist_append(m_headers, header.c_str()); -#endif return S_OK; } @@ -403,11 +376,7 @@ size_t CurlEasyRequest::WriteHeaderCallback(char* buffer, size_t size, size_t ni size_t CurlEasyRequest::GetResponseContentLength(CURL* curlHandle) { curl_off_t contentLength = 0; -#if HC_PLATFORM == HC_PLATFORM_GDK CURL_CALL(curl_easy_getinfo)(curlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &contentLength); -#else - curl_easy_getinfo(curlHandle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &contentLength); -#endif return contentLength; } diff --git a/Source/HTTP/Curl/CurlEasyRequest.h b/Source/HTTP/Curl/CurlEasyRequest.h index a5b837da..1c1e1cb8 100644 --- a/Source/HTTP/Curl/CurlEasyRequest.h +++ b/Source/HTTP/Curl/CurlEasyRequest.h @@ -1,15 +1,10 @@ #pragma once -#if HC_PLATFORM == HC_PLATFORM_GDK -// When developing titles for Xbox consoles, you must use WinHTTP or xCurl. -// See https://docs.microsoft.com/en-us/gaming/gdk/_content/gc/networking/overviews/web-requests/http-networking for detail -#include +// Always include CurlDynamicLoader.h for macros and (on GDK) loader type #include "CurlDynamicLoader.h" -#define CURL_CALL(func_name) CurlDynamicLoader::GetInstance().func_name##_fn -#else // Http provider should work with other curl implementations as well. // The logic in CurlMulti::Perform is optimized for XCurl, but should work on any curl implementation. +#if HC_PLATFORM != HC_PLATFORM_GDK #include -#define CURL_CALL(func_name) func_name #endif #include "Result.h" @@ -81,11 +76,7 @@ class CurlEasyRequest template HRESULT CurlEasyRequest::SetOpt(CURLoption option, typename OptType::type v) noexcept { -#if HC_PLATFORM == HC_PLATFORM_GDK CURLcode result = CURL_CALL(curl_easy_setopt)(m_curlEasyHandle, option, v); -#else - CURLcode result = curl_easy_setopt(m_curlEasyHandle, option, v); -#endif if (result != CURLE_OK) { HC_TRACE_ERROR(HTTPCLIENT, "curl_easy_setopt(request, %d, value) failed with %d", option, result); diff --git a/Source/HTTP/Curl/CurlMulti.cpp b/Source/HTTP/Curl/CurlMulti.cpp index c78e7909..83225b6e 100644 --- a/Source/HTTP/Curl/CurlMulti.cpp +++ b/Source/HTTP/Curl/CurlMulti.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "CurlMulti.h" +#include "CurlDynamicLoader.h" #include "CurlProvider.h" namespace xbox @@ -27,11 +28,7 @@ Result> CurlMulti::Initialize(XTaskQueuePortHandle work http_stl_allocator a{}; HC_UNIQUE_PTR multi{ new (a.allocate(1)) CurlMulti }; -#if HC_PLATFORM == HC_PLATFORM_GDK multi->m_curlMultiHandle = CURL_CALL(curl_multi_init)(); -#else - multi->m_curlMultiHandle = curl_multi_init(); -#endif if (!multi->m_curlMultiHandle) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Initialize: curl_multi_init failed"); @@ -58,14 +55,7 @@ CurlMulti::~CurlMulti() if (m_curlMultiHandle) { -#if HC_PLATFORM == HC_PLATFORM_GDK - if (CurlDynamicLoader::GetInstance().IsLoaded()) - { - CURL_CALL(curl_multi_cleanup)(m_curlMultiHandle); - } -#else - curl_multi_cleanup(m_curlMultiHandle); -#endif + (void)CURL_INVOKE(curl_multi_cleanup, m_curlMultiHandle); } } @@ -79,11 +69,7 @@ HRESULT CurlMulti::AddRequest(HC_UNIQUE_PTR easyRequest) return E_FAIL; } -#if HC_PLATFORM == HC_PLATFORM_GDK auto result = CURL_CALL(curl_multi_add_handle)(m_curlMultiHandle, easyRequest->Handle()); -#else - auto result = curl_multi_add_handle(m_curlMultiHandle, easyRequest->Handle()); -#endif if (result != CURLM_OK) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::AddRequest: curl_multi_add_handle failed with CURLCode=%u", result); @@ -225,11 +211,7 @@ HRESULT CurlMulti::Perform() noexcept std::unique_lock lock{ m_mutex }; int runningRequests{ 0 }; -#if HC_PLATFORM == HC_PLATFORM_GDK CURLMcode result = CURL_CALL(curl_multi_perform)(m_curlMultiHandle, &runningRequests); -#else - CURLMcode result = curl_multi_perform(m_curlMultiHandle, &runningRequests); -#endif if (result != CURLM_OK) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Perform: curl_multi_perform failed with CURLCode=%u", result); @@ -239,11 +221,7 @@ HRESULT CurlMulti::Perform() noexcept int remainingMessages{ 1 }; // assume there is at least 1 message so loop is always entered while (remainingMessages) { -#if HC_PLATFORM == HC_PLATFORM_GDK - CURLMsg* message = CURL_CALL(curl_multi_info_read)(m_curlMultiHandle, &remainingMessages); -#else - CURLMsg* message = curl_multi_info_read(m_curlMultiHandle, &remainingMessages); -#endif + CURLMsg* message = CURL_CALL(curl_multi_info_read)(m_curlMultiHandle, &remainingMessages); if (message) { switch (message->msg) @@ -253,11 +231,7 @@ HRESULT CurlMulti::Perform() noexcept auto requestIter = m_easyRequests.find(message->easy_handle); assert(requestIter != m_easyRequests.end()); -#if HC_PLATFORM == HC_PLATFORM_GDK result = CURL_CALL(curl_multi_remove_handle)(m_curlMultiHandle, message->easy_handle); -#else - result = curl_multi_remove_handle(m_curlMultiHandle, message->easy_handle); -#endif if (result != CURLM_OK) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::Perform: curl_multi_remove_handle failed with CURLCode=%u", result); @@ -283,8 +257,8 @@ HRESULT CurlMulti::Perform() noexcept { // Reschedule Perform if there are still running requests int workAvailable{ 0 }; -#if HC_PLATFORM == HC_PLATFORM_GDK // Try curl_multi_poll first, fall back to curl_multi_wait if not available + // For non-GDK, CURL_CALL expands directly to the symbol if (CURL_CALL(curl_multi_poll)) { result = CURL_CALL(curl_multi_poll)(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); @@ -293,13 +267,6 @@ HRESULT CurlMulti::Perform() noexcept { result = CURL_CALL(curl_multi_wait)(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); } -#else -#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7,66,0) - result = curl_multi_poll(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); -#else - result = curl_multi_wait(m_curlMultiHandle, nullptr, 0, POLL_TIMEOUT_MS, &workAvailable); -#endif -#endif if (result != CURLM_OK) { @@ -322,22 +289,11 @@ void CurlMulti::FailAllRequests(HRESULT hr) noexcept { for (auto& pair : m_easyRequests) { -#if HC_PLATFORM == HC_PLATFORM_GDK - if (CurlDynamicLoader::GetInstance().IsLoaded()) - { - auto result = CURL_CALL(curl_multi_remove_handle)(m_curlMultiHandle, pair.first); - if (FAILED(HrFromCurlm(result))) - { - HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::FailAllRequests: curl_multi_remove_handle failed with CURLCode=%u", result); - } - } -#else - auto result = curl_multi_remove_handle(m_curlMultiHandle, pair.first); + auto result = CURL_INVOKE_OR(CURLM_OK, curl_multi_remove_handle, m_curlMultiHandle, pair.first); if (FAILED(HrFromCurlm(result))) { HC_TRACE_ERROR(HTTPCLIENT, "CurlMulti::FailAllRequests: curl_multi_remove_handle failed with CURLCode=%u", result); } -#endif pair.second->Fail(hr); } m_easyRequests.clear(); diff --git a/Source/HTTP/Curl/CurlProvider.cpp b/Source/HTTP/Curl/CurlProvider.cpp index c912c685..557a1841 100644 --- a/Source/HTTP/Curl/CurlProvider.cpp +++ b/Source/HTTP/Curl/CurlProvider.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "CurlProvider.h" #include "CurlEasyRequest.h" +#include "CurlDynamicLoader.h" namespace xbox { @@ -39,14 +40,23 @@ Result> CurlProvider::Initialize() if (!loader.Initialize()) { HC_TRACE_ERROR(HTTPCLIENT, "CurlProvider::Initialize: Failed to load XCurl.dll"); + // Ensure the loader is cleaned up if initialization fails + CurlDynamicLoader::DestroyInstance(); return E_FAIL; } CURLcode initRes = CURL_CALL(curl_global_init)(CURL_GLOBAL_ALL); + HRESULT initHr = HrFromCurle(initRes); + if (FAILED(initHr)) + { + // If curl init fails, unload XCurl and free the loader singleton + CurlDynamicLoader::DestroyInstance(); + return initHr; + } #else - CURLcode initRes = curl_global_init(CURL_GLOBAL_ALL); -#endif + CURLcode initRes = CURL_CALL(curl_global_init)(CURL_GLOBAL_ALL); RETURN_IF_FAILED(HrFromCurle(initRes)); +#endif http_stl_allocator a{}; auto provider = HC_UNIQUE_PTR{ new (a.allocate(1)) CurlProvider }; @@ -72,8 +82,10 @@ CurlProvider::~CurlProvider() { CURL_CALL(curl_global_cleanup)(); } + // Free the dynamic loader singleton (unloads XCurl.dll via its destructor) + CurlDynamicLoader::DestroyInstance(); #else - curl_global_cleanup(); + CURL_CALL(curl_global_cleanup)(); #endif } From de39f84b897da27de34cffde17cbafecb659cadf Mon Sep 17 00:00:00 2001 From: Jason Sandlin Date: Tue, 12 Aug 2025 10:55:39 -0700 Subject: [PATCH 3/3] PR feedback --- Source/HTTP/Curl/CurlEasyRequest.cpp | 6 +++--- Source/HTTP/Curl/CurlMulti.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/HTTP/Curl/CurlEasyRequest.cpp b/Source/HTTP/Curl/CurlEasyRequest.cpp index 9d92e57d..a4a25609 100644 --- a/Source/HTTP/Curl/CurlEasyRequest.cpp +++ b/Source/HTTP/Curl/CurlEasyRequest.cpp @@ -183,7 +183,7 @@ void CurlEasyRequest::Complete(CURLcode result) HC_TRACE_INFORMATION(HTTPCLIENT, "CurlEasyRequest::m_errorBuffer='%s'", m_errorBuffer); long platformError = 0; - auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError); + auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_OS_ERRNO, &platformError); if (curle != CURLE_OK) { return Fail(HrFromCurle(curle)); @@ -192,13 +192,13 @@ void CurlEasyRequest::Complete(CURLcode result) HRESULT hr = HCHttpCallResponseSetNetworkErrorCode(m_hcCallHandle, E_FAIL, static_cast(platformError)); assert(SUCCEEDED(hr)); - hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, CURL_CALL(curl_easy_strerror)(result)); + hr = HCHttpCallResponseSetPlatformNetworkErrorMessage(m_hcCallHandle, CURL_CALL(curl_easy_strerror)(result)); assert(SUCCEEDED(hr)); } else { long httpStatus = 0; - auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus); + auto curle = CURL_CALL(curl_easy_getinfo)(m_curlEasyHandle, CURLINFO_RESPONSE_CODE, &httpStatus); if (curle != CURLE_OK) { return Fail(HrFromCurle(curle)); diff --git a/Source/HTTP/Curl/CurlMulti.cpp b/Source/HTTP/Curl/CurlMulti.cpp index 83225b6e..a857a260 100644 --- a/Source/HTTP/Curl/CurlMulti.cpp +++ b/Source/HTTP/Curl/CurlMulti.cpp @@ -55,7 +55,7 @@ CurlMulti::~CurlMulti() if (m_curlMultiHandle) { - (void)CURL_INVOKE(curl_multi_cleanup, m_curlMultiHandle); + (void)CURL_INVOKE(curl_multi_cleanup, m_curlMultiHandle); } }