#include "HttpClient.h" #include #include #include #include namespace Romeo { static wchar_t* ConvertToWide(Juliet::Arena* arena, const Juliet::String& str) { Assert(arena != nullptr); if (str.Size == 0) { return const_cast(L""); } int wLen = MultiByteToWideChar(CP_UTF8, 0, CStr(str), static_cast(str.Size), nullptr, 0); if (wLen <= 0) { return const_cast(L""); } wchar_t* wBuf = Juliet::ArenaPushArray(arena, static_cast(wLen + 1) JULIET_DEBUG_PARAM("WideStr")); MultiByteToWideChar(CP_UTF8, 0, CStr(str), static_cast(str.Size), wBuf, wLen); wBuf[wLen] = L'\0'; return wBuf; } bool HttpClient::Post( Juliet::Arena* arena, const Juliet::String& host, int port, const Juliet::String& path, bool isHttps, const Juliet::String& requestBody, Juliet::String& outResponse ) { Assert(arena != nullptr); Assert(host.Size > 0); bool success = false; HINTERNET hSession = nullptr; HINTERNET hConnect = nullptr; HINTERNET hRequest = nullptr; hSession = WinHttpOpen( L"Romeo/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, nullptr, nullptr, 0 ); if (hSession != nullptr) { WinHttpSetTimeouts(hSession, 60000, 60000, 60000, 1800000); wchar_t* wHost = ConvertToWide(arena, host); hConnect = WinHttpConnect( hSession, wHost, static_cast(port), 0 ); } if (hConnect != nullptr) { wchar_t* wPath = ConvertToWide(arena, path); hRequest = WinHttpOpenRequest( hConnect, L"POST", wPath, nullptr, nullptr, nullptr, isHttps ? WINHTTP_FLAG_SECURE : 0 ); } if (hRequest != nullptr) { const wchar_t* headers = L"Content-Type: application/json\r\n"; DWORD headersLen = static_cast(-1); BOOL sendRes = WinHttpSendRequest( hRequest, headers, headersLen, const_cast(CStr(requestBody)), static_cast(requestBody.Size), static_cast(requestBody.Size), 0 ); if (sendRes != 0) { BOOL recvRes = WinHttpReceiveResponse(hRequest, nullptr); if (recvRes != 0) { DWORD dwSize = 0; DWORD dwDownloaded = 0; size_t totalBytes = 0; size_t capacity = 1024; char* responseData = Juliet::ArenaPushArray(arena, capacity JULIET_DEBUG_PARAM("HttpResponse")); do { dwSize = 0; if (WinHttpQueryDataAvailable(hRequest, &dwSize) == 0) { break; } if (dwSize == 0) { break; } if (totalBytes + dwSize >= capacity) { size_t newCapacity = capacity * 2; if (newCapacity < totalBytes + dwSize + 1) { newCapacity = totalBytes + dwSize + 1; } char* newBuf = Juliet::ArenaPushArray(arena, newCapacity JULIET_DEBUG_PARAM("HttpResponseGrow")); memcpy(newBuf, responseData, totalBytes); responseData = newBuf; capacity = newCapacity; } dwDownloaded = 0; if (WinHttpReadData(hRequest, responseData + totalBytes, dwSize, &dwDownloaded) != 0) { totalBytes += dwDownloaded; } else { break; } } while (dwSize > 0); DWORD dwStatusCode = 0; DWORD dwHeaderSize = sizeof(dwStatusCode); WinHttpQueryHeaders( hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, nullptr, &dwStatusCode, &dwHeaderSize, nullptr ); if (dwStatusCode == 200) { if (totalBytes > 0) { responseData[totalBytes] = '\0'; outResponse.Data = responseData; outResponse.Size = totalBytes; success = true; } } else { if (totalBytes > 0) { responseData[totalBytes] = '\0'; printf("Romeo HttpClient: HTTP Error Status %u. Response: %s\n", static_cast(dwStatusCode), responseData); } else { printf("Romeo HttpClient: HTTP Error Status %u. Empty response.\n", static_cast(dwStatusCode)); } } } } } if (hRequest != nullptr) { WinHttpCloseHandle(hRequest); } if (hConnect != nullptr) { WinHttpCloseHandle(hConnect); } if (hSession != nullptr) { WinHttpCloseHandle(hSession); } return success; } }