From 7035e50a94263fee94962e5d55ed812a80bfa423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3me=C3=B3=20Ervin=20Fuk=C3=A1sz?= Date: Tue, 14 Feb 2017 13:02:32 +0100 Subject: [PATCH 1/6] added functions for the insecure ssl config modifications (peer and host) --- include/restclient-cpp/connection.h | 8 ++++++++ source/connection.cc | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/restclient-cpp/connection.h b/include/restclient-cpp/connection.h index 087b6b4f..632e76b7 100644 --- a/include/restclient-cpp/connection.h +++ b/include/restclient-cpp/connection.h @@ -135,6 +135,12 @@ class Connection { // set to not use signals void SetNoSignal(bool no); + // set whether the peer certificate should be validated + void SetPeerVerify(bool peerVerify); + + // set whether the host certificate should be validated + void SetHostVerify(bool hostVerify); + // set whether to follow redirects void FollowRedirects(bool follow); @@ -192,6 +198,8 @@ class Connection { int timeout; bool followRedirects; bool noSignal; + bool hostVerify; + bool peerVerify; struct { std::string username; std::string password; diff --git a/source/connection.cc b/source/connection.cc index e005ed7a..aec8be12 100644 --- a/source/connection.cc +++ b/source/connection.cc @@ -183,6 +183,14 @@ RestClient::Connection::SetNoSignal(bool no) { this->noSignal = no; } +void RestClient::Connection::SetPeerVerify(bool peerVerify) { + this->peerVerify = peerVerify; +} + +void RestClient::Connection::SetHostVerify(bool hostVerify) { + this->hostVerify = hostVerify; +} + /** * @brief set username and password for basic auth * @@ -311,6 +319,14 @@ RestClient::Connection::performCurlRequest(const std::string& uri) { curl_easy_setopt(this->curlHandle, CURLOPT_HTTPHEADER, headerList); + if (!this->hostVerify) { + curl_easy_setopt(this->curlHandle, CURLOPT_SSL_VERIFYHOST, 0L); + } + + if (!this->peerVerify) { + curl_easy_setopt(this->curlHandle, CURLOPT_SSL_VERIFYPEER, 0L); + } + // set basic auth if configured if (this->basicAuth.username.length() > 0) { std::string authString = std::string(this->basicAuth.username + ":" + From 8c13ee6d080352d9fcb759cc3892afaa7120f4fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3me=C3=B3=20Ervin=20Fuk=C3=A1sz?= Date: Wed, 15 Feb 2017 14:50:16 +0100 Subject: [PATCH 2/6] Added c++11 support and made cookies available in the response object --- Makefile.am | 2 +- include/restclient-cpp/restclient.h | 2 ++ source/connection.cc | 14 +++++++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index 5cba018d..fc3f2353 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ ACLOCAL_AMFLAGS=-I m4 -CPPFLAGS=-Iinclude +CPPFLAGS=-Iinclude -std=c++11 check_PROGRAMS = test-program pkginclude_HEADERS = include/restclient-cpp/restclient.h include/restclient-cpp/version.h include/restclient-cpp/connection.h include/restclient-cpp/helpers.h BUILT_SOURCES = include/restclient-cpp/version.h diff --git a/include/restclient-cpp/restclient.h b/include/restclient-cpp/restclient.h index 75dc7c6e..e3c2195e 100644 --- a/include/restclient-cpp/restclient.h +++ b/include/restclient-cpp/restclient.h @@ -25,6 +25,7 @@ namespace RestClient { * public data definitions */ typedef std::map HeaderFields; +typedef std::map Cookies; /** @struct Response * @brief This structure represents the HTTP response data @@ -39,6 +40,7 @@ typedef struct { int code; std::string body; HeaderFields headers; + Cookies cookies; } Response; // init and disable functions diff --git a/source/connection.cc b/source/connection.cc index aec8be12..67db233d 100644 --- a/source/connection.cc +++ b/source/connection.cc @@ -19,6 +19,7 @@ #include "restclient-cpp/helpers.h" #include "restclient-cpp/version.h" + /** * @brief constructor for the Connection object * @@ -295,6 +296,7 @@ RestClient::Connection::performCurlRequest(const std::string& uri) { std::string headerString; CURLcode res = CURLE_OK; curl_slist* headerList = NULL; + curl_slist* cookieList = NULL; /** set query URL */ curl_easy_setopt(this->curlHandle, CURLOPT_URL, url.c_str()); @@ -431,7 +433,17 @@ RestClient::Connection::performCurlRequest(const std::string& uri) { curl_slist_free_all(headerList); // reset curl handle curl_easy_reset(this->curlHandle); - return ret; + + for (auto& h : ret.headers) { + if (h.first == "Set-Cookie") { + std::string cookie = h.second; + std::size_t pos1 = h.second.find("="); + std::size_t pos2 = h.second.find(";"); + ret.cookies.insert(std::pair( + cookie.substr(0, pos1), cookie.substr(pos1+1, pos2 - pos1 - 1))); + } + } + return ret; } /** From 693c26e97c087a1b7639a6903ee7cc377d2bddff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3me=C3=B3=20Ervin=20Fuk=C3=A1sz?= Date: Sun, 19 Feb 2017 17:59:26 +0100 Subject: [PATCH 3/6] added a copy of the last server response to the connection object added a curl function call to use the cookie engine changed the way cookies are parsed to the response objects w --- include/restclient-cpp/connection.h | 3 +++ source/connection.cc | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/restclient-cpp/connection.h b/include/restclient-cpp/connection.h index 632e76b7..a9b05219 100644 --- a/include/restclient-cpp/connection.h +++ b/include/restclient-cpp/connection.h @@ -191,6 +191,8 @@ class Connection { RestClient::Response del(const std::string& uri); RestClient::Response head(const std::string& uri); + RestClient::Response getLastResponse(); + private: CURL* curlHandle; std::string baseUrl; @@ -213,6 +215,7 @@ class Connection { std::string keyPassword; std::string uriProxy; RestClient::Response performCurlRequest(const std::string& uri); + RestClient::Response lastResponse; }; }; // namespace RestClient diff --git a/source/connection.cc b/source/connection.cc index 67db233d..be398083 100644 --- a/source/connection.cc +++ b/source/connection.cc @@ -291,6 +291,7 @@ RestClient::Response RestClient::Connection::performCurlRequest(const std::string& uri) { // init return type RestClient::Response ret = {}; + curl_easy_setopt(this->curlHandle, CURLOPT_COOKIEFILE, ""); std::string url = std::string(this->baseUrl + uri); std::string headerString; @@ -434,18 +435,26 @@ RestClient::Connection::performCurlRequest(const std::string& uri) { // reset curl handle curl_easy_reset(this->curlHandle); - for (auto& h : ret.headers) { - if (h.first == "Set-Cookie") { - std::string cookie = h.second; - std::size_t pos1 = h.second.find("="); - std::size_t pos2 = h.second.find(";"); - ret.cookies.insert(std::pair( - cookie.substr(0, pos1), cookie.substr(pos1+1, pos2 - pos1 - 1))); - } + struct curl_slist* cookies; + curl_easy_getinfo(this->curlHandle, CURLINFO_COOKIELIST, &cookies); + struct curl_slist* i = cookies; + while (i) { + std::string c = i->data; + std::size_t pos1 = c.find('\t', c.find('\t', c.find('\t', c.find('\t', c.find('\t') + 1) + 1) + 1) + 1); + std::size_t pos2 = c.find('\t', pos1 + 1); + ret.cookies.insert(std::pair(c.substr(pos1 + 1, pos2 - pos1 - 1), c.substr(pos2 + 1))); + i = i->next; } + curl_slist_free_all(cookies); + + this->lastResponse = ret; return ret; } +RestClient::Response RestClient::Connection::getLastResponse() { + return this->lastResponse; +} + /** * @brief HTTP GET method * From 2557b8f92e04f620a0e571113b66b3984f62308a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cz=C3=A9m=C3=A1n=20Arnold?= Date: Sat, 1 Apr 2017 19:38:41 +0200 Subject: [PATCH 4/6] Add cookie handling, and map paramiterized post method --- include/restclient-cpp/connection.h | 12 ++++++ source/connection.cc | 66 ++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/include/restclient-cpp/connection.h b/include/restclient-cpp/connection.h index a9b05219..0194a666 100644 --- a/include/restclient-cpp/connection.h +++ b/include/restclient-cpp/connection.h @@ -22,6 +22,8 @@ */ namespace RestClient { +typedef std::map PostData; + /** * @brief Connection object for advanced usage */ @@ -186,6 +188,8 @@ class Connection { RestClient::Response get(const std::string& uri); RestClient::Response post(const std::string& uri, const std::string& data); + RestClient::Response post(const std::string& url, + const RestClient::PostData& data); RestClient::Response put(const std::string& uri, const std::string& data); RestClient::Response del(const std::string& uri); @@ -193,6 +197,13 @@ class Connection { RestClient::Response getLastResponse(); + // Cookie handler methods + void setCookies(const Cookies& cookies); + const Cookies& getCookies()const; + void setCookie(std::string key, std::string value); + std::string getCookie(std::string key)const; + void clearCookies(); + private: CURL* curlHandle; std::string baseUrl; @@ -216,6 +227,7 @@ class Connection { std::string uriProxy; RestClient::Response performCurlRequest(const std::string& uri); RestClient::Response lastResponse; + Cookies cookies; }; }; // namespace RestClient diff --git a/source/connection.cc b/source/connection.cc index be398083..5c11502c 100644 --- a/source/connection.cc +++ b/source/connection.cc @@ -20,14 +20,32 @@ #include "restclient-cpp/version.h" +static std::string cookies_to_string(const RestClient::Cookies& cookies){ + + std::string retv; + for(auto entry:cookies){ + retv += entry.first + "=" + entry.second + "; "; + } + return retv; +} + +static std::string postdata_to_string(CURL* curlHandle, const RestClient::PostData& data){ + std::string retv; + for(auto entry:data){ + char* value = curl_easy_escape(curlHandle, entry.second.c_str(), entry.second.size()); + retv += entry.first + "=" + value + "&"; + curl_free(value); + } + return retv; +} + /** * @brief constructor for the Connection object * * @param baseUrl - base URL for the connection to use * */ -RestClient::Connection::Connection(const std::string& baseUrl) - : lastRequest(), headerFields() { +RestClient::Connection::Connection(const std::string& baseUrl) { this->curlHandle = curl_easy_init(); if (!this->curlHandle) { throw std::runtime_error("Couldn't initialize curl handle"); @@ -393,6 +411,12 @@ RestClient::Connection::performCurlRequest(const std::string& uri) { 1L); } + // set cookies + if(cookies.empty() == false){ + std::string cookie_data = cookies_to_string(cookies); + curl_easy_setopt(this->curlHandle, CURLOPT_COOKIE, cookie_data.c_str()); + } + res = curl_easy_perform(this->curlHandle); if (res != CURLE_OK) { switch (res) { @@ -485,6 +509,22 @@ RestClient::Connection::post(const std::string& url, return this->performCurlRequest(url); } + + +RestClient::Response +RestClient::Connection::post(const std::string& url, + const RestClient::PostData& data) { + + std::string pdata = postdata_to_string(this->curlHandle, data); + + /** Now specify we want to POST data */ + curl_easy_setopt(this->curlHandle, CURLOPT_POST, 1L); + /** set post fields */ + curl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDS, pdata.c_str()); + curl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDSIZE, pdata.size()); + + return this->performCurlRequest(url); +} /** * @brief HTTP PUT method * @@ -551,3 +591,25 @@ RestClient::Connection::head(const std::string& url) { return this->performCurlRequest(url); } + + +// Cookie handler methods +void RestClient::Connection::setCookies(const Cookies& cookies){ + this->cookies = cookies; +} + +const RestClient::Cookies& RestClient::Connection::getCookies()const{ + return cookies; +} + +void RestClient::Connection::setCookie(std::string key, std::string value){ + cookies[key] = value; +} + +std::string RestClient::Connection::getCookie(std::string key)const{ + return cookies.at(key); +} + +void RestClient::Connection::clearCookies(){ + this->cookies.clear(); +} From cd752ebd7748f41f77f90fe8a3e3cc1369da8695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cz=C3=A9m=C3=A1n=20Arnold?= Date: Sun, 9 Apr 2017 17:42:12 +0200 Subject: [PATCH 5/6] Store effective url in last request --- include/restclient-cpp/connection.h | 1 + source/connection.cc | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/restclient-cpp/connection.h b/include/restclient-cpp/connection.h index 0194a666..d04bf64a 100644 --- a/include/restclient-cpp/connection.h +++ b/include/restclient-cpp/connection.h @@ -67,6 +67,7 @@ class Connection { double preTransferTime; double startTransferTime; double redirectTime; + std::string effectiveUrl; int redirectCount; } RequestInfo; /** diff --git a/source/connection.cc b/source/connection.cc index 5c11502c..94ddb635 100644 --- a/source/connection.cc +++ b/source/connection.cc @@ -454,6 +454,11 @@ RestClient::Connection::performCurlRequest(const std::string& uri) { &this->lastRequest.redirectTime); curl_easy_getinfo(this->curlHandle, CURLINFO_REDIRECT_COUNT, &this->lastRequest.redirectCount); + char* effectiveUrl; + curl_easy_getinfo(this->curlHandle, CURLINFO_EFFECTIVE_URL, + &effectiveUrl); + lastRequest.effectiveUrl = effectiveUrl; + // free header list curl_slist_free_all(headerList); // reset curl handle From 41947b08d6cf9a7ffa7fe55158dbeb93d30c2f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cz=C3=A9m=C3=A1n=20Arnold?= Date: Mon, 17 Apr 2017 01:42:02 +0200 Subject: [PATCH 6/6] Fix uninitialized attributes --- source/connection.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/connection.cc b/source/connection.cc index 94ddb635..397a01e2 100644 --- a/source/connection.cc +++ b/source/connection.cc @@ -45,7 +45,8 @@ static std::string postdata_to_string(CURL* curlHandle, const RestClient::PostDa * @param baseUrl - base URL for the connection to use * */ -RestClient::Connection::Connection(const std::string& baseUrl) { +RestClient::Connection::Connection(const std::string& baseUrl) + :hostVerify(true),peerVerify(true) { this->curlHandle = curl_easy_init(); if (!this->curlHandle) { throw std::runtime_error("Couldn't initialize curl handle");