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" 
@@ -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