reactos/modules/rostests/rosautotest/CWebServiceLibCurl.cpp
2025-08-01 20:49:29 +02:00

134 lines
4.4 KiB
C++

/*
* PROJECT: ReactOS Automatic Testing Utility
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Class implementing the curl interface to the "testman" Web Service
* COPYRIGHT: Copyright 2025 Mark Jansen <mark.jansen@reactos.org>
*/
#include "precomp.h"
#include <curl/curl.h>
static HMODULE g_hLibCurl = nullptr;
static decltype(&curl_global_init) pcurl_global_init = nullptr;
static decltype(&curl_easy_init) pcurl_easy_init = nullptr;
static decltype(&curl_easy_setopt) pcurl_easy_setopt = nullptr;
static decltype(&curl_easy_perform) pcurl_easy_perform = nullptr;
static decltype(&curl_easy_strerror) pcurl_easy_strerror = nullptr;
static decltype(&curl_easy_cleanup) pcurl_easy_cleanup = nullptr;
static decltype(&curl_global_cleanup) pcurl_global_cleanup = nullptr;
bool
CWebServiceLibCurl::CanUseLibCurl()
{
static bool initialized = false;
if (!initialized)
{
initialized = true;
g_hLibCurl = LoadLibraryA("___libcurl.dll");
if (!g_hLibCurl)
return false;
pcurl_global_init = (decltype(&curl_global_init))GetProcAddress(g_hLibCurl, "curl_global_init");
pcurl_easy_init = (decltype(&curl_easy_init))GetProcAddress(g_hLibCurl, "curl_easy_init");
pcurl_easy_setopt = (decltype(&curl_easy_setopt))GetProcAddress(g_hLibCurl, "curl_easy_setopt");
pcurl_easy_perform = (decltype(&curl_easy_perform))GetProcAddress(g_hLibCurl, "curl_easy_perform");
pcurl_easy_strerror = (decltype(&curl_easy_strerror))GetProcAddress(g_hLibCurl, "curl_easy_strerror");
pcurl_easy_cleanup = (decltype(&curl_easy_cleanup))GetProcAddress(g_hLibCurl, "curl_easy_cleanup");
pcurl_global_cleanup = (decltype(&curl_global_cleanup))GetProcAddress(g_hLibCurl, "curl_global_cleanup");
}
if (!pcurl_global_init || !pcurl_easy_init || !pcurl_easy_setopt || !pcurl_easy_perform || !pcurl_easy_strerror ||
!pcurl_easy_cleanup || !pcurl_global_cleanup)
{
return false;
}
return true;
}
/**
* Constructs a CWebServiceLibCurl object
*/
CWebServiceLibCurl::CWebServiceLibCurl()
{
/* Initialize libcurl */
if (pcurl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
{
FATAL("Failed to initialize libcurl\n");
}
m_hCurl = pcurl_easy_init();
if (!m_hCurl)
{
FATAL("Failed to create a libcurl handle\n");
}
CHAR BaseName[MAX_PATH*2];
GetModuleFileNameA(g_hLibCurl, BaseName, _countof(BaseName));
PCHAR FileName = strrchr(BaseName, '\\');
FileName = FileName ? (FileName + 1) : BaseName;
strcpy(FileName, "curl-ca-bundle.crt");
pcurl_easy_setopt(m_hCurl, CURLOPT_CAINFO, BaseName);
}
/**
* Destructs a CWebServiceLibCurl object and closes all connections to the Web Service.
*/
CWebServiceLibCurl::~CWebServiceLibCurl()
{
if (m_hCurl)
{
pcurl_easy_cleanup(m_hCurl);
m_hCurl = nullptr;
}
pcurl_global_cleanup();
}
static size_t
callback_func(void *ptr, size_t size, size_t count, void *userdata)
{
string *ResultData = (string *)userdata;
ResultData->append((const char*)ptr, count);
return count;
}
/**
* Sends data to the Web Service.
*
* @param InputData
* A std::string containing all the data, which is going to be submitted as HTTP POST data.
*
* @return
* Returns a pointer to a char array containing the data received from the Web Service.
* The caller needs to free that pointer.
*/
PCHAR
CWebServiceLibCurl::DoRequest(const char *Hostname, INTERNET_PORT Port, const char *ServerFile, const string &InputData)
{
char buffer[1024];
sprintf(buffer, "https://%s:%u/%s", Hostname, Port, ServerFile);
pcurl_easy_setopt(m_hCurl, CURLOPT_URL, buffer);
pcurl_easy_setopt(m_hCurl, CURLOPT_POSTFIELDS, InputData.c_str());
pcurl_easy_setopt(m_hCurl, CURLOPT_USERAGENT, "rosautotest/curl");
string ResultData;
pcurl_easy_setopt(m_hCurl, CURLOPT_WRITEFUNCTION, callback_func);
pcurl_easy_setopt(m_hCurl, CURLOPT_WRITEDATA, &ResultData);
CURLcode res = pcurl_easy_perform(m_hCurl);
if (res != CURLE_OK)
{
string errorMsg = string("curl_easy_perform failed: ") + pcurl_easy_strerror(res);
FATAL(errorMsg.c_str());
}
auto_array_ptr<char> Data;
Data.reset(new char[ResultData.size() + 1]);
strncpy(Data, ResultData.c_str(), ResultData.size());
Data[ResultData.size()] = '\0';
return Data.release();
}