@@ -103,35 +103,51 @@ void CurlRequester::PerformRequestStatic(net::any_io_executor ctx, TlsOptions co
103103 // Use a unique_ptr to manage the cleanup of our curl instance.
104104 std::unique_ptr<CURL , decltype (&curl_easy_cleanup)> curl_guard (curl, curl_easy_cleanup);
105105
106+ // Helper macro to check curl_easy_setopt return values
107+ // Note: This macro captures ctx and cb by reference for error reporting
108+ #define CURL_SETOPT_CHECK (handle, option, parameter ) \
109+ do { \
110+ CURLcode code = curl_easy_setopt (handle, option, parameter); \
111+ if (code != CURLE_OK ) { \
112+ std::string error_message = kErrorCurlPrefix ; \
113+ error_message += " curl_easy_setopt failed for " #option " : " ; \
114+ error_message += curl_easy_strerror (code); \
115+ boost::asio::post (ctx, [cb = std::move (cb), error_message = std::move (error_message)]() { \
116+ cb (HttpResult (error_message)); \
117+ }); \
118+ return ; \
119+ } \
120+ } while (0 )
121+
106122 std::string response_body;
107123 HttpResult::HeadersType response_headers;
108124
109125 // Store URL to keep it alive for the duration of the request
110126 std::string url = request.Url ();
111127
112128 // Set URL
113- curl_easy_setopt (curl, CURLOPT_URL , url.c_str ());
129+ CURL_SETOPT_CHECK (curl, CURLOPT_URL , url.c_str ());
114130
115131 // Set HTTP method
116132 if (request.Method () == HttpMethod::kPost ) {
117133 // Basically CURLOPT_POST is a flag that indicates this is a post.
118134 // Passing 1 enables this flag.
119135 // This will also set a content type, but the headers for the request
120136 // should override that with the correct value.
121- curl_easy_setopt (curl, CURLOPT_POST , 1L );
137+ CURL_SETOPT_CHECK (curl, CURLOPT_POST , 1L );
122138 } else if (request.Method () == HttpMethod::kPut ) {
123- curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST , kHttpMethodPut );
139+ CURL_SETOPT_CHECK (curl, CURLOPT_CUSTOMREQUEST , kHttpMethodPut );
124140 } else if (request.Method () == HttpMethod::kReport ) {
125- curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST , kHttpMethodReport );
141+ CURL_SETOPT_CHECK (curl, CURLOPT_CUSTOMREQUEST , kHttpMethodReport );
126142 } else if (request.Method () == HttpMethod::kGet ) {
127- curl_easy_setopt (curl, CURLOPT_HTTPGET , 1L );
143+ CURL_SETOPT_CHECK (curl, CURLOPT_HTTPGET , 1L );
128144 }
129145
130146 // Set request body if present
131147 if (request.Body ().has_value ()) {
132148 const std::string& body = request.Body ().value ();
133- curl_easy_setopt (curl, CURLOPT_POSTFIELDS , body.c_str ());
134- curl_easy_setopt (curl, CURLOPT_POSTFIELDSIZE , body.size ());
149+ CURL_SETOPT_CHECK (curl, CURLOPT_POSTFIELDS , body.c_str ());
150+ CURL_SETOPT_CHECK (curl, CURLOPT_POSTFIELDSIZE , body.size ());
135151 }
136152
137153 // Set headers
@@ -156,31 +172,31 @@ void CurlRequester::PerformRequestStatic(net::any_io_executor ctx, TlsOptions co
156172 headers = appendResult;
157173 }
158174 if (headers) {
159- curl_easy_setopt (curl, CURLOPT_HTTPHEADER , headers);
175+ CURL_SETOPT_CHECK (curl, CURLOPT_HTTPHEADER , headers);
160176 }
161177
162178 // Set timeouts with millisecond precision
163179 const long connect_timeout_ms = request.Properties ().ConnectTimeout ().count ();
164180 const long response_timeout_ms = request.Properties ().ResponseTimeout ().count ();
165181
166- curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT_MS , connect_timeout_ms > 0 ? connect_timeout_ms : 30000L );
167- curl_easy_setopt (curl, CURLOPT_TIMEOUT_MS , response_timeout_ms > 0 ? response_timeout_ms : 60000L );
182+ CURL_SETOPT_CHECK (curl, CURLOPT_CONNECTTIMEOUT_MS , connect_timeout_ms > 0 ? connect_timeout_ms : 30000L );
183+ CURL_SETOPT_CHECK (curl, CURLOPT_TIMEOUT_MS , response_timeout_ms > 0 ? response_timeout_ms : 60000L );
168184
169185 // Set TLS options
170186 using VerifyMode = config::shared::built::TlsOptions::VerifyMode;
171187 if (tls_options.PeerVerifyMode () == VerifyMode::kVerifyNone ) {
172- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER , 0L );
173- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST , 0L );
188+ CURL_SETOPT_CHECK (curl, CURLOPT_SSL_VERIFYPEER , 0L );
189+ CURL_SETOPT_CHECK (curl, CURLOPT_SSL_VERIFYHOST , 0L );
174190 } else {
175- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER , 1L );
191+ CURL_SETOPT_CHECK (curl, CURLOPT_SSL_VERIFYPEER , 1L );
176192 // 1 or 2 seem to basically be the same, but the documentation says to
177193 // use 2, and that it would default to 2.
178194 // https://curl.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html
179- curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST , 2L );
195+ CURL_SETOPT_CHECK (curl, CURLOPT_SSL_VERIFYHOST , 2L );
180196
181197 // Set custom CA file if provided
182198 if (tls_options.CustomCAFile ().has_value ()) {
183- curl_easy_setopt (curl, CURLOPT_CAINFO , tls_options.CustomCAFile ()->c_str ());
199+ CURL_SETOPT_CHECK (curl, CURLOPT_CAINFO , tls_options.CustomCAFile ()->c_str ());
184200 }
185201 }
186202
@@ -189,19 +205,19 @@ void CurlRequester::PerformRequestStatic(net::any_io_executor ctx, TlsOptions co
189205 // Empty string explicitly disables proxy (overrides environment variables).
190206 auto const & proxy_url = request.Properties ().Proxy ().Url ();
191207 if (proxy_url.has_value ()) {
192- curl_easy_setopt (curl, CURLOPT_PROXY , proxy_url->c_str ());
208+ CURL_SETOPT_CHECK (curl, CURLOPT_PROXY , proxy_url->c_str ());
193209 }
194210 // If proxy URL is std::nullopt, CURL will use environment variables (default behavior)
195211
196212 // Set callbacks
197- curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION , WriteCallback);
198- curl_easy_setopt (curl, CURLOPT_WRITEDATA , &response_body);
199- curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION , HeaderCallback);
200- curl_easy_setopt (curl, CURLOPT_HEADERDATA , &response_headers);
213+ CURL_SETOPT_CHECK (curl, CURLOPT_WRITEFUNCTION , WriteCallback);
214+ CURL_SETOPT_CHECK (curl, CURLOPT_WRITEDATA , &response_body);
215+ CURL_SETOPT_CHECK (curl, CURLOPT_HEADERFUNCTION , HeaderCallback);
216+ CURL_SETOPT_CHECK (curl, CURLOPT_HEADERDATA , &response_headers);
201217
202218 // Follow redirects
203- curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION , 1L );
204- curl_easy_setopt (curl, CURLOPT_MAXREDIRS , 20L );
219+ CURL_SETOPT_CHECK (curl, CURLOPT_FOLLOWLOCATION , 1L );
220+ CURL_SETOPT_CHECK (curl, CURLOPT_MAXREDIRS , 20L );
205221
206222 // Perform the request
207223 CURLcode res = curl_easy_perform (curl);
0 commit comments