mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 13:37:42 -05:00
sys: Updated to use the new HttpRequest helper instead of Net
This commit is contained in:
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: c24015b8f5...3b7a928b7e
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: 0c3dcfdc3c...25922e11b9
@@ -23,7 +23,6 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/fs.cpp
|
||||
source/helpers/magic.cpp
|
||||
source/helpers/crypto.cpp
|
||||
source/helpers/net.cpp
|
||||
source/helpers/http_requests.cpp
|
||||
source/helpers/opengl.cpp
|
||||
source/helpers/patches.cpp
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
@@ -25,7 +26,8 @@ namespace hex {
|
||||
|
||||
class ResultBase {
|
||||
public:
|
||||
explicit ResultBase(u32 statusCode) : m_statusCode(statusCode) { }
|
||||
ResultBase() = default;
|
||||
explicit ResultBase(u32 statusCode) : m_statusCode(statusCode), m_valid(true) { }
|
||||
|
||||
[[nodiscard]] u32 getStatusCode() const {
|
||||
return this->m_statusCode;
|
||||
@@ -35,13 +37,19 @@ namespace hex {
|
||||
return this->getStatusCode() == 200;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isValid() const {
|
||||
return this->m_valid;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_statusCode;
|
||||
u32 m_statusCode = 0;
|
||||
bool m_valid = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Result : public ResultBase {
|
||||
public:
|
||||
Result() = default;
|
||||
Result(u32 statusCode, T data) : ResultBase(statusCode), m_data(std::move(data)) { }
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -102,6 +110,18 @@ namespace hex {
|
||||
HttpRequest::s_caCertData = std::move(data);
|
||||
}
|
||||
|
||||
static void setProxy(std::string proxy) {
|
||||
HttpRequest::s_proxyUrl = std::move(proxy);
|
||||
}
|
||||
|
||||
void setMethod(std::string method) {
|
||||
this->m_method = std::move(method);
|
||||
}
|
||||
|
||||
void setUrl(std::string url) {
|
||||
this->m_url = std::move(url);
|
||||
}
|
||||
|
||||
void addHeader(std::string key, std::string value) {
|
||||
this->m_headers[std::move(key)] = std::move(value);
|
||||
}
|
||||
@@ -110,24 +130,28 @@ namespace hex {
|
||||
this->m_body = std::move(body);
|
||||
}
|
||||
|
||||
void setTimeout(u32 timeout) {
|
||||
this->m_timeout = timeout;
|
||||
}
|
||||
|
||||
float getProgress() const {
|
||||
return this->m_progress;
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
this->m_canceled = true;
|
||||
}
|
||||
|
||||
template<typename T = std::string>
|
||||
std::future<Result<T>> downloadFile(const std::fs::path &path) {
|
||||
return std::async(std::launch::async, [this, path] {
|
||||
T response;
|
||||
std::vector<u8> response;
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, [](void *contents, size_t size, size_t nmemb, void *userdata){
|
||||
auto &file = *reinterpret_cast<wolv::io::File*>(userdata);
|
||||
|
||||
file.write(reinterpret_cast<const u8*>(contents), size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
});
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &file);
|
||||
|
||||
this->executeImpl<T>(response);
|
||||
|
||||
return Result<T>(200, std::move(response));
|
||||
return this->executeImpl<T>(response);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -135,13 +159,7 @@ namespace hex {
|
||||
return std::async(std::launch::async, [this] {
|
||||
std::vector<u8> response;
|
||||
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, [](void *contents, size_t size, size_t nmemb, void *userdata){
|
||||
auto &response = *reinterpret_cast<std::vector<u8>*>(userdata);
|
||||
|
||||
response.insert(response.end(), reinterpret_cast<const u8*>(contents), reinterpret_cast<const u8*>(contents) + size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
});
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &response);
|
||||
|
||||
return this->executeImpl<std::vector<u8>>(response);
|
||||
@@ -183,8 +201,8 @@ namespace hex {
|
||||
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
T responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToContainer<T>);
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
@@ -202,8 +220,8 @@ namespace hex {
|
||||
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
T responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToContainer<T>);
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
@@ -213,20 +231,46 @@ namespace hex {
|
||||
template<typename T = std::string>
|
||||
std::future<Result<T>> execute() {
|
||||
return std::async(std::launch::async, [this] {
|
||||
T data;
|
||||
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToContainer<T>);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &data);
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
|
||||
return this->executeImpl<T>(data);
|
||||
return this->executeImpl<T>(responseData);
|
||||
});
|
||||
}
|
||||
|
||||
std::string urlEncode(const std::string &input) {
|
||||
auto escapedString = curl_easy_escape(this->m_curl, input.c_str(), std::strlen(input.c_str()));
|
||||
|
||||
if (escapedString != nullptr) {
|
||||
std::string output = escapedString;
|
||||
curl_free(escapedString);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string urlDecode(const std::string &input) {
|
||||
auto unescapedString = curl_easy_unescape(this->m_curl, input.c_str(), std::strlen(input.c_str()), nullptr);
|
||||
|
||||
if (unescapedString != nullptr) {
|
||||
std::string output = unescapedString;
|
||||
curl_free(unescapedString);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
protected:
|
||||
void setDefaultConfig();
|
||||
|
||||
template<typename T>
|
||||
Result<T> executeImpl(T &data) {
|
||||
Result<T> executeImpl(std::vector<u8> &data) {
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_URL, this->m_url.c_str());
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_CUSTOMREQUEST, this->m_method.c_str());
|
||||
|
||||
@@ -245,52 +289,49 @@ namespace hex {
|
||||
}
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
auto result = curl_easy_perform(this->m_curl);
|
||||
printf("Curl result: %s\n", curl_easy_strerror(result));
|
||||
{
|
||||
std::scoped_lock lock(this->m_transmissionMutex);
|
||||
|
||||
auto result = curl_easy_perform(this->m_curl);
|
||||
if (result != CURLE_OK){
|
||||
char *url = nullptr;
|
||||
curl_easy_getinfo(this->m_curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", this->m_method, url, u32(result), curl_easy_strerror(result));
|
||||
if (!HttpRequest::s_proxyUrl.empty()){
|
||||
log::info("A custom proxy '{0}' is in use. Is it working correctly?", HttpRequest::s_proxyUrl);
|
||||
}
|
||||
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
u32 statusCode = 0;
|
||||
curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||
|
||||
return Result<T>(statusCode, std::move(data));
|
||||
return Result<T>(statusCode, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
|
||||
hex::unused(ctx, userData);
|
||||
|
||||
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
|
||||
|
||||
auto crt = static_cast<mbedtls_x509_crt*>(userData);
|
||||
mbedtls_x509_crt_init(crt);
|
||||
|
||||
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(HttpRequest::s_caCertData.data()), HttpRequest::s_caCertData.size());
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static size_t writeToContainer(void *contents, size_t size, size_t nmemb, void *userdata) {
|
||||
auto &response = *reinterpret_cast<T*>(userdata);
|
||||
auto startSize = response.size();
|
||||
|
||||
response.resize(startSize + size * nmemb);
|
||||
std::memcpy(response.data() + startSize, contents, size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
}
|
||||
[[maybe_unused]] static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData);
|
||||
static size_t writeToVector(void *contents, size_t size, size_t nmemb, void *userdata);
|
||||
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata);
|
||||
static int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
|
||||
|
||||
private:
|
||||
CURL *m_curl;
|
||||
|
||||
std::mutex m_transmissionMutex;
|
||||
|
||||
std::string m_method;
|
||||
std::string m_url;
|
||||
std::string m_body;
|
||||
std::map<std::string, std::string> m_headers;
|
||||
u32 m_timeout = 1000;
|
||||
|
||||
float m_progress = 0.0F;
|
||||
bool m_canceled = false;
|
||||
|
||||
[[maybe_unused]] std::unique_ptr<mbedtls_x509_crt> m_caCert;
|
||||
static std::string s_caCertData;
|
||||
static std::string s_caCertData, s_proxyUrl;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <future>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <atomic>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <curl/curl.h>
|
||||
#include <curl/system.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
struct Response {
|
||||
i32 code;
|
||||
T body;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Response<void> {
|
||||
i32 code;
|
||||
};
|
||||
|
||||
class Net {
|
||||
public:
|
||||
Net();
|
||||
~Net();
|
||||
|
||||
constexpr static u32 DefaultTimeout = 2'000;
|
||||
|
||||
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
||||
|
||||
std::future<Response<nlohmann::json>> postJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
||||
|
||||
std::future<Response<std::string>> uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<void>> downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
|
||||
|
||||
[[nodiscard]] std::string encode(const std::string &input);
|
||||
[[nodiscard]] std::string decode(const std::string &input);
|
||||
|
||||
[[nodiscard]] float getProgress() const { return this->m_progress; }
|
||||
|
||||
void cancel() { this->m_shouldCancel = true; }
|
||||
|
||||
static void setProxy(const std::string &url);
|
||||
static void setCACert(const std::string &content);
|
||||
|
||||
private:
|
||||
void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
||||
std::optional<i32> execute();
|
||||
|
||||
friend int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
|
||||
friend CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData);
|
||||
|
||||
private:
|
||||
CURL *m_ctx;
|
||||
mbedtls_x509_crt m_caCert;
|
||||
curl_slist *m_headers = nullptr;
|
||||
|
||||
std::mutex m_transmissionActive;
|
||||
float m_progress = 0.0F;
|
||||
bool m_shouldCancel = false;
|
||||
|
||||
static std::string s_proxyUrl;
|
||||
static std::string s_caCert;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -26,11 +26,11 @@ namespace hex {
|
||||
|
||||
void close();
|
||||
|
||||
[[nodiscard]] std::vector<u8> read(const std::fs::path &path);
|
||||
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path);
|
||||
[[nodiscard]] std::string readString(const std::fs::path &path);
|
||||
|
||||
void write(const std::fs::path &path, const std::vector<u8> &data);
|
||||
void write(const std::fs::path &path, const std::string &data);
|
||||
void writeVector(const std::fs::path &path, const std::vector<u8> &data);
|
||||
void writeString(const std::fs::path &path, const std::string &data);
|
||||
|
||||
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/");
|
||||
[[nodiscard]] bool contains(const std::fs::path &path);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <hex/data_processor/node.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -69,7 +68,7 @@ namespace hex {
|
||||
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
|
||||
|
||||
if (file.isValid()) {
|
||||
file.write(getSettingsData().dump(4));
|
||||
file.writeString(getSettingsData().dump(4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace hex {
|
||||
return false;
|
||||
|
||||
{
|
||||
const auto metadataContent = tar.read(MetadataPath);
|
||||
const auto metadataContent = tar.readVector(MetadataPath);
|
||||
|
||||
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
|
||||
return false;
|
||||
@@ -131,7 +131,7 @@ namespace hex {
|
||||
|
||||
{
|
||||
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
|
||||
tar.write(MetadataPath, metadataContent);
|
||||
tar.writeString(MetadataPath, metadataContent);
|
||||
}
|
||||
|
||||
ImHexApi::Provider::resetDirty();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace hex {
|
||||
|
||||
std::string HttpRequest::s_caCertData;
|
||||
std::string HttpRequest::s_proxyUrl;
|
||||
|
||||
void HttpRequest::setDefaultConfig() {
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
||||
@@ -13,8 +14,11 @@ namespace hex {
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_TIMEOUT_MS, 0L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_CONNECTTIMEOUT_MS, 10000);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_CONNECTTIMEOUT_MS, this->m_timeout);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFODATA, this);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_PROXY, s_proxyUrl.c_str());
|
||||
|
||||
#if defined(IMHEX_USE_BUNDLED_CA)
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_CAINFO, nullptr);
|
||||
@@ -27,4 +31,50 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
CURLcode HttpRequest::sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
|
||||
hex::unused(ctx, userData);
|
||||
|
||||
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
|
||||
|
||||
auto crt = static_cast<mbedtls_x509_crt*>(userData);
|
||||
mbedtls_x509_crt_init(crt);
|
||||
|
||||
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(HttpRequest::s_caCertData.data()), HttpRequest::s_caCertData.size());
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
size_t HttpRequest::writeToVector(void *contents, size_t size, size_t nmemb, void *userdata) {
|
||||
auto &response = *reinterpret_cast<std::vector<u8>*>(userdata);
|
||||
auto startSize = response.size();
|
||||
|
||||
response.resize(startSize + size * nmemb);
|
||||
std::memcpy(response.data() + startSize, contents, size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
size_t HttpRequest::writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) {
|
||||
auto &file = *reinterpret_cast<wolv::io::File*>(userdata);
|
||||
|
||||
file.writeBuffer(reinterpret_cast<const u8*>(contents), size * nmemb);
|
||||
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
|
||||
auto &request = *static_cast<HttpRequest *>(contents);
|
||||
|
||||
if (dlTotal > 0)
|
||||
request.m_progress = float(dlNow) / dlTotal;
|
||||
else if (ulTotal > 0)
|
||||
request.m_progress = float(ulNow) / ulTotal;
|
||||
else
|
||||
request.m_progress = 0.0F;
|
||||
|
||||
return request.m_canceled ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,306 +0,0 @@
|
||||
#include <hex/helpers/net.hpp>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstdio>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
Net::Net() {
|
||||
AT_FIRST_TIME {
|
||||
curl_global_sslset(CURLSSLBACKEND_MBEDTLS, nullptr, nullptr);
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
};
|
||||
|
||||
AT_FINAL_CLEANUP {
|
||||
curl_global_cleanup();
|
||||
};
|
||||
|
||||
this->m_ctx = curl_easy_init();
|
||||
}
|
||||
|
||||
Net::~Net() {
|
||||
curl_easy_cleanup(this->m_ctx);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
|
||||
hex::unused(ctx, userData);
|
||||
|
||||
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
|
||||
|
||||
auto crt = static_cast<mbedtls_x509_crt*>(userData);
|
||||
mbedtls_x509_crt_init(crt);
|
||||
|
||||
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(Net::s_caCert.data()), Net::s_caCert.size());
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
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, u32 timeout, 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;
|
||||
|
||||
this->m_headers = curl_slist_append(this->m_headers, entry.c_str());
|
||||
}
|
||||
|
||||
if (!body.empty())
|
||||
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_WRITEDATA, &response);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_TIMEOUT_MS, 0L);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_CONNECTTIMEOUT_MS, timeout);
|
||||
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);
|
||||
|
||||
#if defined(IMHEX_USE_BUNDLED_CA)
|
||||
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_SSL_CTX_DATA, &this->m_caCert);
|
||||
#endif
|
||||
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
|
||||
}
|
||||
|
||||
std::optional<i32> Net::execute() {
|
||||
CURLcode result = curl_easy_perform(this->m_ctx);
|
||||
if (result != CURLE_OK){
|
||||
char *url = nullptr;
|
||||
curl_easy_getinfo(this->m_ctx, CURLINFO_EFFECTIVE_URL, &url);
|
||||
log::error("Net request '{0}' failed with error {1}: '{2}'", url, u32(result), curl_easy_strerror(result));
|
||||
if(!Net::s_proxyUrl.empty()){
|
||||
log::info("A custom proxy '{}' is in use. Is it working correctly?", Net::s_proxyUrl);
|
||||
}
|
||||
}
|
||||
|
||||
long responseCode = 0;
|
||||
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
|
||||
curl_slist_free_all(this->m_headers);
|
||||
this->m_headers = nullptr;
|
||||
this->m_progress = 0.0F;
|
||||
this->m_shouldCancel = false;
|
||||
|
||||
if (result != CURLE_OK)
|
||||
return std::nullopt;
|
||||
else
|
||||
return i32(responseCode);
|
||||
}
|
||||
|
||||
std::future<Response<std::string>> Net::getString(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
|
||||
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, timeout, extraHeaders, body);
|
||||
|
||||
auto responseCode = execute();
|
||||
|
||||
return Response<std::string> { responseCode.value_or(0), response };
|
||||
});
|
||||
}
|
||||
|
||||
std::future<Response<nlohmann::json>> Net::getJson(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
|
||||
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, timeout, extraHeaders, body);
|
||||
|
||||
auto responseCode = execute();
|
||||
if (!responseCode.has_value())
|
||||
return Response<nlohmann::json> { 0, { } };
|
||||
else
|
||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
|
||||
});
|
||||
}
|
||||
|
||||
std::future<Response<nlohmann::json>> Net::postJson(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
|
||||
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, "POST");
|
||||
setCommonSettings(response, url, timeout, extraHeaders, body);
|
||||
|
||||
auto responseCode = execute();
|
||||
if (!responseCode.has_value())
|
||||
return Response<nlohmann::json> { 0, { } };
|
||||
else
|
||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
|
||||
});
|
||||
}
|
||||
|
||||
std::future<Response<std::string>> Net::uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout) {
|
||||
this->m_transmissionActive.lock();
|
||||
|
||||
return std::async(std::launch::async, [=, this] {
|
||||
std::string response;
|
||||
|
||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
||||
|
||||
wolv::io::File file(filePath, wolv::io::File::Mode::Read);
|
||||
if (!file.isValid())
|
||||
return Response<std::string> { 400, {} };
|
||||
|
||||
curl_mime *mime = curl_mime_init(this->m_ctx);
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
auto fileName = wolv::util::toUTF8String(filePath.filename());
|
||||
curl_mime_data_cb(part, file.getSize(),
|
||||
[](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);
|
||||
|
||||
if (fseek(file, offset, origin) != 0)
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
else
|
||||
return CURL_SEEKFUNC_OK;
|
||||
},
|
||||
[](void *arg) {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
|
||||
fclose(file);
|
||||
},
|
||||
file.getHandle());
|
||||
curl_mime_filename(part, fileName.c_str());
|
||||
curl_mime_name(part, "file");
|
||||
|
||||
setCommonSettings(response, url, timeout);
|
||||
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::fs::path &filePath, u32 timeout) {
|
||||
this->m_transmissionActive.lock();
|
||||
|
||||
return std::async(std::launch::async, [=, this] {
|
||||
std::string response;
|
||||
|
||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
||||
|
||||
wolv::io::File file(filePath, wolv::io::File::Mode::Create);
|
||||
if (!file.isValid())
|
||||
return Response<void> { 400 };
|
||||
|
||||
setCommonSettings(response, url, timeout);
|
||||
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) };
|
||||
});
|
||||
}
|
||||
|
||||
std::string Net::encode(const std::string &input) {
|
||||
auto escapedString = curl_easy_escape(this->m_ctx, input.c_str(), std::strlen(input.c_str()));
|
||||
|
||||
if (escapedString != nullptr) {
|
||||
std::string output = escapedString;
|
||||
curl_free(escapedString);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string Net::decode(const std::string &input) {
|
||||
auto unescapedString = curl_easy_unescape(this->m_ctx, input.c_str(), std::strlen(input.c_str()), nullptr);
|
||||
|
||||
if (unescapedString != nullptr) {
|
||||
std::string output = unescapedString;
|
||||
curl_free(unescapedString);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string Net::s_proxyUrl;
|
||||
void Net::setProxy(const std::string &url) {
|
||||
Net::s_proxyUrl = url;
|
||||
}
|
||||
|
||||
std::string Net::s_caCert;
|
||||
void Net::setCACert(const std::string &content) {
|
||||
Net::s_caCert = content;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace hex {
|
||||
this->m_valid = false;
|
||||
}
|
||||
|
||||
std::vector<u8> Tar::read(const std::fs::path &path) {
|
||||
std::vector<u8> Tar::readVector(const std::fs::path &path) {
|
||||
mtar_header_t header;
|
||||
|
||||
auto fixedPath = path.string();
|
||||
@@ -100,11 +100,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::string Tar::readString(const std::fs::path &path) {
|
||||
auto result = this->read(path);
|
||||
auto result = this->readVector(path);
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
void Tar::write(const std::fs::path &path, const std::vector<u8> &data) {
|
||||
void Tar::writeVector(const std::fs::path &path, const std::vector<u8> &data) {
|
||||
if (path.has_parent_path()) {
|
||||
std::fs::path pathPart;
|
||||
for (const auto &part : path.parent_path()) {
|
||||
@@ -126,8 +126,8 @@ namespace hex {
|
||||
mtar_write_data(&this->m_ctx, data.data(), data.size());
|
||||
}
|
||||
|
||||
void Tar::write(const std::fs::path &path, const std::string &data) {
|
||||
this->write(path, std::vector<u8>(data.begin(), data.end()));
|
||||
void Tar::writeString(const std::fs::path &path, const std::string &data) {
|
||||
this->writeVector(path, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) {
|
||||
@@ -140,7 +140,7 @@ namespace hex {
|
||||
buffer.resize(std::min<u64>(BufferSize, header->size - offset));
|
||||
|
||||
mtar_read_data(ctx, buffer.data(), buffer.size());
|
||||
outputFile.write(buffer);
|
||||
outputFile.writeVector(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace hex::prv {
|
||||
bufferSize = std::min<size_t>(bufferSize, this->getActualSize() - offset);
|
||||
|
||||
this->read(offset + this->getBaseAddress(), buffer.data(), bufferSize, true);
|
||||
file.write(buffer.data(), bufferSize);
|
||||
file.writeBuffer(buffer.data(), bufferSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user