Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 55 additions & 52 deletions internal/curlwrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,70 +7,78 @@
#ifndef CURLWRAPPER_HPP
#define CURLWRAPPER_HPP

#include <memory>
#include <string>
#include <curl/curl.h>

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<FILE, decltype(&fclose)>;
using CurlPtr = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>;
using CurlSlist = std::unique_ptr<curl_slist, decltype(&curl_slist_free_all)>;

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;
Expand All @@ -79,70 +87,65 @@ 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;

return response;
}

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

Loading