Reactos
at master 134 lines 4.5 kB view raw
1/* 2 * PROJECT: ReactOS Automatic Testing Utility 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Class implementing the curl interface to the "testman" Web Service 5 * COPYRIGHT: Copyright 2025 Mark Jansen <mark.jansen@reactos.org> 6 */ 7 8#include "precomp.h" 9#include <curl/curl.h> 10 11static HMODULE g_hLibCurl = nullptr; 12static decltype(&curl_global_init) pcurl_global_init = nullptr; 13static decltype(&curl_easy_init) pcurl_easy_init = nullptr; 14static decltype(&curl_easy_setopt) pcurl_easy_setopt = nullptr; 15static decltype(&curl_easy_perform) pcurl_easy_perform = nullptr; 16static decltype(&curl_easy_strerror) pcurl_easy_strerror = nullptr; 17static decltype(&curl_easy_cleanup) pcurl_easy_cleanup = nullptr; 18static decltype(&curl_global_cleanup) pcurl_global_cleanup = nullptr; 19 20 21bool 22CWebServiceLibCurl::CanUseLibCurl() 23{ 24 static bool initialized = false; 25 if (!initialized) 26 { 27 initialized = true; 28 g_hLibCurl = LoadLibraryA("___libcurl.dll"); 29 if (!g_hLibCurl) 30 return false; 31 32 pcurl_global_init = (decltype(&curl_global_init))GetProcAddress(g_hLibCurl, "curl_global_init"); 33 pcurl_easy_init = (decltype(&curl_easy_init))GetProcAddress(g_hLibCurl, "curl_easy_init"); 34 pcurl_easy_setopt = (decltype(&curl_easy_setopt))GetProcAddress(g_hLibCurl, "curl_easy_setopt"); 35 pcurl_easy_perform = (decltype(&curl_easy_perform))GetProcAddress(g_hLibCurl, "curl_easy_perform"); 36 pcurl_easy_strerror = (decltype(&curl_easy_strerror))GetProcAddress(g_hLibCurl, "curl_easy_strerror"); 37 pcurl_easy_cleanup = (decltype(&curl_easy_cleanup))GetProcAddress(g_hLibCurl, "curl_easy_cleanup"); 38 pcurl_global_cleanup = (decltype(&curl_global_cleanup))GetProcAddress(g_hLibCurl, "curl_global_cleanup"); 39 } 40 if (!pcurl_global_init || !pcurl_easy_init || !pcurl_easy_setopt || !pcurl_easy_perform || !pcurl_easy_strerror || 41 !pcurl_easy_cleanup || !pcurl_global_cleanup) 42 { 43 return false; 44 } 45 return true; 46} 47 48/** 49 * Constructs a CWebServiceLibCurl object 50 */ 51CWebServiceLibCurl::CWebServiceLibCurl() 52{ 53 /* Initialize libcurl */ 54 if (pcurl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) 55 { 56 FATAL("Failed to initialize libcurl\n"); 57 } 58 59 m_hCurl = pcurl_easy_init(); 60 if (!m_hCurl) 61 { 62 FATAL("Failed to create a libcurl handle\n"); 63 } 64 65 CHAR BaseName[MAX_PATH*2]; 66 GetModuleFileNameA(g_hLibCurl, BaseName, _countof(BaseName)); 67 PCHAR FileName = strrchr(BaseName, '\\'); 68 FileName = FileName ? (FileName + 1) : BaseName; 69 strcpy(FileName, "curl-ca-bundle.crt"); 70 pcurl_easy_setopt(m_hCurl, CURLOPT_CAINFO, BaseName); 71} 72 73/** 74 * Destructs a CWebServiceLibCurl object and closes all connections to the Web Service. 75 */ 76CWebServiceLibCurl::~CWebServiceLibCurl() 77{ 78 if (m_hCurl) 79 { 80 pcurl_easy_cleanup(m_hCurl); 81 m_hCurl = nullptr; 82 } 83 84 pcurl_global_cleanup(); 85} 86 87 88static size_t 89callback_func(void *ptr, size_t size, size_t count, void *userdata) 90{ 91 string *ResultData = (string *)userdata; 92 ResultData->append((const char*)ptr, count); 93 return count; 94} 95 96/** 97 * Sends data to the Web Service. 98 * 99 * @param InputData 100 * A std::string containing all the data, which is going to be submitted as HTTP POST data. 101 * 102 * @return 103 * Returns a pointer to a char array containing the data received from the Web Service. 104 * The caller needs to free that pointer. 105 */ 106PCHAR 107CWebServiceLibCurl::DoRequest(const char *Hostname, INTERNET_PORT Port, const char *ServerFile, const string &InputData) 108{ 109 char buffer[1024]; 110 sprintf(buffer, "https://%s:%u/%s", Hostname, Port, ServerFile); 111 112 pcurl_easy_setopt(m_hCurl, CURLOPT_URL, buffer); 113 pcurl_easy_setopt(m_hCurl, CURLOPT_POSTFIELDS, InputData.c_str()); 114 pcurl_easy_setopt(m_hCurl, CURLOPT_USERAGENT, "rosautotest/curl"); 115 116 string ResultData; 117 pcurl_easy_setopt(m_hCurl, CURLOPT_WRITEFUNCTION, callback_func); 118 pcurl_easy_setopt(m_hCurl, CURLOPT_WRITEDATA, &ResultData); 119 120 CURLcode res = pcurl_easy_perform(m_hCurl); 121 if (res != CURLE_OK) 122 { 123 string errorMsg = string("curl_easy_perform failed: ") + pcurl_easy_strerror(res); 124 FATAL(errorMsg.c_str()); 125 } 126 127 auto_array_ptr<char> Data; 128 Data.reset(new char[ResultData.size() + 1]); 129 strncpy(Data, ResultData.c_str(), ResultData.size()); 130 Data[ResultData.size()] = '\0'; 131 132 return Data.release(); 133} 134