77#include  < sys/stat.h> 
88#include  " duckdb/common/exception/http_exception.hpp" 
99
10- #ifndef  EMSCRIPTEN
11- #include  " httpfs_curl_client.hpp" 
12- #endif 
10+ #define  CHECK_CURL_OK (expr ) D_ASSERT((expr) == CURLE_OK)
1311
1412namespace  duckdb  {
1513
@@ -91,11 +89,11 @@ CURLHandle::CURLHandle(const string &token, const string &cert_path) {
9189		throw  InternalException (" Failed to initialize curl"  );
9290	}
9391	if  (!token.empty ()) {
94- 		curl_easy_setopt (curl, CURLOPT_XOAUTH2_BEARER, token.c_str ());
95- 		curl_easy_setopt (curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
92+ 		CHECK_CURL_OK ( curl_easy_setopt (curl, CURLOPT_XOAUTH2_BEARER, token.c_str () ));
93+ 		CHECK_CURL_OK ( curl_easy_setopt (curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER) );
9694	}
9795	if  (!cert_path.empty ()) {
98- 		curl_easy_setopt (curl, CURLOPT_CAINFO, cert_path.c_str ());
96+ 		CHECK_CURL_OK ( curl_easy_setopt (curl, CURLOPT_CAINFO, cert_path.c_str () ));
9997	}
10098}
10199
@@ -110,7 +108,7 @@ struct RequestInfo {
110108	std::vector<HTTPHeaders> header_collection;
111109};
112110
113- static  idx_t  httpfs_client_count =  0 ;
111+ static  std::atomic< idx_t >  httpfs_client_count { 0 } ;
114112
115113class  HTTPFSCurlClient  : public  HTTPClient  {
116114public: 
@@ -129,45 +127,48 @@ class HTTPFSCurlClient : public HTTPClient {
129127
130128		//  set curl options
131129		//  follow redirects
132- 		curl_easy_setopt (*curl, CURLOPT_FOLLOWLOCATION, 1L );
130+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_FOLLOWLOCATION, 1L ) );
133131
134132		//  Curl re-uses connections by default
135133		if  (!http_params.keep_alive ) {
136- 			curl_easy_setopt (*curl, CURLOPT_FORBID_REUSE, 1L );
134+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_FORBID_REUSE, 1L ) );
137135		}
138136
139137		if  (http_params.enable_curl_server_cert_verification ) {
140- 			curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYPEER, 1L ); //  Verify the cert
141- 			curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYHOST, 2L ); //  Verify that the cert matches the hostname
138+ 			CHECK_CURL_OK (curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYPEER, 1L )); //  Verify the cert
139+ 			CHECK_CURL_OK (
140+ 			    curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYHOST, 2L )); //  Verify that the cert matches the hostname
142141		} else  {
143- 			curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYPEER, 0L ); //  Override default, don't verify the cert
144- 			curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYHOST,
145- 			                 0L ); //  Override default, don't verify that the cert matches the hostname
142+ 			CHECK_CURL_OK (
143+ 			    curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYPEER, 0L )); //  Override default, don't verify the cert
144+ 			CHECK_CURL_OK (curl_easy_setopt (*curl, CURLOPT_SSL_VERIFYHOST,
145+ 			                               0L )); //  Override default, don't verify that the cert matches the hostname
146146		}
147147
148148		//  set read timeout
149- 		curl_easy_setopt (*curl, CURLOPT_TIMEOUT, http_params.timeout );
149+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_TIMEOUT, http_params.timeout ) );
150150		//  set connection timeout
151- 		curl_easy_setopt (*curl, CURLOPT_CONNECTTIMEOUT, http_params.timeout );
151+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_CONNECTTIMEOUT, http_params.timeout ) );
152152		//  accept content as-is (i.e no decompressing)
153- 		curl_easy_setopt (*curl, CURLOPT_ACCEPT_ENCODING, " identity"  );
153+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_ACCEPT_ENCODING, " identity" ) );
154154		//  follow redirects
155- 		curl_easy_setopt (*curl, CURLOPT_FOLLOWLOCATION, 1L );
155+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_FOLLOWLOCATION, 1L ) );
156156
157157		//  define the header callback
158- 		curl_easy_setopt (*curl, CURLOPT_HEADERFUNCTION, RequestHeaderCallback);
159- 		curl_easy_setopt (*curl, CURLOPT_HEADERDATA, &request_info->header_collection );
158+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HEADERFUNCTION, RequestHeaderCallback) );
159+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HEADERDATA, &request_info->header_collection ) );
160160		//  define the write data callback (for get requests)
161- 		curl_easy_setopt (*curl, CURLOPT_WRITEFUNCTION, RequestWriteCallback);
162- 		curl_easy_setopt (*curl, CURLOPT_WRITEDATA, &request_info->body );
161+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_WRITEFUNCTION, RequestWriteCallback) );
162+ 		CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_WRITEDATA, &request_info->body ) );
163163
164164		if  (!http_params.http_proxy .empty ()) {
165- 			curl_easy_setopt (*curl, CURLOPT_PROXY,
166- 			                 StringUtil::Format (" %s:%s"  , http_params.http_proxy , http_params.http_proxy_port ).c_str ());
165+ 			CHECK_CURL_OK (curl_easy_setopt (
166+ 			    *curl, CURLOPT_PROXY,
167+ 			    StringUtil::Format (" %s:%s"  , http_params.http_proxy , http_params.http_proxy_port ).c_str ()));
167168
168169			if  (!http_params.http_proxy_username .empty ()) {
169- 				curl_easy_setopt (*curl, CURLOPT_PROXYUSERNAME, http_params.http_proxy_username .c_str ());
170- 				curl_easy_setopt (*curl, CURLOPT_PROXYPASSWORD, http_params.http_proxy_password .c_str ());
170+ 				CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_PROXYUSERNAME, http_params.http_proxy_username .c_str () ));
171+ 				CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_PROXYPASSWORD, http_params.http_proxy_password .c_str () ));
171172			}
172173		}
173174	}
@@ -191,9 +192,9 @@ class HTTPFSCurlClient : public HTTPClient {
191192		CURLcode res;
192193		{
193194			//  If the same handle served a HEAD request, we must set NOBODY back to 0L to request content again
194- 			curl_easy_setopt (*curl, CURLOPT_NOBODY, 0L );
195- 			curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str ());
196- 			curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr );
195+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_NOBODY, 0L ) );
196+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str () ));
197+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr ) );
197198			res = curl->Execute ();
198199		}
199200
@@ -237,15 +238,15 @@ class HTTPFSCurlClient : public HTTPClient {
237238
238239		CURLcode res;
239240		{
240- 			curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str ());
241+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str () ));
241242			//  Perform PUT
242- 			curl_easy_setopt (*curl, CURLOPT_CUSTOMREQUEST, " PUT"  );
243+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_CUSTOMREQUEST, " PUT" ) );
243244			//  Include PUT body
244- 			curl_easy_setopt (*curl, CURLOPT_POSTFIELDS, const_char_ptr_cast (info.buffer_in ));
245- 			curl_easy_setopt (*curl, CURLOPT_POSTFIELDSIZE, info.buffer_in_len );
245+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_POSTFIELDS, const_char_ptr_cast (info.buffer_in ) ));
246+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_POSTFIELDSIZE, info.buffer_in_len ) );
246247
247248			//  Apply headers
248- 			curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr );
249+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr ) );
249250
250251			res = curl->Execute ();
251252		}
@@ -271,14 +272,14 @@ class HTTPFSCurlClient : public HTTPClient {
271272		CURLcode res;
272273		{
273274			//  Set URL
274- 			curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str ());
275+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str () ));
275276
276277			//  Perform HEAD request instead of GET
277- 			curl_easy_setopt (*curl, CURLOPT_NOBODY, 1L );
278- 			curl_easy_setopt (*curl, CURLOPT_HTTPGET, 0L );
278+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_NOBODY, 1L ) );
279+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HTTPGET, 0L ) );
279280
280281			//  Add headers if any
281- 			curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr );
282+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr ) );
282283
283284			//  Execute HEAD request
284285			res = curl->Execute ();
@@ -304,16 +305,16 @@ class HTTPFSCurlClient : public HTTPClient {
304305		CURLcode res;
305306		{
306307			//  Set URL
307- 			curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str ());
308+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str () ));
308309
309310			//  Set DELETE request method
310- 			curl_easy_setopt (*curl, CURLOPT_CUSTOMREQUEST, " DELETE"  );
311+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_CUSTOMREQUEST, " DELETE" ) );
311312
312313			//  Follow redirects
313- 			curl_easy_setopt (*curl, CURLOPT_FOLLOWLOCATION, 1L );
314+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_FOLLOWLOCATION, 1L ) );
314315
315316			//  Add headers if any
316- 			curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr );
317+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr ) );
317318
318319			//  Execute DELETE request
319320			res = curl->Execute ();
@@ -342,15 +343,15 @@ class HTTPFSCurlClient : public HTTPClient {
342343
343344		CURLcode res;
344345		{
345- 			curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str ());
346- 			curl_easy_setopt (*curl, CURLOPT_POST, 1L );
346+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_URL, request_info->url .c_str () ));
347+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_POST, 1L ) );
347348
348349			//  Set POST body
349- 			curl_easy_setopt (*curl, CURLOPT_POSTFIELDS, const_char_ptr_cast (info.buffer_in ));
350- 			curl_easy_setopt (*curl, CURLOPT_POSTFIELDSIZE, info.buffer_in_len );
350+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_POSTFIELDS, const_char_ptr_cast (info.buffer_in ) ));
351+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_POSTFIELDSIZE, info.buffer_in_len ) );
351352
352353			//  Add headers if any
353- 			curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr );
354+ 			CHECK_CURL_OK ( curl_easy_setopt (*curl, CURLOPT_HTTPHEADER, curl_headers ? curl_headers.headers  : nullptr ) );
354355
355356			//  Execute POST request
356357			res = curl->Execute ();
@@ -430,13 +431,7 @@ class HTTPFSCurlClient : public HTTPClient {
430431	optional_ptr<HTTPState> state;
431432	unique_ptr<RequestInfo> request_info;
432433
433- 	static  std::mutex &GetRefLock () {
434- 		static  std::mutex mtx;
435- 		return  mtx;
436- 	}
437- 
438434	static  void  InitCurlGlobal () {
439- 		GetRefLock ();
440435		if  (httpfs_client_count == 0 ) {
441436			curl_global_init (CURL_GLOBAL_DEFAULT);
442437		}
@@ -446,7 +441,6 @@ class HTTPFSCurlClient : public HTTPClient {
446441	static  void  DestroyCurlGlobal () {
447442		//  TODO: when to call curl_global_cleanup()
448443		//  calling it on client destruction causes SSL errors when verification is on (due to many requests).
449- 		//  GetRefLock();
450444		//  if (httpfs_client_count == 0) {
451445		//  	throw InternalException("Destroying Httpfs client that did not initialize CURL");
452446		//  }
0 commit comments