dropshell-build/tests/ipdemo/src/http_utils.cpp
j842 222ed229ef
Some checks failed
dropshell-build / build (push) Failing after 6s
.
2025-06-10 11:12:28 +12:00

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;
}