This commit is contained in:
parent
ede75f5565
commit
1fce6fc0b4
@ -1,4 +1,32 @@
|
||||
#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};
|
||||
@ -14,6 +42,105 @@ HttpResponse http_get(const std::string& url, const std::string& path, bool use_
|
||||
&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);
|
||||
|
@ -13,5 +13,17 @@ struct HttpResponse {
|
||||
bool success;
|
||||
};
|
||||
|
||||
// SSL configuration options for HTTP client
|
||||
struct HttpClientSSLConfig {
|
||||
std::string cert_path; // Client certificate path
|
||||
std::string key_path; // Client key path
|
||||
bool validate_cert = true; // Whether to validate server certificate
|
||||
bool use_old_tls = false; // Enable TLS 1.0/1.1
|
||||
std::vector<std::pair<std::string, std::string>> ssl_configs; // Additional SSL_CONF_cmd options
|
||||
};
|
||||
|
||||
// Utility function for blocking HTTP GET requests
|
||||
HttpResponse http_get(const std::string& url, const std::string& path, bool use_https = false, double timeout_seconds = 10.0);
|
||||
HttpResponse http_get(const std::string& url, const std::string& path, bool use_https = false, double timeout_seconds = 10.0);
|
||||
|
||||
// Utility function for blocking HTTP GET requests with SSL configuration
|
||||
HttpResponse http_get_with_ssl(const std::string& url, const std::string& path, const HttpClientSSLConfig& ssl_config, double timeout_seconds = 10.0);
|
@ -15,7 +15,7 @@ int main() {
|
||||
std::cout << "Retrieving IP address..." << std::endl;
|
||||
|
||||
// Use the utility function for HTTP GET
|
||||
auto response = http_get("ipinfo.io", "/ip", false, 10.0);
|
||||
auto response = http_get("ipinfo.io", "/ip", true, 10.0);
|
||||
|
||||
ASSERT(response.success && response.status_code == 200, "Failed to get IP");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user