88#include < regex>
99#include < sstream>
1010
11+ #ifdef _WIN32
12+ #include < windows.h>
13+ #else // POSIX
14+ #include < sys/stat.h>
15+ #endif
16+
1117namespace duckdb
1218{
1319 namespace netquack
1420 {
21+ bool file_exists (const char *file_path)
22+ {
23+ #ifdef _WIN32
24+ DWORD attributes = GetFileAttributesA (file_path);
25+ return (attributes != INVALID_FILE_ATTRIBUTES);
26+ #else // POSIX
27+ struct stat buffer;
28+ return (stat (file_path, &buffer) == 0 );
29+ #endif
30+ }
31+
32+ CURL *CreateCurlHandler ()
33+ {
34+ CURL *curl = curl_easy_init ();
35+ if (!curl)
36+ {
37+ throw std::runtime_error (" Failed to initialize CURL" );
38+ }
39+
40+ const char *ca_info = std::getenv (" CURL_CA_INFO" );
41+ #if !defined(_WIN32) && !defined(__APPLE__)
42+ if (!ca_info)
43+ {
44+ // Check for common CA certificate bundle locations on Linux
45+ for (const auto *path : {
46+ " /etc/ssl/certs/ca-certificates.crt" , // Debian/Ubuntu/Gentoo etc.
47+ " /etc/pki/tls/certs/ca-bundle.crt" , // Fedora/RHEL 6
48+ " /etc/ssl/ca-bundle.pem" , // OpenSUSE
49+ " /etc/pki/tls/cacert.pem" , // OpenELEC
50+ " /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem" , // CentOS/RHEL 7
51+ " /etc/ssl/cert.pem" // Alpine Linux
52+ })
53+ {
54+ if (file_exists (path))
55+ {
56+ ca_info = path;
57+ break ;
58+ }
59+ }
60+ }
61+ #endif
62+ curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L ); // Follow redirects
63+ curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, WriteCallback);
64+ if (ca_info)
65+ {
66+ // Set the custom CA certificate bundle file
67+ // https://github.com/hatamiarash7/duckdb-netquack/issues/6
68+ LogMessage (" DEBUG" , " Using custom CA certificate bundle: " + std::string (ca_info));
69+ curl_easy_setopt (curl, CURLOPT_CAINFO, ca_info);
70+ }
71+ const char *ca_path = std::getenv (" CURL_CA_PATH" );
72+ if (ca_path)
73+ {
74+ // Set the custom CA certificate directory
75+ LogMessage (" DEBUG" , " Using custom CA certificate directory: " + std::string (ca_path));
76+ curl_easy_setopt (curl, CURLOPT_CAPATH, ca_path);
77+ }
78+
79+ return curl;
80+ }
81+
1582 void LogMessage (const std::string &level, const std::string &message)
1683 {
1784 std::ofstream log_file (" netquack.log" , std::ios_base::app);
@@ -31,24 +98,19 @@ namespace duckdb
3198
3299 std::string DownloadPublicSuffixList ()
33100 {
34- CURL *curl;
101+ CURL *curl = CreateCurlHandler () ;
35102 CURLcode res;
36103 std::string readBuffer;
37104
38- curl = curl_easy_init ();
39- if (curl)
40- {
41- curl_easy_setopt (curl, CURLOPT_URL, " https://publicsuffix.org/list/public_suffix_list.dat" );
42- curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, WriteCallback);
43- curl_easy_setopt (curl, CURLOPT_WRITEDATA, &readBuffer);
44- res = curl_easy_perform (curl);
45- curl_easy_cleanup (curl);
105+ curl_easy_setopt (curl, CURLOPT_URL, " https://publicsuffix.org/list/public_suffix_list.dat" );
106+ curl_easy_setopt (curl, CURLOPT_WRITEDATA, &readBuffer);
107+ res = curl_easy_perform (curl);
108+ curl_easy_cleanup (curl);
46109
47- if (res != CURLE_OK)
48- {
49- LogMessage (" ERROR" , " Failed to download public suffix list: " + std::string (curl_easy_strerror (res)));
50- throw std::runtime_error (" Failed to download public suffix list. Check logs for details." );
51- }
110+ if (res != CURLE_OK)
111+ {
112+ LogMessage (" ERROR" , " Failed to download public suffix list: " + std::string (curl_easy_strerror (res)));
113+ throw std::runtime_error (" Failed to download public suffix list. Check logs for details." );
52114 }
53115
54116 return readBuffer;
0 commit comments