#include "http_utils.hpp" #include #include #include static std::string find_ca_certificates() { // Common CA certificate locations across different Linux distributions const std::vector 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> 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 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 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> 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 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 lock(mtx); cv.wait(lock, [&] { return done; }); } worker.join(); return result; }