175 lines
6.0 KiB
C++
175 lines
6.0 KiB
C++
#include "http_utils.hpp"
|
|
#include <fstream>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
static std::string find_ca_certificates() {
|
|
// Common CA certificate locations across different Linux distributions
|
|
const std::vector<std::string> ca_paths = {
|
|
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Raspbian
|
|
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL/CentOS
|
|
"/etc/ssl/ca-bundle.pem", // OpenSUSE
|
|
"/etc/pki/tls/cert.pem", // Fedora/RHEL alternative
|
|
"/etc/ssl/certs/ca-bundle.crt", // Some distros
|
|
"/etc/ssl/cert.pem", // Alpine Linux
|
|
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD
|
|
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7+
|
|
"/etc/ca-certificates/extracted/tls-ca-bundle.pem" // Arch Linux
|
|
};
|
|
|
|
for (const auto& path : ca_paths) {
|
|
std::ifstream file(path);
|
|
if (file.good()) {
|
|
file.close();
|
|
return path;
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
HttpResponse http_get(const std::string& url, const std::string& path, bool use_https, double timeout_seconds) {
|
|
HttpResponse result{0, "", false};
|
|
bool done = false;
|
|
std::mutex mtx;
|
|
std::condition_variable cv;
|
|
|
|
std::thread worker([&]() {
|
|
trantor::EventLoop loop;
|
|
|
|
auto client = drogon::HttpClient::newHttpClient(
|
|
(use_https ? "https://" : "http://") + url,
|
|
&loop
|
|
);
|
|
|
|
// Configure SSL certificates for HTTPS
|
|
if (use_https) {
|
|
std::string ca_path = find_ca_certificates();
|
|
if (!ca_path.empty()) {
|
|
std::cerr << "Debug: Found CA certificates at: " << ca_path << std::endl;
|
|
// Use addSSLConfigs with proper parameter names for OpenSSL
|
|
std::vector<std::pair<std::string, std::string>> sslConfigs;
|
|
sslConfigs.push_back({"VerifyCAFile", ca_path});
|
|
client->addSSLConfigs(sslConfigs);
|
|
} else {
|
|
// If no CA certificates found, print warning but continue
|
|
std::cerr << "Warning: No system CA certificates found. SSL verification may fail." << std::endl;
|
|
}
|
|
}
|
|
|
|
auto req = drogon::HttpRequest::newHttpRequest();
|
|
req->setMethod(drogon::Get);
|
|
req->setPath(path);
|
|
|
|
client->sendRequest(req, [&](drogon::ReqResult res, const drogon::HttpResponsePtr &resp) {
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
if (res == drogon::ReqResult::Ok && resp) {
|
|
result.status_code = resp->statusCode();
|
|
result.body = resp->body();
|
|
result.success = true;
|
|
} else {
|
|
result.status_code = 0;
|
|
result.body = "";
|
|
result.success = false;
|
|
}
|
|
done = true;
|
|
cv.notify_one();
|
|
loop.quit();
|
|
}, timeout_seconds);
|
|
|
|
loop.loop();
|
|
});
|
|
|
|
// Wait for completion
|
|
{
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
cv.wait(lock, [&] { return done; });
|
|
}
|
|
|
|
worker.join();
|
|
return result;
|
|
}
|
|
|
|
HttpResponse http_get_with_ssl(const std::string& url, const std::string& path, const HttpClientSSLConfig& ssl_config, double timeout_seconds) {
|
|
HttpResponse result{0, "", false};
|
|
bool done = false;
|
|
std::mutex mtx;
|
|
std::condition_variable cv;
|
|
|
|
std::thread worker([&]() {
|
|
trantor::EventLoop loop;
|
|
|
|
// Create HTTPS client with SSL configuration options
|
|
auto client = drogon::HttpClient::newHttpClient(
|
|
"https://" + url,
|
|
&loop,
|
|
ssl_config.use_old_tls,
|
|
ssl_config.validate_cert
|
|
);
|
|
|
|
// Configure client certificate if provided
|
|
if (!ssl_config.cert_path.empty() && !ssl_config.key_path.empty()) {
|
|
client->setCertPath(ssl_config.cert_path, ssl_config.key_path);
|
|
}
|
|
|
|
// Configure SSL settings
|
|
std::vector<std::pair<std::string, std::string>> finalSslConfigs = ssl_config.ssl_configs;
|
|
|
|
// Set CA certificates path if not explicitly disabled
|
|
if (ssl_config.validate_cert) {
|
|
// Check if cafile is provided in ssl_configs
|
|
bool ca_path_set = false;
|
|
for (const auto& config : ssl_config.ssl_configs) {
|
|
if (config.first == "cafile" || config.first == "CAfile" ||
|
|
config.first == "VerifyCAFile") {
|
|
ca_path_set = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If no cafile provided, use system certificates
|
|
if (!ca_path_set) {
|
|
std::string ca_path = find_ca_certificates();
|
|
if (!ca_path.empty()) {
|
|
finalSslConfigs.push_back({"VerifyCAFile", ca_path});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add all SSL configurations at once
|
|
if (!finalSslConfigs.empty()) {
|
|
client->addSSLConfigs(finalSslConfigs);
|
|
}
|
|
|
|
auto req = drogon::HttpRequest::newHttpRequest();
|
|
req->setMethod(drogon::Get);
|
|
req->setPath(path);
|
|
|
|
client->sendRequest(req, [&](drogon::ReqResult res, const drogon::HttpResponsePtr &resp) {
|
|
std::lock_guard<std::mutex> lock(mtx);
|
|
if (res == drogon::ReqResult::Ok && resp) {
|
|
result.status_code = resp->statusCode();
|
|
result.body = resp->body();
|
|
result.success = true;
|
|
} else {
|
|
result.status_code = 0;
|
|
result.body = "";
|
|
result.success = false;
|
|
}
|
|
done = true;
|
|
cv.notify_one();
|
|
loop.quit();
|
|
}, timeout_seconds);
|
|
|
|
loop.loop();
|
|
});
|
|
|
|
// Wait for completion
|
|
{
|
|
std::unique_lock<std::mutex> lock(mtx);
|
|
cv.wait(lock, [&] { return done; });
|
|
}
|
|
|
|
worker.join();
|
|
return result;
|
|
} |