1 | #include "cpr/session.h" |
2 | |
3 | #include <algorithm> |
4 | #include <cstdlib> |
5 | #include <cstring> |
6 | #include <fstream> |
7 | #include <functional> |
8 | #include <iostream> |
9 | #include <stdexcept> |
10 | #include <string> |
11 | |
12 | #include <curl/curl.h> |
13 | |
14 | #include "cpr/async.h" |
15 | #include "cpr/cprtypes.h" |
16 | #include "cpr/interceptor.h" |
17 | #include "cpr/util.h" |
18 | |
19 | #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION |
20 | #include "cpr/ssl_ctx.h" |
21 | #endif |
22 | |
23 | |
24 | namespace cpr { |
25 | // Ignored here since libcurl reqires a long: |
26 | // NOLINTNEXTLINE(google-runtime-int) |
27 | constexpr long ON = 1L; |
28 | // Ignored here since libcurl reqires a long: |
29 | // NOLINTNEXTLINE(google-runtime-int) |
30 | constexpr long OFF = 0L; |
31 | |
32 | CURLcode Session::DoEasyPerform() { |
33 | if (isUsedInMultiPerform) { |
34 | std::cerr << "curl_easy_perform cannot be executed if the CURL handle is used in a MultiPerform." << std::endl; |
35 | return CURLcode::CURLE_FAILED_INIT; |
36 | } |
37 | return curl_easy_perform(curl: curl_->handle); |
38 | } |
39 | |
40 | void Session::() { |
41 | curl_slist* chunk = nullptr; |
42 | for (const std::pair<const std::string, std::string>& item : header_) { |
43 | std::string = item.first; |
44 | if (item.second.empty()) { |
45 | header_string += ";" ; |
46 | } else { |
47 | header_string += ": " + item.second; |
48 | } |
49 | |
50 | curl_slist* temp = curl_slist_append(list: chunk, data: header_string.c_str()); |
51 | if (temp) { |
52 | chunk = temp; |
53 | } |
54 | } |
55 | |
56 | // Set the chunked transfer encoding in case it does not already exist: |
57 | if (chunkedTransferEncoding_ && header_.find(x: "Transfer-Encoding" ) == header_.end()) { |
58 | curl_slist* temp = curl_slist_append(list: chunk, data: "Transfer-Encoding:chunked" ); |
59 | if (temp) { |
60 | chunk = temp; |
61 | } |
62 | } |
63 | |
64 | // libcurl would prepare the header "Expect: 100-continue" by default when uploading files larger than 1 MB. |
65 | // Here we would like to disable this feature: |
66 | curl_slist* temp = curl_slist_append(list: chunk, data: "Expect:" ); |
67 | if (temp) { |
68 | chunk = temp; |
69 | } |
70 | |
71 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPHEADER, chunk); |
72 | |
73 | curl_slist_free_all(list: curl_->chunk); |
74 | curl_->chunk = chunk; |
75 | } |
76 | |
77 | // Only supported with libcurl >= 7.61.0. |
78 | // As an alternative use SetHeader and add the token manually. |
79 | #if LIBCURL_VERSION_NUM >= 0x073D00 |
80 | void Session::SetBearer(const Bearer& token) { |
81 | // Ignore here since this has been defined by libcurl. |
82 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER); |
83 | curl_easy_setopt(curl_->handle, CURLOPT_XOAUTH2_BEARER, token.GetToken()); |
84 | } |
85 | #endif |
86 | |
87 | Session::Session() : curl_(new CurlHolder()) { |
88 | // Set up some sensible defaults |
89 | curl_version_info_data* version_info = curl_version_info(CURLVERSION_NOW); |
90 | const std::string version = "curl/" + std::string{version_info->version}; |
91 | curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, version.c_str()); |
92 | SetRedirect(Redirect()); |
93 | curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 1L); |
94 | curl_easy_setopt(curl_->handle, CURLOPT_ERRORBUFFER, curl_->error.data()); |
95 | curl_easy_setopt(curl_->handle, CURLOPT_COOKIEFILE, "" ); |
96 | #ifdef CPR_CURL_NOSIGNAL |
97 | curl_easy_setopt(curl_->handle, CURLOPT_NOSIGNAL, 1L); |
98 | #endif |
99 | |
100 | #if LIBCURL_VERSION_NUM >= 0x071900 |
101 | curl_easy_setopt(curl_->handle, CURLOPT_TCP_KEEPALIVE, 1L); |
102 | #endif |
103 | } |
104 | |
105 | Response Session::makeDownloadRequest() { |
106 | if (!interceptors_.empty()) { |
107 | return intercept(); |
108 | } |
109 | |
110 | const CURLcode curl_error = DoEasyPerform(); |
111 | |
112 | return CompleteDownload(curl_error); |
113 | } |
114 | |
115 | void Session::prepareCommon() { |
116 | assert(curl_->handle); |
117 | |
118 | // Set Header: |
119 | SetHeaderInternal(); |
120 | |
121 | const std::string parametersContent = parameters_.GetContent(*curl_); |
122 | if (!parametersContent.empty()) { |
123 | const Url new_url{url_ + "?" + parametersContent}; |
124 | curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str()); |
125 | } else { |
126 | curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str()); |
127 | } |
128 | |
129 | // Proxy: |
130 | const std::string protocol = url_.str().substr(pos: 0, n: url_.str().find(c: ':')); |
131 | if (proxies_.has(protocol)) { |
132 | curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str()); |
133 | if (proxyAuth_.has(protocol)) { |
134 | curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); |
135 | curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]); |
136 | } |
137 | } |
138 | |
139 | #if LIBCURL_VERSION_NUM >= 0x072100 |
140 | if (acceptEncoding_.empty()) { |
141 | // Enable all supported built-in compressions |
142 | curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "" ); |
143 | } else if (acceptEncoding_.disabled()) { |
144 | // Disable curl adding the 'Accept-Encoding' header |
145 | curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, nullptr); |
146 | } else { |
147 | curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, acceptEncoding_.getString().c_str()); |
148 | } |
149 | #endif |
150 | |
151 | #if LIBCURL_VERSION_NUM >= 0x077100 |
152 | #if SUPPORT_SSL_NO_REVOKE |
153 | // NOLINTNEXTLINE (google-runtime-int) |
154 | long bitmask{0}; |
155 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, &bitmask); |
156 | const bool noRevoke = bitmask & CURLSSLOPT_NO_REVOKE; |
157 | #endif |
158 | |
159 | // Fix loading certs from Windows cert store when using OpenSSL: |
160 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA); |
161 | |
162 | // Ensure SSL no revoke is still set |
163 | #if SUPPORT_SSL_NO_REVOKE |
164 | if (noRevoke) { |
165 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); |
166 | } |
167 | #endif |
168 | #endif |
169 | |
170 | curl_->error[0] = '\0'; |
171 | |
172 | response_string_.clear(); |
173 | if (response_string_reserve_size_ > 0) { |
174 | response_string_.reserve(res_arg: response_string_reserve_size_); |
175 | } |
176 | header_string_.clear(); |
177 | if (!this->writecb_.callback) { |
178 | curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction); |
179 | curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &response_string_); |
180 | } |
181 | if (!this->headercb_.callback) { |
182 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction); |
183 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_); |
184 | } |
185 | |
186 | // Enable so we are able to retrive certificate information: |
187 | curl_easy_setopt(curl_->handle, CURLOPT_CERTINFO, 1L); |
188 | } |
189 | |
190 | void Session::prepareCommonDownload() { |
191 | assert(curl_->handle); |
192 | |
193 | // Set Header: |
194 | SetHeaderInternal(); |
195 | |
196 | const std::string parametersContent = parameters_.GetContent(*curl_); |
197 | if (!parametersContent.empty()) { |
198 | const Url new_url{url_ + "?" + parametersContent}; |
199 | curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str()); |
200 | } else { |
201 | curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str()); |
202 | } |
203 | |
204 | const std::string protocol = url_.str().substr(pos: 0, n: url_.str().find(c: ':')); |
205 | if (proxies_.has(protocol)) { |
206 | curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str()); |
207 | if (proxyAuth_.has(protocol)) { |
208 | curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); |
209 | curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]); |
210 | } |
211 | } |
212 | |
213 | curl_->error[0] = '\0'; |
214 | |
215 | header_string_.clear(); |
216 | if (headercb_.callback) { |
217 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction); |
218 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_); |
219 | } else { |
220 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction); |
221 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_); |
222 | } |
223 | } |
224 | |
225 | Response Session::makeRequest() { |
226 | if (!interceptors_.empty()) { |
227 | return intercept(); |
228 | } |
229 | |
230 | const CURLcode curl_error = DoEasyPerform(); |
231 | return Complete(curl_error); |
232 | } |
233 | |
234 | void Session::SetLimitRate(const LimitRate& limit_rate) { |
235 | curl_easy_setopt(curl_->handle, CURLOPT_MAX_RECV_SPEED_LARGE, limit_rate.downrate); |
236 | curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate); |
237 | } |
238 | |
239 | void Session::SetReadCallback(const ReadCallback& read) { |
240 | readcb_ = read; |
241 | curl_easy_setopt(curl_->handle, CURLOPT_INFILESIZE_LARGE, read.size); |
242 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, read.size); |
243 | curl_easy_setopt(curl_->handle, CURLOPT_READFUNCTION, cpr::util::readUserFunction); |
244 | curl_easy_setopt(curl_->handle, CURLOPT_READDATA, &readcb_); |
245 | chunkedTransferEncoding_ = read.size == -1; |
246 | } |
247 | |
248 | void Session::(const HeaderCallback& ) { |
249 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction); |
250 | headercb_ = header; |
251 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_); |
252 | } |
253 | |
254 | void Session::SetWriteCallback(const WriteCallback& write) { |
255 | curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeUserFunction); |
256 | writecb_ = write; |
257 | curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &writecb_); |
258 | } |
259 | |
260 | void Session::SetProgressCallback(const ProgressCallback& progress) { |
261 | progresscb_ = progress; |
262 | if (isCancellable) { |
263 | cancellationcb_.SetProgressCallback(progresscb_); |
264 | return; |
265 | } |
266 | #if LIBCURL_VERSION_NUM < 0x072000 |
267 | curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction<ProgressCallback>); |
268 | curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &progresscb_); |
269 | #else |
270 | curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction<ProgressCallback>); |
271 | curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &progresscb_); |
272 | #endif |
273 | curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L); |
274 | } |
275 | |
276 | void Session::SetDebugCallback(const DebugCallback& debug) { |
277 | curl_easy_setopt(curl_->handle, CURLOPT_DEBUGFUNCTION, cpr::util::debugUserFunction); |
278 | debugcb_ = debug; |
279 | curl_easy_setopt(curl_->handle, CURLOPT_DEBUGDATA, &debugcb_); |
280 | curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L); |
281 | } |
282 | |
283 | void Session::SetUrl(const Url& url) { |
284 | url_ = url; |
285 | } |
286 | |
287 | void Session::SetResolve(const Resolve& resolve) { |
288 | SetResolves({resolve}); |
289 | } |
290 | |
291 | void Session::SetResolves(const std::vector<Resolve>& resolves) { |
292 | curl_slist_free_all(list: curl_->resolveCurlList); |
293 | curl_->resolveCurlList = nullptr; |
294 | for (const Resolve& resolve : resolves) { |
295 | for (const uint16_t port : resolve.ports) { |
296 | curl_->resolveCurlList = curl_slist_append(list: curl_->resolveCurlList, data: (resolve.host + ":" + std::to_string(val: port) + ":" + resolve.addr).c_str()); |
297 | } |
298 | } |
299 | curl_easy_setopt(curl_->handle, CURLOPT_RESOLVE, curl_->resolveCurlList); |
300 | } |
301 | |
302 | void Session::SetParameters(const Parameters& parameters) { |
303 | parameters_ = parameters; |
304 | } |
305 | |
306 | void Session::SetParameters(Parameters&& parameters) { |
307 | parameters_ = std::move(parameters); |
308 | } |
309 | |
310 | void Session::(const Header& ) { |
311 | header_ = header; |
312 | } |
313 | |
314 | void Session::(const Header& ) { |
315 | for (const std::pair<const std::string, std::string>& item : header) { |
316 | header_[item.first] = item.second; |
317 | } |
318 | } |
319 | |
320 | void Session::SetTimeout(const Timeout& timeout) { |
321 | curl_easy_setopt(curl_->handle, CURLOPT_TIMEOUT_MS, timeout.Milliseconds()); |
322 | } |
323 | |
324 | void Session::SetConnectTimeout(const ConnectTimeout& timeout) { |
325 | curl_easy_setopt(curl_->handle, CURLOPT_CONNECTTIMEOUT_MS, timeout.Milliseconds()); |
326 | } |
327 | |
328 | void Session::SetAuth(const Authentication& auth) { |
329 | // Ignore here since this has been defined by libcurl. |
330 | switch (auth.GetAuthMode()) { |
331 | case AuthMode::BASIC: |
332 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); |
333 | curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); |
334 | break; |
335 | case AuthMode::DIGEST: |
336 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); |
337 | curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); |
338 | break; |
339 | case AuthMode::NTLM: |
340 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM); |
341 | curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString()); |
342 | break; |
343 | } |
344 | } |
345 | |
346 | void Session::SetUserAgent(const UserAgent& ua) { |
347 | curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, ua.c_str()); |
348 | } |
349 | |
350 | void Session::SetPayload(const Payload& payload) { |
351 | hasBodyOrPayload_ = true; |
352 | const std::string content = payload.GetContent(*curl_); |
353 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length())); |
354 | curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str()); |
355 | } |
356 | |
357 | void Session::SetPayload(Payload&& payload) { |
358 | hasBodyOrPayload_ = true; |
359 | const std::string content = payload.GetContent(*curl_); |
360 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length())); |
361 | curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str()); |
362 | } |
363 | |
364 | void Session::SetProxies(const Proxies& proxies) { |
365 | proxies_ = proxies; |
366 | } |
367 | |
368 | void Session::SetProxies(Proxies&& proxies) { |
369 | proxies_ = std::move(proxies); |
370 | } |
371 | |
372 | void Session::SetProxyAuth(ProxyAuthentication&& proxy_auth) { |
373 | proxyAuth_ = std::move(proxy_auth); |
374 | } |
375 | |
376 | void Session::SetProxyAuth(const ProxyAuthentication& proxy_auth) { |
377 | proxyAuth_ = proxy_auth; |
378 | } |
379 | |
380 | void Session::SetMultipart(const Multipart& multipart) { |
381 | // Make sure, we have a empty multipart to start with: |
382 | if (curl_->multipart) { |
383 | curl_mime_free(mime: curl_->multipart); |
384 | } |
385 | curl_->multipart = curl_mime_init(easy: curl_->handle); |
386 | |
387 | // Add all multipart pieces: |
388 | for (const Part& part : multipart.parts) { |
389 | if (part.is_file) { |
390 | for (const File& file : part.files) { |
391 | curl_mimepart* mimePart = curl_mime_addpart(mime: curl_->multipart); |
392 | if (!part.content_type.empty()) { |
393 | curl_mime_type(part: mimePart, mimetype: part.content_type.c_str()); |
394 | } |
395 | |
396 | curl_mime_filedata(part: mimePart, filename: file.filepath.c_str()); |
397 | curl_mime_name(part: mimePart, name: part.name.c_str()); |
398 | |
399 | if (file.hasOverridenFilename()) { |
400 | curl_mime_filename(part: mimePart, filename: file.overriden_filename.c_str()); |
401 | } |
402 | } |
403 | } else { |
404 | curl_mimepart* mimePart = curl_mime_addpart(mime: curl_->multipart); |
405 | if (!part.content_type.empty()) { |
406 | curl_mime_type(part: mimePart, mimetype: part.content_type.c_str()); |
407 | } |
408 | if (part.is_buffer) { |
409 | // Do not use formdata, to prevent having to use reinterpreter_cast: |
410 | curl_mime_name(part: mimePart, name: part.name.c_str()); |
411 | curl_mime_data(part: mimePart, data: part.data, datasize: part.datalen); |
412 | curl_mime_filename(part: mimePart, filename: part.value.c_str()); |
413 | } else { |
414 | curl_mime_name(part: mimePart, name: part.name.c_str()); |
415 | curl_mime_data(part: mimePart, data: part.value.c_str(), CURL_ZERO_TERMINATED); |
416 | } |
417 | } |
418 | } |
419 | |
420 | curl_easy_setopt(curl_->handle, CURLOPT_MIMEPOST, curl_->multipart); |
421 | hasBodyOrPayload_ = true; |
422 | } |
423 | |
424 | void Session::SetMultipart(Multipart&& multipart) { |
425 | SetMultipart(multipart); |
426 | } |
427 | |
428 | void Session::SetRedirect(const Redirect& redirect) { |
429 | curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, redirect.follow ? 1L : 0L); |
430 | curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, redirect.maximum); |
431 | curl_easy_setopt(curl_->handle, CURLOPT_UNRESTRICTED_AUTH, redirect.cont_send_cred ? 1L : 0L); |
432 | |
433 | // NOLINTNEXTLINE (google-runtime-int) |
434 | long mask = 0; |
435 | if (any(flag: redirect.post_flags & PostRedirectFlags::POST_301)) { |
436 | mask |= CURL_REDIR_POST_301; |
437 | } |
438 | if (any(flag: redirect.post_flags & PostRedirectFlags::POST_302)) { |
439 | mask |= CURL_REDIR_POST_302; |
440 | } |
441 | if (any(flag: redirect.post_flags & PostRedirectFlags::POST_303)) { |
442 | mask |= CURL_REDIR_POST_303; |
443 | } |
444 | curl_easy_setopt(curl_->handle, CURLOPT_POSTREDIR, mask); |
445 | } |
446 | |
447 | void Session::SetCookies(const Cookies& cookies) { |
448 | curl_easy_setopt(curl_->handle, CURLOPT_COOKIELIST, "ALL" ); |
449 | curl_easy_setopt(curl_->handle, CURLOPT_COOKIE, cookies.GetEncoded(*curl_).c_str()); |
450 | } |
451 | |
452 | void Session::SetBody(const Body& body) { |
453 | hasBodyOrPayload_ = true; |
454 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length())); |
455 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, body.c_str()); |
456 | } |
457 | |
458 | void Session::SetBody(Body&& body) { |
459 | hasBodyOrPayload_ = true; |
460 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length())); |
461 | curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, body.c_str()); |
462 | } |
463 | |
464 | void Session::SetLowSpeed(const LowSpeed& low_speed) { |
465 | curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_LIMIT, low_speed.limit); |
466 | curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_TIME, low_speed.time); |
467 | } |
468 | |
469 | void Session::SetVerifySsl(const VerifySsl& verify) { |
470 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, verify ? ON : OFF); |
471 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L); |
472 | } |
473 | |
474 | void Session::SetUnixSocket(const UnixSocket& unix_socket) { |
475 | curl_easy_setopt(curl_->handle, CURLOPT_UNIX_SOCKET_PATH, unix_socket.GetUnixSocketString()); |
476 | } |
477 | |
478 | void Session::SetSslOptions(const SslOptions& options) { |
479 | if (!options.cert_file.empty()) { |
480 | curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT, options.cert_file.c_str()); |
481 | if (!options.cert_type.empty()) { |
482 | curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str()); |
483 | } |
484 | } |
485 | if (!options.key_file.empty()) { |
486 | curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY, options.key_file.c_str()); |
487 | if (!options.key_type.empty()) { |
488 | curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str()); |
489 | } |
490 | if (!options.key_pass.empty()) { |
491 | curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str()); |
492 | } |
493 | #if SUPPORT_CURLOPT_SSLKEY_BLOB |
494 | } else if (!options.key_blob.empty()) { |
495 | std::string key_blob(options.key_blob); |
496 | curl_blob blob{}; |
497 | // NOLINTNEXTLINE (readability-container-data-pointer) |
498 | blob.data = &key_blob[0]; |
499 | blob.len = key_blob.length(); |
500 | curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY_BLOB, &blob); |
501 | if (!options.key_type.empty()) { |
502 | curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str()); |
503 | } |
504 | if (!options.key_pass.empty()) { |
505 | curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str()); |
506 | } |
507 | #endif |
508 | } |
509 | if (!options.pinned_public_key.empty()) { |
510 | curl_easy_setopt(curl_->handle, CURLOPT_PINNEDPUBLICKEY, options.pinned_public_key.c_str()); |
511 | } |
512 | #if SUPPORT_ALPN |
513 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_ALPN, options.enable_alpn ? ON : OFF); |
514 | #endif |
515 | #if SUPPORT_NPN |
516 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_NPN, options.enable_npn ? ON : OFF); |
517 | #endif |
518 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, options.verify_peer ? ON : OFF); |
519 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, options.verify_host ? 2L : 0L); |
520 | #if LIBCURL_VERSION_NUM >= 0x072900 |
521 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYSTATUS, options.verify_status ? ON : OFF); |
522 | #endif |
523 | |
524 | int maxTlsVersion = options.ssl_version; |
525 | #if SUPPORT_MAX_TLS_VERSION |
526 | maxTlsVersion |= options.max_version; |
527 | #endif |
528 | |
529 | curl_easy_setopt(curl_->handle, CURLOPT_SSLVERSION, |
530 | // Ignore here since this has been defined by libcurl. |
531 | maxTlsVersion); |
532 | #if SUPPORT_SSL_NO_REVOKE |
533 | if (options.ssl_no_revoke) { |
534 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE); |
535 | } |
536 | #endif |
537 | if (!options.ca_info.empty()) { |
538 | curl_easy_setopt(curl_->handle, CURLOPT_CAINFO, options.ca_info.c_str()); |
539 | } |
540 | if (!options.ca_path.empty()) { |
541 | curl_easy_setopt(curl_->handle, CURLOPT_CAPATH, options.ca_path.c_str()); |
542 | } |
543 | #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION |
544 | #ifdef OPENSSL_BACKEND_USED |
545 | if (!options.ca_buffer.empty()) { |
546 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function_load_ca_cert_from_buffer); |
547 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, options.ca_buffer.c_str()); |
548 | } |
549 | #endif |
550 | #endif |
551 | if (!options.crl_file.empty()) { |
552 | curl_easy_setopt(curl_->handle, CURLOPT_CRLFILE, options.crl_file.c_str()); |
553 | } |
554 | if (!options.ciphers.empty()) { |
555 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_CIPHER_LIST, options.ciphers.c_str()); |
556 | } |
557 | #if SUPPORT_TLSv13_CIPHERS |
558 | if (!options.tls13_ciphers.empty()) { |
559 | curl_easy_setopt(curl_->handle, CURLOPT_TLS13_CIPHERS, options.ciphers.c_str()); |
560 | } |
561 | #endif |
562 | #if SUPPORT_SESSIONID_CACHE |
563 | curl_easy_setopt(curl_->handle, CURLOPT_SSL_SESSIONID_CACHE, options.session_id_cache ? ON : OFF); |
564 | #endif |
565 | } |
566 | |
567 | void Session::SetVerbose(const Verbose& verbose) { |
568 | curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, verbose.verbose ? ON : OFF); |
569 | } |
570 | |
571 | void Session::SetInterface(const Interface& iface) { |
572 | if (iface.str().empty()) { |
573 | curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, nullptr); |
574 | } else { |
575 | curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, iface.c_str()); |
576 | } |
577 | } |
578 | |
579 | void Session::SetLocalPort(const LocalPort& local_port) { |
580 | curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORT, local_port); |
581 | } |
582 | |
583 | void Session::SetLocalPortRange(const LocalPortRange& local_port_range) { |
584 | curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORTRANGE, local_port_range); |
585 | } |
586 | |
587 | void Session::SetHttpVersion(const HttpVersion& version) { |
588 | switch (version.code) { |
589 | case HttpVersionCode::VERSION_NONE: |
590 | curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE); |
591 | break; |
592 | |
593 | case HttpVersionCode::VERSION_1_0: |
594 | curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); |
595 | break; |
596 | |
597 | case HttpVersionCode::VERSION_1_1: |
598 | curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); |
599 | break; |
600 | |
601 | #if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0 |
602 | case HttpVersionCode::VERSION_2_0: |
603 | curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); |
604 | break; |
605 | #endif |
606 | |
607 | #if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0 |
608 | case HttpVersionCode::VERSION_2_0_TLS: |
609 | curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); |
610 | break; |
611 | #endif |
612 | |
613 | #if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0 |
614 | case HttpVersionCode::VERSION_2_0_PRIOR_KNOWLEDGE: |
615 | curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); |
616 | break; |
617 | #endif |
618 | |
619 | #if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0 |
620 | case HttpVersionCode::VERSION_3_0: |
621 | curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3); |
622 | break; |
623 | #endif |
624 | |
625 | default: // Should not happen |
626 | throw std::invalid_argument("Invalid/Unknown HTTP version type." ); |
627 | break; |
628 | } |
629 | } |
630 | |
631 | void Session::SetRange(const Range& range) { |
632 | const std::string range_str = range.str(); |
633 | curl_easy_setopt(curl_->handle, CURLOPT_RANGE, range_str.c_str()); |
634 | } |
635 | |
636 | void Session::SetMultiRange(const MultiRange& multi_range) { |
637 | const std::string multi_range_str = multi_range.str(); |
638 | curl_easy_setopt(curl_->handle, CURLOPT_RANGE, multi_range_str.c_str()); |
639 | } |
640 | |
641 | void Session::SetReserveSize(const ReserveSize& reserve_size) { |
642 | ResponseStringReserve(size: reserve_size.size); |
643 | } |
644 | |
645 | void Session::SetAcceptEncoding(const AcceptEncoding& accept_encoding) { |
646 | acceptEncoding_ = accept_encoding; |
647 | } |
648 | |
649 | void Session::SetAcceptEncoding(AcceptEncoding&& accept_encoding) { |
650 | acceptEncoding_ = std::move(accept_encoding); |
651 | } |
652 | |
653 | cpr_off_t Session::GetDownloadFileLength() { |
654 | cpr_off_t downloadFileLenth = -1; |
655 | curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str()); |
656 | |
657 | const std::string protocol = url_.str().substr(pos: 0, n: url_.str().find(c: ':')); |
658 | if (proxies_.has(protocol)) { |
659 | curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str()); |
660 | if (proxyAuth_.has(protocol)) { |
661 | curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY); |
662 | curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]); |
663 | } |
664 | } |
665 | |
666 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1); |
667 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1); |
668 | if (DoEasyPerform() == CURLE_OK) { |
669 | // NOLINTNEXTLINE (google-runtime-int) |
670 | long status_code{}; |
671 | curl_easy_getinfo(curl_->handle, CURLINFO_RESPONSE_CODE, &status_code); |
672 | if (200 == status_code) { |
673 | curl_easy_getinfo(curl_->handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &downloadFileLenth); |
674 | } |
675 | } |
676 | return downloadFileLenth; |
677 | } |
678 | |
679 | void Session::ResponseStringReserve(size_t size) { |
680 | response_string_reserve_size_ = size; |
681 | } |
682 | |
683 | Response Session::Delete() { |
684 | PrepareDelete(); |
685 | return makeRequest(); |
686 | } |
687 | |
688 | Response Session::Download(const WriteCallback& write) { |
689 | PrepareDownload(write); |
690 | return makeDownloadRequest(); |
691 | } |
692 | |
693 | Response Session::Download(std::ofstream& file) { |
694 | PrepareDownload(file); |
695 | return makeDownloadRequest(); |
696 | } |
697 | |
698 | Response Session::Get() { |
699 | PrepareGet(); |
700 | return makeRequest(); |
701 | } |
702 | |
703 | Response Session::Head() { |
704 | PrepareHead(); |
705 | return makeRequest(); |
706 | } |
707 | |
708 | Response Session::Options() { |
709 | PrepareOptions(); |
710 | return makeRequest(); |
711 | } |
712 | |
713 | Response Session::Patch() { |
714 | PreparePatch(); |
715 | return makeRequest(); |
716 | } |
717 | |
718 | Response Session::Post() { |
719 | PreparePost(); |
720 | return makeRequest(); |
721 | } |
722 | |
723 | Response Session::Put() { |
724 | PreparePut(); |
725 | return makeRequest(); |
726 | } |
727 | |
728 | std::shared_ptr<Session> Session::GetSharedPtrFromThis() { |
729 | try { |
730 | return shared_from_this(); |
731 | } catch (std::bad_weak_ptr&) { |
732 | throw std::runtime_error("Failed to get a shared pointer from this. The reason is probably that the session object is not managed by a shared pointer, which is required to use this functionality." ); |
733 | } |
734 | } |
735 | |
736 | AsyncResponse Session::GetAsync() { |
737 | auto shared_this = shared_from_this(); |
738 | return async(fn: [shared_this]() { return shared_this->Get(); }); |
739 | } |
740 | |
741 | AsyncResponse Session::DeleteAsync() { |
742 | return async(fn: [shared_this = GetSharedPtrFromThis()]() { return shared_this->Delete(); }); |
743 | } |
744 | |
745 | AsyncResponse Session::DownloadAsync(const WriteCallback& write) { |
746 | return async(fn: [shared_this = GetSharedPtrFromThis(), write]() { return shared_this->Download(write); }); |
747 | } |
748 | |
749 | AsyncResponse Session::DownloadAsync(std::ofstream& file) { |
750 | return async(fn: [shared_this = GetSharedPtrFromThis(), &file]() { return shared_this->Download(file); }); |
751 | } |
752 | |
753 | AsyncResponse Session::HeadAsync() { |
754 | return async(fn: [shared_this = GetSharedPtrFromThis()]() { return shared_this->Head(); }); |
755 | } |
756 | |
757 | AsyncResponse Session::OptionsAsync() { |
758 | return async(fn: [shared_this = GetSharedPtrFromThis()]() { return shared_this->Options(); }); |
759 | } |
760 | |
761 | AsyncResponse Session::PatchAsync() { |
762 | return async(fn: [shared_this = GetSharedPtrFromThis()]() { return shared_this->Patch(); }); |
763 | } |
764 | |
765 | AsyncResponse Session::PostAsync() { |
766 | return async(fn: [shared_this = GetSharedPtrFromThis()]() { return shared_this->Post(); }); |
767 | } |
768 | |
769 | AsyncResponse Session::PutAsync() { |
770 | return async(fn: [shared_this = GetSharedPtrFromThis()]() { return shared_this->Put(); }); |
771 | } |
772 | |
773 | std::shared_ptr<CurlHolder> Session::GetCurlHolder() { |
774 | return curl_; |
775 | } |
776 | |
777 | std::string Session::GetFullRequestUrl() { |
778 | const std::string parametersContent = parameters_.GetContent(*curl_); |
779 | return url_.str() + (parametersContent.empty() ? "" : "?" ) + parametersContent; |
780 | } |
781 | |
782 | void Session::PrepareDelete() { |
783 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L); |
784 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
785 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "DELETE" ); |
786 | prepareCommon(); |
787 | } |
788 | |
789 | void Session::PrepareGet() { |
790 | // In case there is a body or payload for this request, we create a custom GET-Request since a |
791 | // GET-Request with body is based on the HTTP RFC **not** a leagal request. |
792 | if (hasBodyOrPayload_) { |
793 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
794 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET" ); |
795 | } else { |
796 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
797 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); |
798 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1L); |
799 | } |
800 | prepareCommon(); |
801 | } |
802 | |
803 | void Session::PrepareHead() { |
804 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1L); |
805 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); |
806 | prepareCommon(); |
807 | } |
808 | |
809 | void Session::PrepareOptions() { |
810 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
811 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "OPTIONS" ); |
812 | prepareCommon(); |
813 | } |
814 | |
815 | void Session::PreparePatch() { |
816 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
817 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PATCH" ); |
818 | prepareCommon(); |
819 | } |
820 | |
821 | void Session::PreparePost() { |
822 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
823 | |
824 | // In case there is no body or payload set it to an empty post: |
825 | if (hasBodyOrPayload_) { |
826 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); |
827 | } else { |
828 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, readcb_.callback ? nullptr : "" ); |
829 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "POST" ); |
830 | } |
831 | prepareCommon(); |
832 | } |
833 | |
834 | void Session::PreparePut() { |
835 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
836 | if (!hasBodyOrPayload_ && readcb_.callback) { |
837 | /** |
838 | * Yes, this one has to be CURLOPT_POSTFIELDS even if we are performing a PUT request. |
839 | * In case we don't set this one, performing a POST-request with PUT won't work. |
840 | * It in theory this only enforces the usage of the readcallback for POST requests, but works here as well. |
841 | **/ |
842 | curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, nullptr); |
843 | } |
844 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PUT" ); |
845 | curl_easy_setopt(curl_->handle, CURLOPT_RANGE, nullptr); |
846 | prepareCommon(); |
847 | } |
848 | |
849 | void Session::PrepareDownload(std::ofstream& file) { |
850 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
851 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1); |
852 | curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFileFunction); |
853 | curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &file); |
854 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); |
855 | |
856 | prepareCommonDownload(); |
857 | } |
858 | |
859 | void Session::PrepareDownload(const WriteCallback& write) { |
860 | curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L); |
861 | curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1); |
862 | curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr); |
863 | |
864 | SetWriteCallback(write); |
865 | |
866 | prepareCommonDownload(); |
867 | } |
868 | |
869 | Response Session::Complete(CURLcode curl_error) { |
870 | curl_slist* raw_cookies{nullptr}; |
871 | curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies); |
872 | Cookies cookies = util::parseCookies(raw_cookies); |
873 | curl_slist_free_all(list: raw_cookies); |
874 | |
875 | // Reset the has no body property: |
876 | hasBodyOrPayload_ = false; |
877 | |
878 | std::string errorMsg = curl_->error.data(); |
879 | return Response(curl_, std::move(response_string_), std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg))); |
880 | } |
881 | |
882 | Response Session::CompleteDownload(CURLcode curl_error) { |
883 | if (!headercb_.callback) { |
884 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, nullptr); |
885 | curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, 0); |
886 | } |
887 | |
888 | curl_slist* raw_cookies{nullptr}; |
889 | curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies); |
890 | Cookies cookies = util::parseCookies(raw_cookies); |
891 | curl_slist_free_all(list: raw_cookies); |
892 | std::string errorMsg = curl_->error.data(); |
893 | |
894 | return Response(curl_, "" , std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg))); |
895 | } |
896 | |
897 | void Session::AddInterceptor(const std::shared_ptr<Interceptor>& pinterceptor) { |
898 | interceptors_.push(x: pinterceptor); |
899 | } |
900 | |
901 | Response Session::proceed() { |
902 | prepareCommon(); |
903 | return makeRequest(); |
904 | } |
905 | |
906 | Response Session::intercept() { |
907 | // At least one interceptor exists -> Execute its intercept function |
908 | const std::shared_ptr<Interceptor> interceptor = interceptors_.front(); |
909 | interceptors_.pop(); |
910 | return interceptor->intercept(session&: *this); |
911 | } |
912 | |
913 | // clang-format off |
914 | void Session::SetOption(const Resolve& resolve) { SetResolve(resolve); } |
915 | void Session::SetOption(const std::vector<Resolve>& resolves) { SetResolves(resolves); } |
916 | void Session::SetOption(const ReadCallback& read) { SetReadCallback(read); } |
917 | void Session::(const HeaderCallback& ) { SetHeaderCallback(header); } |
918 | void Session::SetOption(const WriteCallback& write) { SetWriteCallback(write); } |
919 | void Session::SetOption(const ProgressCallback& progress) { SetProgressCallback(progress); } |
920 | void Session::SetOption(const DebugCallback& debug) { SetDebugCallback(debug); } |
921 | void Session::SetOption(const Url& url) { SetUrl(url); } |
922 | void Session::SetOption(const Parameters& parameters) { SetParameters(parameters); } |
923 | void Session::SetOption(Parameters&& parameters) { SetParameters(std::move(parameters)); } |
924 | void Session::SetOption(const Header& ) { SetHeader(header); } |
925 | void Session::SetOption(const Timeout& timeout) { SetTimeout(timeout); } |
926 | void Session::SetOption(const ConnectTimeout& timeout) { SetConnectTimeout(timeout); } |
927 | void Session::SetOption(const Authentication& auth) { SetAuth(auth); } |
928 | void Session::SetOption(const LimitRate& limit_rate) { SetLimitRate(limit_rate); } |
929 | // Only supported with libcurl >= 7.61.0. |
930 | // As an alternative use SetHeader and add the token manually. |
931 | #if LIBCURL_VERSION_NUM >= 0x073D00 |
932 | void Session::SetOption(const Bearer& auth) { SetBearer(auth); } |
933 | #endif |
934 | void Session::SetOption(const UserAgent& ua) { SetUserAgent(ua); } |
935 | void Session::SetOption(const Payload& payload) { SetPayload(payload); } |
936 | void Session::SetOption(Payload&& payload) { SetPayload(std::move(payload)); } |
937 | void Session::SetOption(const Proxies& proxies) { SetProxies(proxies); } |
938 | void Session::SetOption(Proxies&& proxies) { SetProxies(std::move(proxies)); } |
939 | void Session::SetOption(ProxyAuthentication&& proxy_auth) { SetProxyAuth(std::move(proxy_auth)); } |
940 | void Session::SetOption(const ProxyAuthentication& proxy_auth) { SetProxyAuth(proxy_auth); } |
941 | void Session::SetOption(const Multipart& multipart) { SetMultipart(multipart); } |
942 | void Session::SetOption(Multipart&& multipart) { SetMultipart(std::move(multipart)); } |
943 | void Session::SetOption(const Redirect& redirect) { SetRedirect(redirect); } |
944 | void Session::SetOption(const Cookies& cookies) { SetCookies(cookies); } |
945 | void Session::SetOption(const Body& body) { SetBody(body); } |
946 | void Session::SetOption(Body&& body) { SetBody(std::move(body)); } |
947 | void Session::SetOption(const LowSpeed& low_speed) { SetLowSpeed(low_speed); } |
948 | void Session::SetOption(const VerifySsl& verify) { SetVerifySsl(verify); } |
949 | void Session::SetOption(const Verbose& verbose) { SetVerbose(verbose); } |
950 | void Session::SetOption(const UnixSocket& unix_socket) { SetUnixSocket(unix_socket); } |
951 | void Session::SetOption(const SslOptions& options) { SetSslOptions(options); } |
952 | void Session::SetOption(const Interface& iface) { SetInterface(iface); } |
953 | void Session::SetOption(const LocalPort& local_port) { SetLocalPort(local_port); } |
954 | void Session::SetOption(const LocalPortRange& local_port_range) { SetLocalPortRange(local_port_range); } |
955 | void Session::SetOption(const HttpVersion& version) { SetHttpVersion(version); } |
956 | void Session::SetOption(const Range& range) { SetRange(range); } |
957 | void Session::SetOption(const MultiRange& multi_range) { SetMultiRange(multi_range); } |
958 | void Session::SetOption(const ReserveSize& reserve_size) { SetReserveSize(reserve_size.size); } |
959 | void Session::SetOption(const AcceptEncoding& accept_encoding) { SetAcceptEncoding(accept_encoding); } |
960 | void Session::SetOption(AcceptEncoding&& accept_encoding) { SetAcceptEncoding(accept_encoding); } |
961 | // clang-format on |
962 | |
963 | void Session::SetCancellationParam(std::shared_ptr<std::atomic_bool> param) { |
964 | cancellationcb_ = CancellationCallback{std::move(param)}; |
965 | isCancellable = true; |
966 | #if LIBCURL_VERSION_NUM < 0x072000 |
967 | curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction<CancellationCallback>); |
968 | curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &cancellationcb_); |
969 | #else |
970 | curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction<CancellationCallback>); |
971 | curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &cancellationcb_); |
972 | #endif |
973 | curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L); |
974 | } |
975 | } // namespace cpr |
976 | |