session.cpp
Go to the documentation of this file.
00001 #include "cpr/session.h"
00002 
00003 #include <algorithm>
00004 #include <functional>
00005 #include <string>
00006 
00007 #include <curl/curl.h>
00008 
00009 #include "cpr/curlholder.h"
00010 #include "cpr/util.h"
00011 
00012 namespace cpr {
00013 
00014 class Session::Impl {
00015   public:
00016     Impl();
00017 
00018     void SetUrl(const Url& url);
00019     void SetParameters(const Parameters& parameters);
00020     void SetParameters(Parameters&& parameters);
00021     void SetHeader(const Header& header);
00022     void SetTimeout(const Timeout& timeout);
00023     void SetAuth(const Authentication& auth);
00024     void SetDigest(const Digest& auth);
00025     void SetPayload(Payload&& payload);
00026     void SetPayload(const Payload& payload);
00027     void SetProxies(Proxies&& proxies);
00028     void SetProxies(const Proxies& proxies);
00029     void SetMultipart(Multipart&& multipart);
00030     void SetMultipart(const Multipart& multipart);
00031     void SetRedirect(const bool& redirect);
00032     void SetMaxRedirects(const MaxRedirects& max_redirects);
00033     void SetCookies(const Cookies& cookies);
00034     void SetBody(Body&& body);
00035     void SetBody(const Body& body);
00036     void SetLowSpeed(const LowSpeed& low_speed);
00037     void SetVerifySsl(const VerifySsl& verify);
00038 
00039     Response Delete();
00040     Response Get();
00041     Response Head();
00042     Response Options();
00043     Response Patch();
00044     Response Post();
00045     Response Put();
00046 
00047   private:
00048     std::unique_ptr<CurlHolder, std::function<void(CurlHolder*)>> curl_;
00049     Url url_;
00050     Parameters parameters_;
00051     Proxies proxies_;
00052 
00053     Response makeRequest(CURL* curl);
00054     static void freeHolder(CurlHolder* holder);
00055     static CurlHolder* newHolder();
00056 };
00057 
00058 Session::Impl::Impl() {
00059     curl_ = std::unique_ptr<CurlHolder, std::function<void(CurlHolder*)>>(newHolder(),
00060                                                                           &Impl::freeHolder);
00061     auto curl = curl_->handle;
00062     if (curl) {
00063         // Set up some sensible defaults
00064         auto version_info = curl_version_info(CURLVERSION_NOW);
00065         auto version = std::string{"curl/"} + std::string{version_info->version};
00066         curl_easy_setopt(curl, CURLOPT_USERAGENT, version.data());
00067         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
00068         curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
00069         curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 50L);
00070         curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_->error);
00071         curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
00072 #ifdef CPR_CURL_NOSIGNAL
00073         curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
00074 #endif
00075 #if LIBCURL_VERSION_MAJOR >= 7
00076 #if LIBCURL_VERSION_MINOR >= 25
00077 #if LIBCURL_VERSION_PATCH >= 0
00078         curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
00079 #endif
00080 #endif
00081 #endif
00082     }
00083 }
00084 
00085 void Session::Impl::freeHolder(CurlHolder* holder) {
00086     curl_easy_cleanup(holder->handle);
00087     curl_slist_free_all(holder->chunk);
00088     curl_formfree(holder->formpost);
00089     delete holder;
00090 }
00091 
00092 CurlHolder* Session::Impl::newHolder() {
00093     CurlHolder* holder = new CurlHolder();
00094     holder->handle = curl_easy_init();
00095     return holder;
00096 }
00097 
00098 void Session::Impl::SetUrl(const Url& url) {
00099     url_ = url;
00100 }
00101 
00102 void Session::Impl::SetParameters(const Parameters& parameters) {
00103     parameters_ = parameters;
00104 }
00105 
00106 void Session::Impl::SetParameters(Parameters&& parameters) {
00107     parameters_ = std::move(parameters);
00108 }
00109 
00110 void Session::Impl::SetHeader(const Header& header) {
00111     auto curl = curl_->handle;
00112     if (curl) {
00113         struct curl_slist* chunk = NULL;
00114         for (auto item = header.cbegin(); item != header.cend(); ++item) {
00115             auto header_string = std::string{item->first};
00116             if (item->second.empty()) {
00117                 header_string += ";";
00118             } else {
00119                 header_string += ": " + item->second;
00120             }
00121             chunk = curl_slist_append(chunk, header_string.data());
00122             curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
00123             curl_->chunk = chunk;
00124         }
00125     }
00126 }
00127 
00128 void Session::Impl::SetTimeout(const Timeout& timeout) {
00129     auto curl = curl_->handle;
00130     if (curl) {
00131         curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout.Milliseconds());
00132     }
00133 }
00134 
00135 void Session::Impl::SetAuth(const Authentication& auth) {
00136     auto curl = curl_->handle;
00137     if (curl) {
00138         curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
00139         curl_easy_setopt(curl, CURLOPT_USERPWD, auth.GetAuthString());
00140     }
00141 }
00142 
00143 void Session::Impl::SetDigest(const Digest& auth) {
00144     auto curl = curl_->handle;
00145     if (curl) {
00146         curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
00147         curl_easy_setopt(curl, CURLOPT_USERPWD, auth.GetAuthString());
00148     }
00149 }
00150 
00151 void Session::Impl::SetPayload(Payload&& payload) {
00152     auto curl = curl_->handle;
00153     if (curl) {
00154         curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.content.length());
00155         curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, payload.content.data());
00156     }
00157 }
00158 
00159 void Session::Impl::SetPayload(const Payload& payload) {
00160     auto curl = curl_->handle;
00161     if (curl) {
00162         curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.content.length());
00163         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.content.data());
00164     }
00165 }
00166 
00167 void Session::Impl::SetProxies(const Proxies& proxies) {
00168     proxies_ = proxies;
00169 }
00170 
00171 void Session::Impl::SetProxies(Proxies&& proxies) {
00172     proxies_ = std::move(proxies);
00173 }
00174 
00175 void Session::Impl::SetMultipart(Multipart&& multipart) {
00176     auto curl = curl_->handle;
00177     if (curl) {
00178         struct curl_httppost* formpost = NULL;
00179         struct curl_httppost* lastptr = NULL;
00180 
00181         for (auto& part : multipart.parts) {
00182             std::vector<struct curl_forms> formdata;
00183             formdata.push_back({CURLFORM_COPYNAME, part.name.data()});
00184             if (part.is_buffer) {
00185                 formdata.push_back({CURLFORM_BUFFER, part.value.data()});
00186                 formdata.push_back(
00187                         {CURLFORM_COPYCONTENTS, reinterpret_cast<const char*>(part.data)});
00188                 formdata.push_back(
00189                         {CURLFORM_CONTENTSLENGTH, reinterpret_cast<const char*>(part.datalen)});
00190             } else if (part.is_file) {
00191                 formdata.push_back({CURLFORM_FILE, part.value.data()});
00192             } else {
00193                 formdata.push_back({CURLFORM_COPYCONTENTS, part.value.data()});
00194             }
00195             if (!part.content_type.empty()) {
00196                 formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.data()});
00197             }
00198             formdata.push_back({CURLFORM_END, nullptr});
00199             curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
00200         }
00201         curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
00202 
00203         curl_formfree(curl_->formpost);
00204         curl_->formpost = formpost;
00205     }
00206 }
00207 
00208 void Session::Impl::SetMultipart(const Multipart& multipart) {
00209     auto curl = curl_->handle;
00210     if (curl) {
00211         struct curl_httppost* formpost = NULL;
00212         struct curl_httppost* lastptr = NULL;
00213 
00214         for (auto& part : multipart.parts) {
00215             std::vector<struct curl_forms> formdata;
00216             formdata.push_back({CURLFORM_PTRNAME, part.name.data()});
00217             if (part.is_buffer) {
00218                 formdata.push_back({CURLFORM_BUFFER, part.value.data()});
00219                 formdata.push_back({CURLFORM_BUFFERPTR, reinterpret_cast<const char*>(part.data)});
00220                 formdata.push_back(
00221                         {CURLFORM_BUFFERLENGTH, reinterpret_cast<const char*>(part.datalen)});
00222             } else if (part.is_file) {
00223                 formdata.push_back({CURLFORM_FILE, part.value.data()});
00224             } else {
00225                 formdata.push_back({CURLFORM_PTRCONTENTS, part.value.data()});
00226             }
00227             if (!part.content_type.empty()) {
00228                 formdata.push_back({CURLFORM_CONTENTTYPE, part.content_type.data()});
00229             }
00230             formdata.push_back({CURLFORM_END, nullptr});
00231             curl_formadd(&formpost, &lastptr, CURLFORM_ARRAY, formdata.data(), CURLFORM_END);
00232         }
00233         curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
00234 
00235         curl_formfree(curl_->formpost);
00236         curl_->formpost = formpost;
00237     }
00238 }
00239 
00240 void Session::Impl::SetRedirect(const bool& redirect) {
00241     auto curl = curl_->handle;
00242     if (curl) {
00243         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, std::int32_t(redirect));
00244     }
00245 }
00246 
00247 void Session::Impl::SetMaxRedirects(const MaxRedirects& max_redirects) {
00248     auto curl = curl_->handle;
00249     if (curl) {
00250         curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_redirects.number_of_redirects);
00251     }
00252 }
00253 
00254 void Session::Impl::SetCookies(const Cookies& cookies) {
00255     auto curl = curl_->handle;
00256     if (curl) {
00257         curl_easy_setopt(curl, CURLOPT_COOKIELIST, "ALL");
00258         curl_easy_setopt(curl, CURLOPT_COOKIE, cookies.GetEncoded().data());
00259     }
00260 }
00261 
00262 void Session::Impl::SetBody(Body&& body) {
00263     auto curl = curl_->handle;
00264     if (curl) {
00265         curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
00266         curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, body.data());
00267     }
00268 }
00269 
00270 void Session::Impl::SetBody(const Body& body) {
00271     auto curl = curl_->handle;
00272     if (curl) {
00273         curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.length());
00274         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.data());
00275     }
00276 }
00277 
00278 void Session::Impl::SetLowSpeed(const LowSpeed& low_speed) {
00279     auto curl = curl_->handle;
00280     if (curl) {
00281         curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, low_speed.limit);
00282         curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, low_speed.time);
00283     }
00284 }
00285 
00286 void Session::Impl::SetVerifySsl(const VerifySsl& verify) {
00287     auto curl = curl_->handle;
00288     if (curl) {
00289         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, verify ? 1L : 0L);
00290         curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, verify ? 2L : 0L);
00291     }
00292 }
00293 
00294 Response Session::Impl::Delete() {
00295     auto curl = curl_->handle;
00296     if (curl) {
00297         curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L);
00298         curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
00299         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
00300     }
00301 
00302     return makeRequest(curl);
00303 }
00304 
00305 Response Session::Impl::Get() {
00306     auto curl = curl_->handle;
00307     if (curl) {
00308         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
00309         curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
00310         curl_easy_setopt(curl, CURLOPT_POST, 0L);
00311         curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
00312     }
00313 
00314     return makeRequest(curl);
00315 }
00316 
00317 Response Session::Impl::Head() {
00318     auto curl = curl_->handle;
00319     if (curl) {
00320         curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L);
00321         curl_easy_setopt(curl, CURLOPT_POST, 0L);
00322         curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
00323     }
00324 
00325     return makeRequest(curl);
00326 }
00327 
00328 Response Session::Impl::Options() {
00329     auto curl = curl_->handle;
00330     if (curl) {
00331         curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L);
00332         curl_easy_setopt(curl, CURLOPT_POST, 0L);
00333         curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
00334         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "OPTIONS");
00335     }
00336 
00337     return makeRequest(curl);
00338 }
00339 
00340 Response Session::Impl::Patch() {
00341     auto curl = curl_->handle;
00342     if (curl) {
00343         curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
00344         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
00345     }
00346 
00347     return makeRequest(curl);
00348 }
00349 
00350 Response Session::Impl::Post() {
00351     auto curl = curl_->handle;
00352     if (curl) {
00353         curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L);
00354         curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
00355     }
00356 
00357     return makeRequest(curl);
00358 }
00359 
00360 Response Session::Impl::Put() {
00361     auto curl = curl_->handle;
00362     if (curl) {
00363         curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
00364         curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
00365     }
00366 
00367     return makeRequest(curl);
00368 }
00369 
00370 Response Session::Impl::makeRequest(CURL* curl) {
00371     if (!parameters_.content.empty()) {
00372         Url new_url{url_ + "?" + parameters_.content};
00373         curl_easy_setopt(curl, CURLOPT_URL, new_url.data());
00374     } else {
00375         curl_easy_setopt(curl, CURLOPT_URL, url_.data());
00376     }
00377 
00378     auto protocol = url_.substr(0, url_.find(':'));
00379     if (proxies_.has(protocol)) {
00380         curl_easy_setopt(curl, CURLOPT_PROXY, proxies_[protocol].data());
00381     } else {
00382         curl_easy_setopt(curl, CURLOPT_PROXY, "");
00383     }
00384 
00385     curl_->error[0] = '\0';
00386 
00387     std::string response_string;
00388     std::string header_string;
00389     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cpr::util::writeFunction);
00390     curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);
00391     curl_easy_setopt(curl, CURLOPT_HEADERDATA, &header_string);
00392 
00393     auto curl_error = curl_easy_perform(curl);
00394 
00395     char* raw_url;
00396     long response_code;
00397     double elapsed;
00398     curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
00399     curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &elapsed);
00400     curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &raw_url);
00401 
00402     Error error(curl_error, curl_->error);
00403 
00404     Cookies cookies;
00405     struct curl_slist* raw_cookies;
00406     curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &raw_cookies);
00407     for (struct curl_slist* nc = raw_cookies; nc; nc = nc->next) {
00408         auto tokens = cpr::util::split(nc->data, '\t');
00409         auto value = tokens.back();
00410         tokens.pop_back();
00411         cookies[tokens.back()] = value;
00412     }
00413     curl_slist_free_all(raw_cookies);
00414 
00415     auto header = cpr::util::parseHeader(header_string);
00416     return Response{static_cast<std::int32_t>(response_code),
00417                     response_string,
00418                     header,
00419                     raw_url,
00420                     elapsed,
00421                     cookies,
00422                     error};
00423 }
00424 
00425 // clang-format off
00426 Session::Session() : pimpl_{ new Impl{} } {}
00427 Session::~Session() {}
00428 void Session::SetUrl(const Url& url) { pimpl_->SetUrl(url); }
00429 void Session::SetParameters(const Parameters& parameters) { pimpl_->SetParameters(parameters); }
00430 void Session::SetParameters(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); }
00431 void Session::SetHeader(const Header& header) { pimpl_->SetHeader(header); }
00432 void Session::SetTimeout(const Timeout& timeout) { pimpl_->SetTimeout(timeout); }
00433 void Session::SetAuth(const Authentication& auth) { pimpl_->SetAuth(auth); }
00434 void Session::SetDigest(const Digest& auth) { pimpl_->SetDigest(auth); }
00435 void Session::SetPayload(const Payload& payload) { pimpl_->SetPayload(payload); }
00436 void Session::SetPayload(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); }
00437 void Session::SetProxies(const Proxies& proxies) { pimpl_->SetProxies(proxies); }
00438 void Session::SetProxies(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); }
00439 void Session::SetMultipart(const Multipart& multipart) { pimpl_->SetMultipart(multipart); }
00440 void Session::SetMultipart(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); }
00441 void Session::SetRedirect(const bool& redirect) { pimpl_->SetRedirect(redirect); }
00442 void Session::SetMaxRedirects(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); }
00443 void Session::SetCookies(const Cookies& cookies) { pimpl_->SetCookies(cookies); }
00444 void Session::SetBody(const Body& body) { pimpl_->SetBody(body); }
00445 void Session::SetBody(Body&& body) { pimpl_->SetBody(std::move(body)); }
00446 void Session::SetLowSpeed(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); }
00447 void Session::SetVerifySsl(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); }
00448 void Session::SetOption(const Url& url) { pimpl_->SetUrl(url); }
00449 void Session::SetOption(const Parameters& parameters) { pimpl_->SetParameters(parameters); }
00450 void Session::SetOption(Parameters&& parameters) { pimpl_->SetParameters(std::move(parameters)); }
00451 void Session::SetOption(const Header& header) { pimpl_->SetHeader(header); }
00452 void Session::SetOption(const Timeout& timeout) { pimpl_->SetTimeout(timeout); }
00453 void Session::SetOption(const Authentication& auth) { pimpl_->SetAuth(auth); }
00454 void Session::SetOption(const Digest& auth) { pimpl_->SetDigest(auth); }
00455 void Session::SetOption(const Payload& payload) { pimpl_->SetPayload(payload); }
00456 void Session::SetOption(Payload&& payload) { pimpl_->SetPayload(std::move(payload)); }
00457 void Session::SetOption(const Proxies& proxies) { pimpl_->SetProxies(proxies); }
00458 void Session::SetOption(Proxies&& proxies) { pimpl_->SetProxies(std::move(proxies)); }
00459 void Session::SetOption(const Multipart& multipart) { pimpl_->SetMultipart(multipart); }
00460 void Session::SetOption(Multipart&& multipart) { pimpl_->SetMultipart(std::move(multipart)); }
00461 void Session::SetOption(const bool& redirect) { pimpl_->SetRedirect(redirect); }
00462 void Session::SetOption(const MaxRedirects& max_redirects) { pimpl_->SetMaxRedirects(max_redirects); }
00463 void Session::SetOption(const Cookies& cookies) { pimpl_->SetCookies(cookies); }
00464 void Session::SetOption(const Body& body) { pimpl_->SetBody(body); }
00465 void Session::SetOption(Body&& body) { pimpl_->SetBody(std::move(body)); }
00466 void Session::SetOption(const LowSpeed& low_speed) { pimpl_->SetLowSpeed(low_speed); }
00467 void Session::SetOption(const VerifySsl& verify) { pimpl_->SetVerifySsl(verify); }
00468 Response Session::Delete() { return pimpl_->Delete(); }
00469 Response Session::Get() { return pimpl_->Get(); }
00470 Response Session::Head() { return pimpl_->Head(); }
00471 Response Session::Options() { return pimpl_->Options(); }
00472 Response Session::Patch() { return pimpl_->Patch(); }
00473 Response Session::Post() { return pimpl_->Post(); }
00474 Response Session::Put() { return pimpl_->Put(); }
00475 // clang-format on
00476 
00477 } // namespace cpr


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06