diff --git a/internal/curlwrapper.hpp b/internal/curlwrapper.hpp index 4e0e40a..7a400c3 100644 --- a/internal/curlwrapper.hpp +++ b/internal/curlwrapper.hpp @@ -7,70 +7,78 @@ #ifndef CURLWRAPPER_HPP #define CURLWRAPPER_HPP +#include #include #include -static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) { - userp->append((char*)contents, size * nmemb); - return size * nmemb; -} +using FilePtr = std::unique_ptr; +using CurlPtr = std::unique_ptr; +using CurlSlist = std::unique_ptr; -static size_t WriteFileCallback(void* ptr, size_t size, size_t nmemb, FILE* stream) { - return fwrite(ptr, size, nmemb, stream); +static FilePtr openFile(const char *path, const char *mode) { + return FilePtr{fopen(path, mode), &fclose}; } -static std::string strToString(__jule_Str str) { - std::string result = ""; - for (__jule_U8& c : str) { - result += c; - } - return result; +static CurlPtr initCurl() { + return CurlPtr{curl_easy_init(), &curl_easy_cleanup}; } -static struct curl_slist* sliceToSlist(const __jule_Slice<__jule_Str> headersSlice) { +static struct curl_slist* sliceToSlist(const __jule_Slice<__jule_Str> &headersSlice) { struct curl_slist* headers = NULL; const int headersLen = headersSlice.len(); for (size_t i = 0; i < headersLen; i += 2) { if (i + 1 < headersLen) { - std::string header = strToString(headersSlice[i]) + ": " + strToString(headersSlice[i + 1]); + const std::string header{headersSlice[i] + ": " + headersSlice[i + 1]}; + // header.c_str() is cloned, so you don't have to worry about the lifetime here. headers = curl_slist_append(headers, header.c_str()); } } return headers; } +static CurlSlist initHeadersList(const __jule_Slice<__jule_Str> &headers) { + return CurlSlist{sliceToSlist(headers), &curl_slist_free_all}; +} + +static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp) { + userp->append((char*)contents, size * nmemb); + return size * nmemb; +} + +static size_t WriteFileCallback(void* ptr, size_t size, size_t nmemb, FILE* stream) { + return fwrite(ptr, size, nmemb, stream); +} + struct Response { __jule_Str body; __jule_Int status; }; -static Response request(const char *url, const __jule_Slice<__jule_Str> headers, const __jule_Int method) { - CURL* curl; +static Response request(const char *url, const __jule_Slice<__jule_Str> &headers, const __jule_Int method) { CURLcode res; std::string readBuffer; Response response; - struct curl_slist* headersList = sliceToSlist(headers); + CurlSlist headersList = initHeadersList(headers); - curl = curl_easy_init(); + CurlPtr curl = initCurl(); if (!curl) { response.status = 418; return response; } - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headersList); + curl_easy_setopt(curl.get(), CURLOPT_URL, url); + curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headersList.get()); if (method == 0) { // GET - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &readBuffer); } else if (method == 1) { // HEAD - curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + curl_easy_setopt(curl.get(), CURLOPT_NOBODY, 1L); } - res = curl_easy_perform(curl); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response.status); - curl_easy_cleanup(curl); + res = curl_easy_perform(curl.get()); + curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &response.status); if (method == 0) { // GET response.body = readBuffer; @@ -79,40 +87,38 @@ static Response request(const char *url, const __jule_Slice<__jule_Str> headers, return response; } -static Response post(const char *url, const char *data, const __jule_Slice<__jule_Str> headers, const __jule_Int method) { - CURL* curl; +static Response post(const char *url, const char *data, const __jule_Slice<__jule_Str> &headers, const __jule_Int method) { CURLcode res; std::string readBuffer; Response response; - struct curl_slist* headersList = sliceToSlist(headers); + CurlSlist headersList = initHeadersList(headers); - curl = curl_easy_init(); + CurlPtr curl = initCurl(); if (!curl) { response.status = 418; return response; } - curl_easy_setopt(curl, CURLOPT_URL, url); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headersList); + curl_easy_setopt(curl.get(), CURLOPT_URL, url); + curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headersList.get()); if (method == 0) { // POST - curl_easy_setopt(curl, CURLOPT_POST, 1L); + curl_easy_setopt(curl.get(), CURLOPT_POST, 1L); } else if (method == 1) { // PUT - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); + curl_easy_setopt(curl.get(), CURLOPT_CUSTOMREQUEST, "PUT"); } else if (method == 2) { // DELETE - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); + curl_easy_setopt(curl.get(), CURLOPT_CUSTOMREQUEST, "DELETE"); } if (data) { - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); + curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, data); } - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); + curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &readBuffer); - res = curl_easy_perform(curl); - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response.status); - curl_easy_cleanup(curl); + res = curl_easy_perform(curl.get()); + curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &response.status); response.body = readBuffer; @@ -120,29 +126,26 @@ static Response post(const char *url, const char *data, const __jule_Slice<__jul } static bool download(__jule_Str url, __jule_Str filename) { - CURL* curl = curl_easy_init(); + CurlPtr curl = initCurl(); if (!curl) { return false; } - FILE* file = fopen(strToString(filename).c_str(), "wb"); + FilePtr file{openFile(filename, "wb")}; if (!file) { return false; } - curl_easy_setopt(curl, CURLOPT_URL, strToString(url).c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteFileCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); + // curl_easy_setopt is a macro, so implicit conversion don't happen. + curl_easy_setopt(curl.get(), CURLOPT_URL, (const char*)url); + curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, WriteFileCallback); + curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, file.get()); - curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl.get(), CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_perform(curl); - - fclose(file); - curl_easy_cleanup(curl); + curl_easy_perform(curl.get()); return true; } #endif // CURLWRAPPER_HPP -