1
0
mirror of synced 2024-11-15 03:27:40 +01:00
ImHex/plugins/libimhex/source/helpers/net.cpp

231 lines
8.3 KiB
C++
Raw Normal View History

#include <hex/helpers/net.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/file.hpp>
#include <filesystem>
2021-08-28 00:45:59 +02:00
#include <cstdio>
#include <mbedtls/ssl.h>
#include <mbedtls/error.h>
2021-07-31 17:10:19 +02:00
#include <nlohmann/json.hpp>
2021-07-31 17:10:19 +02:00
#include <hex/resources.hpp>
namespace hex {
Net::Net() {
2021-08-28 00:45:59 +02:00
FIRST_TIME {
curl_global_sslset(CURLSSLBACKEND_MBEDTLS, nullptr, nullptr);
curl_global_init(CURL_GLOBAL_ALL);
};
FINAL_CLEANUP {
curl_global_cleanup();
};
this->m_ctx = curl_easy_init();
}
Net::~Net() {
curl_easy_cleanup(this->m_ctx);
}
2021-08-28 00:45:59 +02:00
static size_t writeToString(void *contents, size_t size, size_t nmemb, void *userdata){
static_cast<std::string*>(userdata)->append((char*)contents, size * nmemb);
return size * nmemb;
}
2021-08-28 00:45:59 +02:00
static size_t readFromFile(void *contents, size_t size, size_t nmemb, void *userdata) {
FILE *file = static_cast<FILE*>(userdata);
return fread(contents, size, nmemb, file);
}
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) {
FILE *file = static_cast<FILE*>(userdata);
return fwrite(contents, size, nmemb, file);
}
static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userdata) {
auto* cfg = static_cast<mbedtls_ssl_config*>(sslctx);
static mbedtls_x509_crt crt;
mbedtls_x509_crt_init(&crt);
mbedtls_x509_crt_parse(&crt, cacert, cacert_size);
mbedtls_ssl_conf_ca_chain(cfg, &crt, nullptr);
return CURLE_OK;
}
2021-08-28 00:45:59 +02:00
int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
auto &net = *static_cast<Net*>(contents);
if (dlTotal > 0)
net.m_progress = float(dlNow) / dlTotal;
else if (ulTotal > 0)
net.m_progress = float(ulNow) / ulTotal;
else
net.m_progress = 0.0F;
return net.m_shouldCancel ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
}
void Net::setCommonSettings(std::string &response, const std::string &url, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
this->m_headers = curl_slist_append(this->m_headers, "Cache-Control: no-cache");
if (!extraHeaders.empty())
for (const auto &[key, value] : extraHeaders) {
std::string entry = key;
entry += ": ";
entry += value;
2021-08-28 00:45:59 +02:00
this->m_headers = curl_slist_append(this->m_headers, entry.c_str());
}
if (!body.empty())
2021-08-28 00:45:59 +02:00
curl_easy_setopt(this->m_ctx, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(this->m_ctx, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(this->m_ctx, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_easy_setopt(this->m_ctx, CURLOPT_URL, url.c_str());
curl_easy_setopt(this->m_ctx, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(this->m_ctx, CURLOPT_HTTPHEADER, this->m_headers);
curl_easy_setopt(this->m_ctx, CURLOPT_USERAGENT, "ImHex/1.0");
curl_easy_setopt(this->m_ctx, CURLOPT_DEFAULT_PROTOCOL, "https");
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToString);
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(this->m_ctx, CURLOPT_CAINFO, nullptr);
curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr);
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(this->m_ctx, CURLOPT_TIMEOUT_MS, 0L);
curl_easy_setopt(this->m_ctx, CURLOPT_CONNECTTIMEOUT_MS, 2000L);
curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFOFUNCTION, progressCallback);
curl_easy_setopt(this->m_ctx, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(this->m_ctx, CURLOPT_NOPROGRESS, 0L);
}
2021-08-28 00:45:59 +02:00
std::optional<s32> Net::execute() {
CURLcode result = curl_easy_perform(this->m_ctx);
2021-08-28 00:45:59 +02:00
s32 responseCode = 0;
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
2021-08-28 00:45:59 +02:00
curl_slist_free_all(this->m_headers);
this->m_headers = nullptr;
this->m_progress = 0.0F;
this->m_shouldCancel = false;
if (result != CURLE_OK)
2021-08-28 00:45:59 +02:00
return { };
else
2021-08-28 00:45:59 +02:00
return responseCode;
}
2021-08-28 00:45:59 +02:00
std::future<Response<std::string>> Net::getString(const std::string &url) {
this->m_transmissionActive.lock();
2021-08-28 00:45:59 +02:00
return std::async(std::launch::async, [=, this]{
std::string response;
2021-08-28 00:45:59 +02:00
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
2021-08-28 00:45:59 +02:00
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
setCommonSettings(response, url);
2021-08-28 00:45:59 +02:00
auto responseCode = execute();
return Response<std::string> { responseCode.value_or(0), response };
});
}
std::future<Response<nlohmann::json>> Net::getJson(const std::string &url) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this]{
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
setCommonSettings(response, url, {});
auto responseCode = execute();
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response) };
});
}
std::future<Response<std::string>> Net::uploadFile(const std::string &url, const std::filesystem::path &filePath) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this] {
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
File file(filePath.string(), File::Mode::Read);
if (!file.isValid())
2021-08-28 00:45:59 +02:00
return Response<std::string> { 400, { } };
curl_mime *mime = curl_mime_init(this->m_ctx);
curl_mimepart *part = curl_mime_addpart(mime);
auto fileName = filePath.filename().string();
curl_mime_data_cb(part, file.getSize(),
2021-08-28 00:45:59 +02:00
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto file = static_cast<FILE*>(arg);
return fread(buffer, size, nitems, file);
},
[](void *arg, curl_off_t offset, int origin) -> int {
auto file = static_cast<FILE*>(arg);
fseek(file, offset, origin);
return CURL_SEEKFUNC_OK;
},
[](void *arg) {
auto file = static_cast<FILE*>(arg);
fclose(file);
}, file.getHandle());
2021-08-28 00:45:59 +02:00
curl_mime_filename(part, fileName.c_str());
curl_mime_name(part, "file");
setCommonSettings(response, url);
curl_easy_setopt(this->m_ctx, CURLOPT_MIMEPOST, mime);
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "POST");
auto responseCode = execute();
return Response<std::string> { responseCode.value_or(0), response };
});
}
std::future<Response<void>> Net::downloadFile(const std::string &url, const std::filesystem::path &filePath) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this]{
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
File file(filePath.string(), File::Mode::Create);
if (!file.isValid())
return Response<void> { 400 };
setCommonSettings(response, url, {});
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToFile);
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, file.getHandle());
auto responseCode = execute();
return Response<void> { responseCode.value_or(0) };
});
}
}