Common/HTTP: Implement Multiform

This commit is contained in:
Sketch 2023-11-11 09:51:46 -05:00 committed by Admiral H. Curtiss
parent 5f7e9d3bf1
commit 0d908a83e7
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
2 changed files with 38 additions and 3 deletions

View File

@ -33,7 +33,8 @@ public:
void FollowRedirects(long max); void FollowRedirects(long max);
s32 GetLastResponseCode(); s32 GetLastResponseCode();
Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload, Response Fetch(const std::string& url, Method method, const Headers& headers, const u8* payload,
size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only); size_t size, AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only,
std::span<Multiform> multiform = {});
static int CurlProgressCallback(Impl* impl, curl_off_t dltotal, curl_off_t dlnow, static int CurlProgressCallback(Impl* impl, curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow); curl_off_t ultotal, curl_off_t ulnow);
@ -174,6 +175,13 @@ void HttpRequest::Impl::UseIPv4()
curl_easy_setopt(m_curl.get(), CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_easy_setopt(m_curl.get(), CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
} }
HttpRequest::Response HttpRequest::PostMultiform(const std::string& url,
std::span<Multiform> multiform,
const Headers& headers, AllowedReturnCodes codes)
{
return m_impl->Fetch(url, Impl::Method::POST, headers, nullptr, 0, codes, multiform);
}
void HttpRequest::Impl::FollowRedirects(long max) void HttpRequest::Impl::FollowRedirects(long max)
{ {
curl_easy_setopt(m_curl.get(), CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(m_curl.get(), CURLOPT_FOLLOWLOCATION, 1);
@ -225,17 +233,33 @@ static size_t header_callback(char* buffer, size_t size, size_t nitems, void* us
HttpRequest::Response HttpRequest::Impl::Fetch(const std::string& url, Method method, HttpRequest::Response HttpRequest::Impl::Fetch(const std::string& url, Method method,
const Headers& headers, const u8* payload, const Headers& headers, const u8* payload,
size_t size, AllowedReturnCodes codes) size_t size, AllowedReturnCodes codes,
std::span<Multiform> multiform)
{ {
m_response_headers.clear(); m_response_headers.clear();
curl_easy_setopt(m_curl.get(), CURLOPT_POST, method == Method::POST); curl_easy_setopt(m_curl.get(), CURLOPT_POST, method == Method::POST);
curl_easy_setopt(m_curl.get(), CURLOPT_URL, url.c_str()); curl_easy_setopt(m_curl.get(), CURLOPT_URL, url.c_str());
if (method == Method::POST) if (method == Method::POST && multiform.empty())
{ {
curl_easy_setopt(m_curl.get(), CURLOPT_POSTFIELDS, payload); curl_easy_setopt(m_curl.get(), CURLOPT_POSTFIELDS, payload);
curl_easy_setopt(m_curl.get(), CURLOPT_POSTFIELDSIZE, size); curl_easy_setopt(m_curl.get(), CURLOPT_POSTFIELDSIZE, size);
} }
curl_mime* form = nullptr;
Common::ScopeGuard multiform_guard{[&form] { curl_mime_free(form); }};
if (!multiform.empty())
{
form = curl_mime_init(m_curl.get());
for (const auto& value : multiform)
{
curl_mimepart* part = curl_mime_addpart(form);
curl_mime_name(part, value.name.c_str());
curl_mime_data(part, value.data.c_str(), value.data.size());
}
curl_easy_setopt(m_curl.get(), CURLOPT_MIMEPOST, form);
}
curl_slist* list = nullptr; curl_slist* list = nullptr;
Common::ScopeGuard list_guard{[&list] { curl_slist_free_all(list); }}; Common::ScopeGuard list_guard{[&list] { curl_slist_free_all(list); }};
for (const auto& [name, value] : headers) for (const auto& [name, value] : headers)

View File

@ -8,6 +8,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <span>
#include <string> #include <string>
#include <vector> #include <vector>
@ -35,6 +36,12 @@ public:
using Response = std::optional<std::vector<u8>>; using Response = std::optional<std::vector<u8>>;
using Headers = std::map<std::string, std::optional<std::string>>; using Headers = std::map<std::string, std::optional<std::string>>;
struct Multiform
{
std::string name;
std::string data;
};
void SetCookies(const std::string& cookies); void SetCookies(const std::string& cookies);
void UseIPv4(); void UseIPv4();
void FollowRedirects(long max = 1); void FollowRedirects(long max = 1);
@ -48,6 +55,10 @@ public:
Response Post(const std::string& url, const std::string& payload, const Headers& headers = {}, Response Post(const std::string& url, const std::string& payload, const Headers& headers = {},
AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only); AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
Response PostMultiform(const std::string& url, std::span<Multiform> multiform,
const Headers& headers = {},
AllowedReturnCodes codes = AllowedReturnCodes::Ok_Only);
private: private:
class Impl; class Impl;
std::unique_ptr<Impl> m_impl; std::unique_ptr<Impl> m_impl;