123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964 |
- #include "cpr/session.h"
- #include <algorithm>
- #include <cstdlib>
- #include <cstring>
- #include <fstream>
- #include <functional>
- #include <iostream>
- #include <stdexcept>
- #include <string>
- #include <curl/curl.h>
- #include "cpr/async.h"
- #include "cpr/cprtypes.h"
- #include "cpr/interceptor.h"
- #include "cpr/util.h"
- #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
- #include "cpr/ssl_ctx.h"
- #endif
- namespace cpr {
- // Ignored here since libcurl reqires a long:
- // NOLINTNEXTLINE(google-runtime-int)
- constexpr long ON = 1L;
- // Ignored here since libcurl reqires a long:
- // NOLINTNEXTLINE(google-runtime-int)
- constexpr long OFF = 0L;
- CURLcode Session::DoEasyPerform() {
- if (isUsedInMultiPerform) {
- std::cerr << "curl_easy_perform cannot be executed if the CURL handle is used in a MultiPerform." << std::endl;
- return CURLcode::CURLE_FAILED_INIT;
- }
- return curl_easy_perform(curl_->handle);
- }
- void Session::SetHeaderInternal() {
- curl_slist* chunk = nullptr;
- for (const std::pair<const std::string, std::string>& item : header_) {
- std::string header_string = item.first;
- if (item.second.empty()) {
- header_string += ";";
- } else {
- header_string += ": " + item.second;
- }
- curl_slist* temp = curl_slist_append(chunk, header_string.c_str());
- if (temp) {
- chunk = temp;
- }
- }
- // Set the chunked transfer encoding in case it does not already exist:
- if (chunkedTransferEncoding_ && header_.find("Transfer-Encoding") == header_.end()) {
- curl_slist* temp = curl_slist_append(chunk, "Transfer-Encoding:chunked");
- if (temp) {
- chunk = temp;
- }
- }
- // libcurl would prepare the header "Expect: 100-continue" by default when uploading files larger than 1 MB.
- // Here we would like to disable this feature:
- curl_slist* temp = curl_slist_append(chunk, "Expect:");
- if (temp) {
- chunk = temp;
- }
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPHEADER, chunk);
- curl_slist_free_all(curl_->chunk);
- curl_->chunk = chunk;
- }
- // Only supported with libcurl >= 7.61.0.
- // As an alternative use SetHeader and add the token manually.
- #if LIBCURL_VERSION_NUM >= 0x073D00
- void Session::SetBearer(const Bearer& token) {
- // Ignore here since this has been defined by libcurl.
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
- curl_easy_setopt(curl_->handle, CURLOPT_XOAUTH2_BEARER, token.GetToken());
- }
- #endif
- Session::Session() : curl_(new CurlHolder()) {
- // Set up some sensible defaults
- curl_version_info_data* version_info = curl_version_info(CURLVERSION_NOW);
- std::string version = "curl/" + std::string{version_info->version};
- curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, version.c_str());
- SetRedirect(Redirect());
- curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 1L);
- curl_easy_setopt(curl_->handle, CURLOPT_ERRORBUFFER, curl_->error.data());
- curl_easy_setopt(curl_->handle, CURLOPT_COOKIEFILE, "");
- #ifdef CPR_CURL_NOSIGNAL
- curl_easy_setopt(curl_->handle, CURLOPT_NOSIGNAL, 1L);
- #endif
- #if LIBCURL_VERSION_NUM >= 0x071900
- curl_easy_setopt(curl_->handle, CURLOPT_TCP_KEEPALIVE, 1L);
- #endif
- }
- Response Session::makeDownloadRequest() {
- if (!interceptors_.empty()) {
- std::shared_ptr<Interceptor> interceptor = interceptors_.front();
- interceptors_.pop();
- return interceptor->intercept(*this);
- }
- CURLcode curl_error = DoEasyPerform();
- return CompleteDownload(curl_error);
- }
- void Session::prepareCommon() {
- assert(curl_->handle);
- // Set Header:
- SetHeaderInternal();
- const std::string parametersContent = parameters_.GetContent(*curl_);
- if (!parametersContent.empty()) {
- Url new_url{url_ + "?" + parametersContent};
- curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str());
- } else {
- curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
- }
- // Proxy:
- std::string protocol = url_.str().substr(0, url_.str().find(':'));
- if (proxies_.has(protocol)) {
- curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
- if (proxyAuth_.has(protocol)) {
- curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
- curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
- }
- }
- #if LIBCURL_VERSION_MAJOR >= 7
- #if LIBCURL_VERSION_MINOR >= 21
- if (acceptEncoding_.empty()) {
- /* enable all supported built-in compressions */
- curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, "");
- } else {
- curl_easy_setopt(curl_->handle, CURLOPT_ACCEPT_ENCODING, acceptEncoding_.getString().c_str());
- }
- #endif
- #endif
- #if LIBCURL_VERSION_MAJOR >= 7
- #if LIBCURL_VERSION_MINOR >= 71
- // Fix loading certs from Windows cert store when using OpenSSL:
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
- #endif
- #endif
- curl_->error[0] = '\0';
- response_string_.clear();
- if (response_string_reserve_size_ > 0) {
- response_string_.reserve(response_string_reserve_size_);
- }
- header_string_.clear();
- if (!this->writecb_.callback) {
- curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &response_string_);
- }
- if (!this->headercb_.callback) {
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_);
- }
- // Enable so we are able to retrive certificate information:
- curl_easy_setopt(curl_->handle, CURLOPT_CERTINFO, 1L);
- }
- void Session::prepareCommonDownload() {
- assert(curl_->handle);
- // Set Header:
- SetHeaderInternal();
- const std::string parametersContent = parameters_.GetContent(*curl_);
- if (!parametersContent.empty()) {
- Url new_url{url_ + "?" + parametersContent};
- curl_easy_setopt(curl_->handle, CURLOPT_URL, new_url.c_str());
- } else {
- curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
- }
- std::string protocol = url_.str().substr(0, url_.str().find(':'));
- if (proxies_.has(protocol)) {
- curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
- if (proxyAuth_.has(protocol)) {
- curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
- curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
- }
- }
- curl_->error[0] = '\0';
- header_string_.clear();
- if (headercb_.callback) {
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_);
- } else {
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::writeFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &header_string_);
- }
- }
- Response Session::makeRequest() {
- if (!interceptors_.empty()) {
- // At least one interceptor exists -> Execute its intercept function
- std::shared_ptr<Interceptor> interceptor = interceptors_.front();
- interceptors_.pop();
- return interceptor->intercept(*this);
- }
- CURLcode curl_error = DoEasyPerform();
- return Complete(curl_error);
- }
- void Session::SetLimitRate(const LimitRate& limit_rate) {
- curl_easy_setopt(curl_->handle, CURLOPT_MAX_RECV_SPEED_LARGE, limit_rate.downrate);
- curl_easy_setopt(curl_->handle, CURLOPT_MAX_SEND_SPEED_LARGE, limit_rate.uprate);
- }
- void Session::SetReadCallback(const ReadCallback& read) {
- readcb_ = read;
- curl_easy_setopt(curl_->handle, CURLOPT_INFILESIZE_LARGE, read.size);
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, read.size);
- curl_easy_setopt(curl_->handle, CURLOPT_READFUNCTION, cpr::util::readUserFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_READDATA, &readcb_);
- chunkedTransferEncoding_ = read.size == -1;
- }
- void Session::SetHeaderCallback(const HeaderCallback& header) {
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, cpr::util::headerUserFunction);
- headercb_ = header;
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, &headercb_);
- }
- void Session::SetWriteCallback(const WriteCallback& write) {
- curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeUserFunction);
- writecb_ = write;
- curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &writecb_);
- }
- void Session::SetProgressCallback(const ProgressCallback& progress) {
- progresscb_ = progress;
- #if LIBCURL_VERSION_NUM < 0x072000
- curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSFUNCTION, cpr::util::progressUserFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_PROGRESSDATA, &progresscb_);
- #else
- curl_easy_setopt(curl_->handle, CURLOPT_XFERINFOFUNCTION, cpr::util::progressUserFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_XFERINFODATA, &progresscb_);
- #endif
- curl_easy_setopt(curl_->handle, CURLOPT_NOPROGRESS, 0L);
- }
- void Session::SetDebugCallback(const DebugCallback& debug) {
- curl_easy_setopt(curl_->handle, CURLOPT_DEBUGFUNCTION, cpr::util::debugUserFunction);
- debugcb_ = debug;
- curl_easy_setopt(curl_->handle, CURLOPT_DEBUGDATA, &debugcb_);
- curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, 1L);
- }
- void Session::SetUrl(const Url& url) {
- url_ = url;
- }
- void Session::SetResolve(const Resolve& resolve) {
- SetResolves({resolve});
- }
- void Session::SetResolves(const std::vector<Resolve>& resolves) {
- curl_slist_free_all(curl_->resolveCurlList);
- curl_->resolveCurlList = nullptr;
- for (const Resolve& resolve : resolves) {
- for (const uint16_t port : resolve.ports) {
- curl_->resolveCurlList = curl_slist_append(curl_->resolveCurlList, (resolve.host + ":" + std::to_string(port) + ":" + resolve.addr).c_str());
- }
- }
- curl_easy_setopt(curl_->handle, CURLOPT_RESOLVE, curl_->resolveCurlList);
- }
- void Session::SetParameters(const Parameters& parameters) {
- parameters_ = parameters;
- }
- void Session::SetParameters(Parameters&& parameters) {
- parameters_ = std::move(parameters);
- }
- void Session::SetHeader(const Header& header) {
- header_ = header;
- }
- void Session::UpdateHeader(const Header& header) {
- for (const std::pair<const std::string, std::string>& item : header) {
- header_[item.first] = item.second;
- }
- }
- void Session::SetTimeout(const Timeout& timeout) {
- curl_easy_setopt(curl_->handle, CURLOPT_TIMEOUT_MS, timeout.Milliseconds());
- }
- void Session::SetConnectTimeout(const ConnectTimeout& timeout) {
- curl_easy_setopt(curl_->handle, CURLOPT_CONNECTTIMEOUT_MS, timeout.Milliseconds());
- }
- void Session::SetAuth(const Authentication& auth) {
- // Ignore here since this has been defined by libcurl.
- switch (auth.GetAuthMode()) {
- case AuthMode::BASIC:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
- curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
- break;
- case AuthMode::DIGEST:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
- curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
- break;
- case AuthMode::NTLM:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
- curl_easy_setopt(curl_->handle, CURLOPT_USERPWD, auth.GetAuthString());
- break;
- }
- }
- void Session::SetUserAgent(const UserAgent& ua) {
- curl_easy_setopt(curl_->handle, CURLOPT_USERAGENT, ua.c_str());
- }
- void Session::SetPayload(const Payload& payload) {
- hasBodyOrPayload_ = true;
- const std::string content = payload.GetContent(*curl_);
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length()));
- curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str());
- }
- void Session::SetPayload(Payload&& payload) {
- hasBodyOrPayload_ = true;
- const std::string content = payload.GetContent(*curl_);
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(content.length()));
- curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, content.c_str());
- }
- void Session::SetProxies(const Proxies& proxies) {
- proxies_ = proxies;
- }
- void Session::SetProxies(Proxies&& proxies) {
- proxies_ = std::move(proxies);
- }
- void Session::SetProxyAuth(ProxyAuthentication&& proxy_auth) {
- proxyAuth_ = std::move(proxy_auth);
- }
- void Session::SetProxyAuth(const ProxyAuthentication& proxy_auth) {
- proxyAuth_ = proxy_auth;
- }
- void Session::SetMultipart(const Multipart& multipart) {
- curl_httppost* formpost = nullptr;
- curl_httppost* lastptr = nullptr;
- for (const Part& part : multipart.parts) {
- std::vector<curl_forms> formdata;
- if (!part.content_type.empty()) {
- formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()});
- }
- if (part.is_file) {
- for (const File& file : part.files) {
- formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
- formdata.push_back({CURLFORM_FILE, file.filepath.c_str()});
- if (file.hasOverridedFilename()) {
- formdata.push_back({CURLFORM_FILENAME, file.overrided_filename.c_str()});
- }
- formdata.push_back({CURLFORM_END, nullptr});
- curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
- formdata.clear();
- }
- } else if (part.is_buffer) {
- // Do not use formdata, to prevent having to use reinterpreter_cast:
- 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);
- } else {
- formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
- formdata.push_back({CURLFORM_COPYCONTENTS, part.value.c_str()});
- formdata.push_back({CURLFORM_END, nullptr});
- curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
- }
- }
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPPOST, formpost);
- hasBodyOrPayload_ = true;
- curl_formfree(curl_->formpost);
- curl_->formpost = formpost;
- }
- void Session::SetMultipart(Multipart&& multipart) {
- curl_httppost* formpost = nullptr;
- curl_httppost* lastptr = nullptr;
- for (const Part& part : multipart.parts) {
- std::vector<curl_forms> formdata;
- if (!part.content_type.empty()) {
- formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.c_str()});
- }
- if (part.is_file) {
- for (const File& file : part.files) {
- formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
- formdata.push_back({CURLFORM_FILE, file.filepath.c_str()});
- if (file.hasOverridedFilename()) {
- formdata.push_back({CURLFORM_FILENAME, file.overrided_filename.c_str()});
- }
- formdata.push_back({CURLFORM_END, nullptr});
- curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
- formdata.clear();
- }
- } else if (part.is_buffer) {
- // Do not use formdata, to prevent having to use reinterpreter_cast:
- 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);
- } else {
- formdata.push_back({CURLFORM_COPYNAME, part.name.c_str()});
- formdata.push_back({CURLFORM_COPYCONTENTS, part.value.c_str()});
- formdata.push_back({CURLFORM_END, nullptr});
- curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
- }
- }
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPPOST, formpost);
- hasBodyOrPayload_ = true;
- curl_formfree(curl_->formpost);
- curl_->formpost = formpost;
- }
- void Session::SetRedirect(const Redirect& redirect) {
- curl_easy_setopt(curl_->handle, CURLOPT_FOLLOWLOCATION, redirect.follow ? 1L : 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_MAXREDIRS, redirect.maximum);
- curl_easy_setopt(curl_->handle, CURLOPT_UNRESTRICTED_AUTH, redirect.cont_send_cred ? 1L : 0L);
- // NOLINTNEXTLINE (google-runtime-int)
- long mask = 0;
- if (any(redirect.post_flags & PostRedirectFlags::POST_301)) {
- mask |= CURL_REDIR_POST_301;
- }
- if (any(redirect.post_flags & PostRedirectFlags::POST_302)) {
- mask |= CURL_REDIR_POST_302;
- }
- if (any(redirect.post_flags & PostRedirectFlags::POST_303)) {
- mask |= CURL_REDIR_POST_303;
- }
- curl_easy_setopt(curl_->handle, CURLOPT_POSTREDIR, mask);
- }
- void Session::SetCookies(const Cookies& cookies) {
- curl_easy_setopt(curl_->handle, CURLOPT_COOKIELIST, "ALL");
- curl_easy_setopt(curl_->handle, CURLOPT_COOKIE, cookies.GetEncoded(*curl_).c_str());
- }
- void Session::SetBody(const Body& body) {
- hasBodyOrPayload_ = true;
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length()));
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, body.c_str());
- }
- void Session::SetBody(Body&& body) {
- hasBodyOrPayload_ = true;
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDSIZE_LARGE, static_cast<curl_off_t>(body.str().length()));
- curl_easy_setopt(curl_->handle, CURLOPT_COPYPOSTFIELDS, body.c_str());
- }
- void Session::SetLowSpeed(const LowSpeed& low_speed) {
- curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_LIMIT, low_speed.limit);
- curl_easy_setopt(curl_->handle, CURLOPT_LOW_SPEED_TIME, low_speed.time);
- }
- void Session::SetVerifySsl(const VerifySsl& verify) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, verify ? ON : OFF);
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L);
- }
- void Session::SetUnixSocket(const UnixSocket& unix_socket) {
- curl_easy_setopt(curl_->handle, CURLOPT_UNIX_SOCKET_PATH, unix_socket.GetUnixSocketString());
- }
- void Session::SetSslOptions(const SslOptions& options) {
- if (!options.cert_file.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSLCERT, options.cert_file.c_str());
- if (!options.cert_type.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSLCERTTYPE, options.cert_type.c_str());
- }
- }
- if (!options.key_file.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY, options.key_file.c_str());
- if (!options.key_type.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str());
- }
- if (!options.key_pass.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str());
- }
- #if SUPPORT_CURLOPT_SSLKEY_BLOB
- } else if (!options.key_blob.empty()) {
- std::string key_blob(options.key_blob);
- curl_blob blob{};
- // NOLINTNEXTLINE (readability-container-data-pointer)
- blob.data = &key_blob[0];
- blob.len = key_blob.length();
- curl_easy_setopt(curl_->handle, CURLOPT_SSLKEY_BLOB, &blob);
- if (!options.key_type.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSLKEYTYPE, options.key_type.c_str());
- }
- if (!options.key_pass.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_KEYPASSWD, options.key_pass.c_str());
- }
- #endif
- }
- if (!options.pinned_public_key.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_PINNEDPUBLICKEY, options.pinned_public_key.c_str());
- }
- #if SUPPORT_ALPN
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_ALPN, options.enable_alpn ? ON : OFF);
- #endif
- #if SUPPORT_NPN
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_ENABLE_NPN, options.enable_npn ? ON : OFF);
- #endif
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYPEER, options.verify_peer ? ON : OFF);
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYHOST, options.verify_host ? 2L : 0L);
- #if LIBCURL_VERSION_NUM >= 0x072900
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_VERIFYSTATUS, options.verify_status ? ON : OFF);
- #endif
- int maxTlsVersion = options.ssl_version;
- #if SUPPORT_MAX_TLS_VERSION
- maxTlsVersion |= options.max_version;
- #endif
- curl_easy_setopt(curl_->handle, CURLOPT_SSLVERSION,
- // Ignore here since this has been defined by libcurl.
- maxTlsVersion);
- #if SUPPORT_SSL_NO_REVOKE
- if (options.ssl_no_revoke) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
- }
- #endif
- if (!options.ca_info.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_CAINFO, options.ca_info.c_str());
- }
- if (!options.ca_path.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_CAPATH, options.ca_path.c_str());
- }
- #if SUPPORT_CURLOPT_SSL_CTX_FUNCTION
- #ifdef OPENSSL_BACKEND_USED
- if (!options.ca_buffer.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_FUNCTION, sslctx_function_load_ca_cert_from_buffer);
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_CTX_DATA, options.ca_buffer.c_str());
- }
- #endif
- #endif
- if (!options.crl_file.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_CRLFILE, options.crl_file.c_str());
- }
- if (!options.ciphers.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_CIPHER_LIST, options.ciphers.c_str());
- }
- #if SUPPORT_TLSv13_CIPHERS
- if (!options.tls13_ciphers.empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_TLS13_CIPHERS, options.ciphers.c_str());
- }
- #endif
- #if SUPPORT_SESSIONID_CACHE
- curl_easy_setopt(curl_->handle, CURLOPT_SSL_SESSIONID_CACHE, options.session_id_cache ? ON : OFF);
- #endif
- }
- void Session::SetVerbose(const Verbose& verbose) {
- curl_easy_setopt(curl_->handle, CURLOPT_VERBOSE, verbose.verbose ? ON : OFF);
- }
- void Session::SetInterface(const Interface& iface) {
- if (iface.str().empty()) {
- curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, nullptr);
- } else {
- curl_easy_setopt(curl_->handle, CURLOPT_INTERFACE, iface.c_str());
- }
- }
- void Session::SetLocalPort(const LocalPort& local_port) {
- curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORT, local_port);
- }
- void Session::SetLocalPortRange(const LocalPortRange& local_port_range) {
- curl_easy_setopt(curl_->handle, CURLOPT_LOCALPORTRANGE, local_port_range);
- }
- void Session::SetHttpVersion(const HttpVersion& version) {
- switch (version.code) {
- case HttpVersionCode::VERSION_NONE:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
- break;
- case HttpVersionCode::VERSION_1_0:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
- break;
- case HttpVersionCode::VERSION_1_1:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
- break;
- #if LIBCURL_VERSION_NUM >= 0x072100 // 7.33.0
- case HttpVersionCode::VERSION_2_0:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
- break;
- #endif
- #if LIBCURL_VERSION_NUM >= 0x072F00 // 7.47.0
- case HttpVersionCode::VERSION_2_0_TLS:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
- break;
- #endif
- #if LIBCURL_VERSION_NUM >= 0x073100 // 7.49.0
- case HttpVersionCode::VERSION_2_0_PRIOR_KNOWLEDGE:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
- break;
- #endif
- #if LIBCURL_VERSION_NUM >= 0x074200 // 7.66.0
- case HttpVersionCode::VERSION_3_0:
- curl_easy_setopt(curl_->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_3);
- break;
- #endif
- default: // Should not happen
- throw std::invalid_argument("Invalid/Unknown HTTP version type.");
- break;
- }
- }
- void Session::SetRange(const Range& range) {
- std::string range_str = range.str();
- curl_easy_setopt(curl_->handle, CURLOPT_RANGE, range_str.c_str());
- }
- void Session::SetMultiRange(const MultiRange& multi_range) {
- std::string multi_range_str = multi_range.str();
- curl_easy_setopt(curl_->handle, CURLOPT_RANGE, multi_range_str.c_str());
- }
- void Session::SetReserveSize(const ReserveSize& reserve_size) {
- ResponseStringReserve(reserve_size.size);
- }
- void Session::SetAcceptEncoding(const AcceptEncoding& accept_encoding) {
- acceptEncoding_ = accept_encoding;
- }
- void Session::SetAcceptEncoding(AcceptEncoding&& accept_encoding) {
- acceptEncoding_ = std::move(accept_encoding);
- }
- cpr_off_t Session::GetDownloadFileLength() {
- cpr_off_t downloadFileLenth = -1;
- curl_easy_setopt(curl_->handle, CURLOPT_URL, url_.c_str());
- std::string protocol = url_.str().substr(0, url_.str().find(':'));
- if (proxies_.has(protocol)) {
- curl_easy_setopt(curl_->handle, CURLOPT_PROXY, proxies_[protocol].c_str());
- if (proxyAuth_.has(protocol)) {
- curl_easy_setopt(curl_->handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
- curl_easy_setopt(curl_->handle, CURLOPT_PROXYUSERPWD, proxyAuth_[protocol]);
- }
- }
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1);
- if (DoEasyPerform() == CURLE_OK) {
- curl_easy_getinfo(curl_->handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &downloadFileLenth);
- }
- return downloadFileLenth;
- }
- void Session::ResponseStringReserve(size_t size) {
- response_string_reserve_size_ = size;
- }
- Response Session::Delete() {
- PrepareDelete();
- return makeRequest();
- }
- Response Session::Download(const WriteCallback& write) {
- PrepareDownload(write);
- return makeDownloadRequest();
- }
- Response Session::Download(std::ofstream& file) {
- PrepareDownload(file);
- return makeDownloadRequest();
- }
- Response Session::Get() {
- PrepareGet();
- return makeRequest();
- }
- Response Session::Head() {
- PrepareHead();
- return makeRequest();
- }
- Response Session::Options() {
- PrepareOptions();
- return makeRequest();
- }
- Response Session::Patch() {
- PreparePatch();
- return makeRequest();
- }
- Response Session::Post() {
- PreparePost();
- return makeRequest();
- }
- Response Session::Put() {
- PreparePut();
- return makeRequest();
- }
- std::shared_ptr<Session> Session::GetSharedPtrFromThis() {
- try {
- return shared_from_this();
- } catch (std::bad_weak_ptr&) {
- 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.");
- }
- }
- AsyncResponse Session::GetAsync() {
- auto shared_this = shared_from_this();
- return async([shared_this]() { return shared_this->Get(); });
- }
- AsyncResponse Session::DeleteAsync() {
- return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Delete(); });
- }
- AsyncResponse Session::DownloadAsync(const WriteCallback& write) {
- return async([shared_this = GetSharedPtrFromThis(), write]() { return shared_this->Download(write); });
- }
- AsyncResponse Session::DownloadAsync(std::ofstream& file) {
- return async([shared_this = GetSharedPtrFromThis(), &file]() { return shared_this->Download(file); });
- }
- AsyncResponse Session::HeadAsync() {
- return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Head(); });
- }
- AsyncResponse Session::OptionsAsync() {
- return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Options(); });
- }
- AsyncResponse Session::PatchAsync() {
- return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Patch(); });
- }
- AsyncResponse Session::PostAsync() {
- return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Post(); });
- }
- AsyncResponse Session::PutAsync() {
- return async([shared_this = GetSharedPtrFromThis()]() { return shared_this->Put(); });
- }
- std::shared_ptr<CurlHolder> Session::GetCurlHolder() {
- return curl_;
- }
- std::string Session::GetFullRequestUrl() {
- const std::string parametersContent = parameters_.GetContent(*curl_);
- return url_.str() + (parametersContent.empty() ? "" : "?") + parametersContent;
- }
- void Session::PrepareDelete() {
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "DELETE");
- prepareCommon();
- }
- void Session::PrepareGet() {
- // In case there is a body or payload for this request, we create a custom GET-Request since a
- // GET-Request with body is based on the HTTP RFC **not** a leagal request.
- if (hasBodyOrPayload_) {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "GET");
- } else {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1L);
- }
- prepareCommon();
- }
- void Session::PrepareHead() {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 1L);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
- prepareCommon();
- }
- void Session::PrepareOptions() {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "OPTIONS");
- prepareCommon();
- }
- void Session::PreparePatch() {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PATCH");
- prepareCommon();
- }
- void Session::PreparePost() {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- // In case there is no body or payload set it to an empty post:
- if (hasBodyOrPayload_) {
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
- } else {
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, readcb_.callback ? nullptr : "");
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "POST");
- }
- prepareCommon();
- }
- void Session::PreparePut() {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- if (!hasBodyOrPayload_ && readcb_.callback) {
- /**
- * Yes, this one has to be CURLOPT_POSTFIELDS even if we are performing a PUT request.
- * In case we don't set this one, performing a POST-request with PUT won't work.
- * It in theory this only enforces the usage of the readcallback for POST requests, but works here as well.
- **/
- curl_easy_setopt(curl_->handle, CURLOPT_POSTFIELDS, nullptr);
- }
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, "PUT");
- curl_easy_setopt(curl_->handle, CURLOPT_RANGE, nullptr);
- prepareCommon();
- }
- void Session::PrepareDownload(std::ofstream& file) {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
- curl_easy_setopt(curl_->handle, CURLOPT_WRITEFUNCTION, cpr::util::writeFileFunction);
- curl_easy_setopt(curl_->handle, CURLOPT_WRITEDATA, &file);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
- prepareCommonDownload();
- }
- void Session::PrepareDownload(const WriteCallback& write) {
- curl_easy_setopt(curl_->handle, CURLOPT_NOBODY, 0L);
- curl_easy_setopt(curl_->handle, CURLOPT_HTTPGET, 1);
- curl_easy_setopt(curl_->handle, CURLOPT_CUSTOMREQUEST, nullptr);
- SetWriteCallback(write);
- prepareCommonDownload();
- }
- Response Session::Complete(CURLcode curl_error) {
- curl_slist* raw_cookies{nullptr};
- curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies);
- Cookies cookies = util::parseCookies(raw_cookies);
- curl_slist_free_all(raw_cookies);
- // Reset the has no body property:
- hasBodyOrPayload_ = false;
- std::string errorMsg = curl_->error.data();
- return Response(curl_, std::move(response_string_), std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg)));
- }
- Response Session::CompleteDownload(CURLcode curl_error) {
- if (!headercb_.callback) {
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERFUNCTION, nullptr);
- curl_easy_setopt(curl_->handle, CURLOPT_HEADERDATA, 0);
- }
- curl_slist* raw_cookies{nullptr};
- curl_easy_getinfo(curl_->handle, CURLINFO_COOKIELIST, &raw_cookies);
- Cookies cookies = util::parseCookies(raw_cookies);
- curl_slist_free_all(raw_cookies);
- std::string errorMsg = curl_->error.data();
- return Response(curl_, "", std::move(header_string_), std::move(cookies), Error(curl_error, std::move(errorMsg)));
- }
- void Session::AddInterceptor(const std::shared_ptr<Interceptor>& pinterceptor) {
- interceptors_.push(pinterceptor);
- }
- Response Session::proceed() {
- prepareCommon();
- return makeRequest();
- }
- // clang-format off
- void Session::SetOption(const Resolve& resolve) { SetResolve(resolve); }
- void Session::SetOption(const std::vector<Resolve>& resolves) { SetResolves(resolves); }
- void Session::SetOption(const ReadCallback& read) { SetReadCallback(read); }
- void Session::SetOption(const HeaderCallback& header) { SetHeaderCallback(header); }
- void Session::SetOption(const WriteCallback& write) { SetWriteCallback(write); }
- void Session::SetOption(const ProgressCallback& progress) { SetProgressCallback(progress); }
- void Session::SetOption(const DebugCallback& debug) { SetDebugCallback(debug); }
- void Session::SetOption(const Url& url) { SetUrl(url); }
- void Session::SetOption(const Parameters& parameters) { SetParameters(parameters); }
- void Session::SetOption(Parameters&& parameters) { SetParameters(std::move(parameters)); }
- void Session::SetOption(const Header& header) { SetHeader(header); }
- void Session::SetOption(const Timeout& timeout) { SetTimeout(timeout); }
- void Session::SetOption(const ConnectTimeout& timeout) { SetConnectTimeout(timeout); }
- void Session::SetOption(const Authentication& auth) { SetAuth(auth); }
- void Session::SetOption(const LimitRate& limit_rate) { SetLimitRate(limit_rate); }
- // Only supported with libcurl >= 7.61.0.
- // As an alternative use SetHeader and add the token manually.
- #if LIBCURL_VERSION_NUM >= 0x073D00
- void Session::SetOption(const Bearer& auth) { SetBearer(auth); }
- #endif
- void Session::SetOption(const UserAgent& ua) { SetUserAgent(ua); }
- void Session::SetOption(const Payload& payload) { SetPayload(payload); }
- void Session::SetOption(Payload&& payload) { SetPayload(std::move(payload)); }
- void Session::SetOption(const Proxies& proxies) { SetProxies(proxies); }
- void Session::SetOption(Proxies&& proxies) { SetProxies(std::move(proxies)); }
- void Session::SetOption(ProxyAuthentication&& proxy_auth) { SetProxyAuth(std::move(proxy_auth)); }
- void Session::SetOption(const ProxyAuthentication& proxy_auth) { SetProxyAuth(proxy_auth); }
- void Session::SetOption(const Multipart& multipart) { SetMultipart(multipart); }
- void Session::SetOption(Multipart&& multipart) { SetMultipart(std::move(multipart)); }
- void Session::SetOption(const Redirect& redirect) { SetRedirect(redirect); }
- void Session::SetOption(const Cookies& cookies) { SetCookies(cookies); }
- void Session::SetOption(const Body& body) { SetBody(body); }
- void Session::SetOption(Body&& body) { SetBody(std::move(body)); }
- void Session::SetOption(const LowSpeed& low_speed) { SetLowSpeed(low_speed); }
- void Session::SetOption(const VerifySsl& verify) { SetVerifySsl(verify); }
- void Session::SetOption(const Verbose& verbose) { SetVerbose(verbose); }
- void Session::SetOption(const UnixSocket& unix_socket) { SetUnixSocket(unix_socket); }
- void Session::SetOption(const SslOptions& options) { SetSslOptions(options); }
- void Session::SetOption(const Interface& iface) { SetInterface(iface); }
- void Session::SetOption(const LocalPort& local_port) { SetLocalPort(local_port); }
- void Session::SetOption(const LocalPortRange& local_port_range) { SetLocalPortRange(local_port_range); }
- void Session::SetOption(const HttpVersion& version) { SetHttpVersion(version); }
- void Session::SetOption(const Range& range) { SetRange(range); }
- void Session::SetOption(const MultiRange& multi_range) { SetMultiRange(multi_range); }
- void Session::SetOption(const ReserveSize& reserve_size) { SetReserveSize(reserve_size.size); }
- void Session::SetOption(const AcceptEncoding& accept_encoding) { SetAcceptEncoding(accept_encoding); }
- void Session::SetOption(AcceptEncoding&& accept_encoding) { SetAcceptEncoding(accept_encoding); }
- // clang-format on
- } // namespace cpr
|