From 9e9d3342b3bde52665678cad2a08e86b37d74f67 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 28 Jul 2023 14:47:20 +0200 Subject: [PATCH] CURL tools improvement - Added wrapper for downloading files. - Moved many function arguments to dedicated parameters structure. --- r5dev/networksystem/pylon.cpp | 10 ++- r5dev/public/tier2/curlutils.h | 39 +++++++++-- r5dev/tier2/curlutils.cpp | 117 +++++++++++++++++++++++++++------ 3 files changed, 141 insertions(+), 25 deletions(-) diff --git a/r5dev/networksystem/pylon.cpp b/r5dev/networksystem/pylon.cpp index 0ce2823f..56825a25 100644 --- a/r5dev/networksystem/pylon.cpp +++ b/r5dev/networksystem/pylon.cpp @@ -361,9 +361,15 @@ bool CPylon::QueryServer(const char* endpoint, const char* request, string finalUrl; CURLFormatUrl(finalUrl, hostName, endpoint); + CURLParams params; + + params.writeFunction = CURLWriteStringCallback; + params.timeout = curl_timeout->GetInt(); + params.verifyPeer = ssl_verify_peer->GetBool(); + params.verbose = curl_debug->GetBool(); + curl_slist* sList = nullptr; - CURL* curl = CURLInitRequest(finalUrl.c_str(), request, outResponse, sList, - curl_timeout->GetInt(), ssl_verify_peer->GetBool(), curl_debug->GetBool()); + CURL* curl = CURLInitRequest(finalUrl.c_str(), request, outResponse, sList, params); if (!curl) { return false; diff --git a/r5dev/public/tier2/curlutils.h b/r5dev/public/tier2/curlutils.h index a70310aa..e1aed636 100644 --- a/r5dev/public/tier2/curlutils.h +++ b/r5dev/public/tier2/curlutils.h @@ -3,14 +3,45 @@ struct CURLProgress { - CURL* priv; + CURLProgress() + : curl(nullptr) + , name(nullptr) + , cust(nullptr) + , size(0) + {} + + CURL* curl; + const char* name; + void* cust; // custom pointer to anything. size_t size; }; -size_t CURLWriteStringCallback(char* contents, const size_t size, const size_t nmemb, void* userp); +struct CURLParams +{ + CURLParams() + : writeFunction(nullptr) + , statusFunction(nullptr) + , timeout(0) + , verifyPeer(false) + , verbose(false) + {} + + void* writeFunction; + void* statusFunction; + + int timeout; + bool verifyPeer; + bool verbose; +}; + +size_t CURLWriteStringCallback(char* contents, const size_t size, const size_t nmemb, string* userp); +size_t CURLWriteFileCallback(void* data, const size_t size, const size_t nmemb, FILE* userp); + +bool CURLDownloadFile(const char* remote, const char* savePath, const char* fileName, + const char* options, curl_off_t dataSize, void* customPointer, CURLParams& params); + +CURL* CURLInitRequest(const char* remote, const char* request, string& outResponse, curl_slist*& slist, CURLParams& params); -CURL* CURLInitRequest(const char* remote, const char* request, string& outResponse, curl_slist*& slist, - const int timeOut, const bool verifyPeer, const bool debug, const void* writeFunction = CURLWriteStringCallback); CURLcode CURLSubmitRequest(CURL* curl, curl_slist*& slist); CURLINFO CURLRetrieveInfo(CURL* curl); diff --git a/r5dev/tier2/curlutils.cpp b/r5dev/tier2/curlutils.cpp index 943e1f62..864e4e93 100644 --- a/r5dev/tier2/curlutils.cpp +++ b/r5dev/tier2/curlutils.cpp @@ -6,14 +6,99 @@ #include "tier1/cvar.h" #include "tier2/curlutils.h" -size_t CURLWriteStringCallback(char* contents, const size_t size, const size_t nmemb, void* userp) +size_t CURLWriteStringCallback(char* data, const size_t size, const size_t nmemb, string* userp) { - reinterpret_cast<string*>(userp)->append(contents, size * nmemb); + userp->append(data, size * nmemb); return size * nmemb; } -CURL* CURLInitRequest(const char* remote, const char* request, string& outResponse, curl_slist*& slist, - const int timeOut, const bool verifyPeer, const bool debug, const void* writeFunction) +size_t CURLWriteFileCallback(void* data, const size_t size, const size_t nmemb, FILE* userp) +{ + const size_t numBytesWritten = fwrite(data, size, nmemb, userp); + return numBytesWritten; +} + +void CURLInitCommonOptions(CURL* curl, const char* remote, const void* writeData, + const void* writeFunction, const int timeout, const bool verifyPeer, const bool debug) +{ + curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); + curl_easy_setopt(curl, CURLOPT_VERBOSE, debug); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, verifyPeer); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); + curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); + curl_easy_setopt(curl, CURLOPT_URL, remote); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, writeData); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "R5R HTTPS/1.0"); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction); +} + +bool CURLDownloadFile(const char* remote, const char* savePath, const char* fileName, + const char* options, curl_off_t dataSize, void* customPointer, CURLParams& params) +{ + CURL* curl = curl_easy_init(); + if (!curl) + { + Error(eDLL_T::COMMON, NO_ERROR, "CURL: %s\n", "Easy init failed"); + return false; + } + + string filePath = savePath; + + AppendSlash(filePath); + filePath.append(fileName); + + FILE* file = fopen(filePath.c_str(), options); + if (!file) + { + Error(eDLL_T::COMMON, NO_ERROR, "CURL: %s\n", "Open file failed"); + curl_easy_cleanup(curl); + + return false; + } + + CURLProgress progressData; + + progressData.curl = curl; + progressData.name = fileName; + progressData.cust = customPointer; + progressData.size = dataSize; + + CURLInitCommonOptions(curl, remote, file, + params.writeFunction, + params.timeout, + params.verifyPeer, + params.verbose); + + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1l); + + if (params.statusFunction) + { + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0l); + curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &progressData); + curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, params.statusFunction); + } + + CURLcode res = curl_easy_perform(curl); + + if (res != CURLE_OK) + { + Error(eDLL_T::COMMON, NO_ERROR, "CURL: Download of file '%s' failed; %s\n", + fileName, curl_easy_strerror(res)); + + curl_easy_cleanup(curl); + fclose(file); + + return false; + } + + curl_easy_cleanup(curl); + fclose(file); + + return true; +} + +CURL* CURLInitRequest(const char* remote, const char* request, + string& outResponse, curl_slist*& slist, CURLParams& params) { std::function<void(const char*)> fnError = [&](const char* errorMsg) { @@ -35,23 +120,17 @@ CURL* CURLInitRequest(const char* remote, const char* request, string& outRespon return nullptr; } + CURLInitCommonOptions(curl, remote, &outResponse, + params.writeFunction, + params.timeout, + params.verifyPeer, + params.verbose); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); - curl_easy_setopt(curl, CURLOPT_URL, remote); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request); - curl_easy_setopt(curl, CURLOPT_POST, 1L); - curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeOut); - curl_easy_setopt(curl, CURLOPT_USERAGENT, "R5R HTTPS/1.0"); - curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outResponse); - - curl_easy_setopt(curl, CURLOPT_VERBOSE, debug); - curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L); - - if (!verifyPeer) + if (request) { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request); + curl_easy_setopt(curl, CURLOPT_POST, 1L); } return curl;