1
0

session.cpp 36 KB

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