Made the request stuff work.

This commit is contained in:
2024-10-23 23:55:28 +02:00
parent 77d46d986c
commit 0d00dec8c7
7 changed files with 352 additions and 47 deletions

View File

@@ -4,6 +4,8 @@
#if !defined(MIJIN_NET_CURL_WRAPPERS_HPP_INCLUDED)
#define MIJIN_NET_CURL_WRAPPERS_HPP_INCLUDED 1
#include <map>
#include <string>
#include <curl/curl.h>
#include "./url.hpp"
@@ -13,7 +15,6 @@
namespace curl
{
#if !MIJIN_WITH_EXCEPTIONS
struct [[nodiscard]] Error
{
CURLcode code = CURLE_OK;
@@ -21,6 +22,8 @@ struct [[nodiscard]] Error
[[nodiscard]]
bool isSuccess() const MIJIN_NOEXCEPT { return code == CURLE_OK; }
};
template<typename TSuccess>
using Result = mijin::ResultBase<TSuccess, Error>;
#define MIJIN_CURL_VERIFY_RESULT(curlResult) \
do \
@@ -30,52 +33,60 @@ do \
return Error{curlResult}; \
} \
} while (0)
#define MIJIN_CURL_RETURN_SUCCESS() return Error()
#else
using Error = void;
[[nodiscard]]
std::string curlCodeMessage(CURLcode code)
{
switch (code)
{
default:
return "Unknown CURL error.";
}
}
using curl_write_callback_t = size_t(*)(char*, size_t, size_t, void*);
using curl_read_callback_t = curl_write_callback_t;
class CurlException : public std::runtime_error
class SList
{
private:
CURLcode code_;
curl_slist* next_ = nullptr;
public:
explicit CurlException(CURLcode code) MIJIN_NOEXCEPT: std::runtime_error(curlCodeMessage(code)), code_(code)
{}
SList() MIJIN_NOEXCEPT = default;
SList(const SList&) = delete;
SList(SList&& other) noexcept : next_(std::exchange(other.next_, nullptr)) {}
~SList() MIJIN_NOEXCEPT
{
if (next_ != nullptr)
{
curl_slist_free_all(next_);
}
}
[[nodiscard]]
constexpr CURLcode getCode() const MIJIN_NOEXCEPT
{ return code_; }
SList& operator=(const SList&) = delete;
SList& operator=(SList&& other) MIJIN_NOEXCEPT
{
if (&other == this)
{
return *this;
}
if (next_ != nullptr)
{
curl_slist_free_all(next_);
}
next_ = std::exchange(other.next_, nullptr);
return *this;
}
auto operator<=>(const SList&) const noexcept = default;
void append(const char* str) MIJIN_NOEXCEPT
{
next_ = curl_slist_append(next_, str);
}
friend class CurlEasy;
};
#define MIJIN_CURL_VERIFY_RESULT(curlResult) \
do \
{ \
if ((curlResult) != CURLE_OK) \
{ \
throw CurlException((curlResult)); \
} \
} while (0)
#define MIJIN_CURL_RETURN_SUCCESS() return
#endif
class CurlEasy
{
private:
CURL* handle_ = nullptr;
SList headers_;
public:
CurlEasy() MIJIN_NOEXCEPT = default;
CurlEasy(const CurlEasy&) = delete;
CurlEasy(CurlEasy&& other) MIJIN_NOEXCEPT : handle_(std::exchange(other.handle_, nullptr)) {}
CurlEasy(CurlEasy&& other) MIJIN_NOEXCEPT : handle_(std::exchange(other.handle_, nullptr)), headers_(std::move(other.headers_)) {}
~CurlEasy() MIJIN_NOEXCEPT
{
reset();
@@ -90,19 +101,21 @@ public:
}
reset();
handle_ = std::exchange(other.handle_, nullptr);
headers_ = std::move(other.headers_);
return *this;
}
MIJIN_ERROR_BOOL init() MIJIN_THROWS
bool init() MIJIN_NOEXCEPT
{
reset();
handle_ = curl_easy_init();
if (handle_ != nullptr)
if (handle_ == nullptr)
{
MIJIN_THROW_OR_RETURN_STD(false, "Error initializing CURL easy.");
return false;
}
MIJIN_RETURN_SUCCESS(true);
return true;
}
void reset() MIJIN_NOEXCEPT
{
if (handle_)
@@ -115,8 +128,7 @@ public:
Error setURL(const char* url) MIJIN_THROWS
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_URL, url);
MIJIN_CURL_VERIFY_RESULT(result);
MIJIN_CURL_RETURN_SUCCESS();
return {result};
}
Error setURL(const std::string& url) MIJIN_NOEXCEPT
@@ -128,6 +140,123 @@ public:
{
return setURL(url.getBase().c_str());
}
Error setSSLVerifyPeer(bool verify) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_SSL_VERIFYPEER, verify);
return {result};
}
Error setSSLVerifyHost(bool verify) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_SSL_VERIFYHOST, verify);
return {result};
}
Error setWriteFunction(curl_write_callback_t callback) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_WRITEFUNCTION, callback);
return {result};
}
Error setWriteData(void* data) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_WRITEDATA, data);
return {result};
}
Error setPostFields(const char* data, bool copy = false) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, copy ? CURLOPT_COPYPOSTFIELDS : CURLOPT_POSTFIELDS, data);
return {result};
}
Error setUpload(bool upload) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_UPLOAD, upload ? 1 : 0);
return {result};
}
Error setInFileSize(curl_off_t size) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_INFILESIZE_LARGE, size);
return {result};
}
Error setReadFunction(curl_read_callback_t callback) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_READFUNCTION, callback);
return {result};
}
Error setReadData(const void* data) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_READDATA, data);
return {result};
}
Error setNoBody(bool nobody) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_NOBODY, nobody ? 1 : 0);
return {result};
}
Error setCustomRequest(bool customRequest) MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_CUSTOMREQUEST, customRequest ? 1 : 0);
return {result};
}
Error setHeaders(SList headers) MIJIN_NOEXCEPT
{
headers_ = std::move(headers);
const CURLcode result = curl_easy_setopt(handle_, CURLOPT_HTTPHEADER, headers_.next_);
return {result};
}
Error perform() MIJIN_NOEXCEPT
{
const CURLcode result = curl_easy_perform(handle_);
return {result};
}
Result<int> getHTTPVersion() MIJIN_NOEXCEPT
{
return getInfo<int, long>(CURLINFO_HTTP_VERSION);
}
Result<int> getStatus() MIJIN_NOEXCEPT
{
return getInfo<int, long>(CURLINFO_RESPONSE_CODE);
}
Result<std::multimap<std::string, std::string>> getResponseHeaders() MIJIN_NOEXCEPT
{
// TODO: how to detect errors?
std::multimap<std::string, std::string> result;
curl_header* header = nullptr;
curl_header* prevHeader = nullptr;
while ((header = curl_easy_nextheader(handle_, CURLH_HEADER, 0, prevHeader)) != nullptr)
{
result.emplace(header->name, header->value);
prevHeader = header;
}
return result;
}
private:
template<typename TResult, typename TInfo = TResult>
Result<TResult> getInfo(CURLINFO info) MIJIN_NOEXCEPT
{
TInfo value = 0;
const CURLcode result = curl_easy_getinfo(handle_, info, &value);
if (result != CURLE_OK)
{
return Error{result};
}
return static_cast<TResult>(value);
}
};
} // namespace curl