summaryrefslogtreecommitdiff
path: root/external/restclient
diff options
context:
space:
mode:
authorIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
committerIronClawTrem <louie.nutman@gmail.com>2020-02-16 03:40:06 +0000
commit425decdf7e9284d15aa726e3ae96b9942fb0e3ea (patch)
tree6c0dd7edfefff1be7b9e75fe0b3a0a85fe1595f3 /external/restclient
parentccb0b2e4d6674a7a00c9bf491f08fc73b6898c54 (diff)
create tremded branch
Diffstat (limited to 'external/restclient')
-rw-r--r--external/restclient/CMakeLists.txt10
-rw-r--r--external/restclient/LICENSE20
-rw-r--r--external/restclient/README.md7
-rw-r--r--external/restclient/connection.cpp363
-rw-r--r--external/restclient/helpers.cpp96
-rw-r--r--external/restclient/restclient.cpp118
-rw-r--r--external/restclient/restclient/connection.h169
-rw-r--r--external/restclient/restclient/helpers.h74
-rw-r--r--external/restclient/restclient/restclient.h63
-rw-r--r--external/restclient/restclient/version.h4
10 files changed, 924 insertions, 0 deletions
diff --git a/external/restclient/CMakeLists.txt b/external/restclient/CMakeLists.txt
new file mode 100644
index 0000000..4ca1f3c
--- /dev/null
+++ b/external/restclient/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_library(
+ restclient
+ restclient/connection.h
+ restclient/helpers.h
+ restclient/restclient.h
+ restclient/version.h
+ connection.cpp
+ helpers.cpp
+ restclient.cpp
+ )
diff --git a/external/restclient/LICENSE b/external/restclient/LICENSE
new file mode 100644
index 0000000..5c1358f
--- /dev/null
+++ b/external/restclient/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2010 Daniel Schauenberg
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/external/restclient/README.md b/external/restclient/README.md
new file mode 100644
index 0000000..aa95b6f
--- /dev/null
+++ b/external/restclient/README.md
@@ -0,0 +1,7 @@
+# Rest client for C++
+Modified from [mrtazz/restclient-cpp](https://github.com/mrtazz/restclient-cpp).
+
+## Changes:
+
+ - Added `CURL_FOLLOWURL` option.
+ - Flattened source & includes in one directory.
diff --git a/external/restclient/connection.cpp b/external/restclient/connection.cpp
new file mode 100644
index 0000000..e3adeb2
--- /dev/null
+++ b/external/restclient/connection.cpp
@@ -0,0 +1,363 @@
+/**
+ * @file connection.cpp
+ * @brief implementation of the connection class
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ */
+
+#include "restclient/connection.h"
+
+#include "../../src/client/cl_curl.h"
+#include <cstring>
+#include <string>
+#include <iostream>
+#include <map>
+#include <stdexcept>
+
+#include "restclient/restclient.h"
+#include "restclient/helpers.h"
+#include "restclient/version.h"
+
+/**
+ * @brief constructor for the Connection object
+ *
+ * @param baseUrl - base URL for the connection to use
+ *
+ */
+RestClient::Connection::Connection(const std::string baseUrl)
+ : lastRequest(), headerFields() {
+ this->curlHandle = qcurl_easy_init();
+ if (!this->curlHandle) {
+ throw std::runtime_error("Couldn't initialize curl handle");
+ }
+ this->baseUrl = baseUrl;
+ this->timeout = 0;
+ this->followRedirects = false;
+}
+
+RestClient::Connection::~Connection() {
+ if (this->curlHandle) {
+ qcurl_easy_cleanup(this->curlHandle);
+ }
+}
+
+// getters/setters
+
+/**
+ * @brief get diagnostic information about the connection object
+ *
+ * @return RestClient::Connection::Info struct
+ */
+RestClient::Connection::Info
+RestClient::Connection::GetInfo() {
+ RestClient::Connection::Info ret;
+ ret.baseUrl = this->baseUrl;
+ ret.headers = this->GetHeaders();
+ ret.timeout = this->timeout;
+ ret.basicAuth.username = this->basicAuth.username;
+ ret.basicAuth.password = this->basicAuth.password;
+ ret.customUserAgent = this->customUserAgent;
+ ret.lastRequest = this->lastRequest;
+
+ return ret;
+}
+
+/**
+ * @brief append a header to the internal map
+ *
+ * @param key for the header field
+ * @param value for the header field
+ *
+ */
+void
+RestClient::Connection::AppendHeader(const std::string& key,
+ const std::string& value) {
+ this->headerFields[key] = value;
+}
+
+/**
+ * @brief set the custom headers map. This will replace the currently
+ * configured headers with the provided ones. If you want to add additional
+ * headers, use AppendHeader()
+ *
+ * @param headers to set
+ */
+void
+RestClient::Connection::SetHeaders(RestClient::HeaderFields headers) {
+ this->headerFields = headers;
+}
+
+/**
+ * @brief get all custom headers set on the connection
+ *
+ * @returns a RestClient::HeaderFields map containing the custom headers
+ */
+RestClient::HeaderFields
+RestClient::Connection::GetHeaders() {
+ return this->headerFields;
+}
+
+/**
+ * @brief configure whether to follow redirects on this connection
+ *
+ * @param follow - boolean whether to follow redirects
+ */
+void
+RestClient::Connection::FollowRedirects(bool follow) {
+ this->followRedirects = follow;
+}
+
+/**
+ * @brief set custom user agent for connection. This gets prepended to the
+ * default restclient-cpp/RESTCLIENT_VERSION string
+ *
+ * @param userAgent - custom userAgent prefix
+ *
+ */
+void
+RestClient::Connection::SetUserAgent(const std::string& userAgent) {
+ this->customUserAgent = userAgent;
+}
+
+/**
+ * @brief set custom Certificate Authority (CA) path
+ *
+ * @param caInfoFilePath - The path to a file holding the certificates used to
+ * verify the peer with. See CURLOPT_CAINFO
+ *
+ */
+void
+RestClient::Connection::SetCAInfoFilePath(const std::string& caInfoFilePath) {
+ this->caInfoFilePath = caInfoFilePath;
+}
+
+/**
+ * @brief get the user agent to add to the request
+ *
+ * @return user agent as std::string
+ */
+std::string
+RestClient::Connection::GetUserAgent() {
+ std::string prefix;
+ if (this->customUserAgent.length() > 0) {
+ prefix = this->customUserAgent + " ";
+ }
+ return std::string(prefix + "restclient-cpp/" + RESTCLIENT_VERSION);
+}
+
+/**
+ * @brief set timeout for connection
+ *
+ * @param seconds - timeout in seconds
+ *
+ */
+void
+RestClient::Connection::SetTimeout(int seconds) {
+ this->timeout = seconds;
+}
+
+/**
+ * @brief set username and password for basic auth
+ *
+ * @param username
+ * @param password
+ *
+ */
+void
+RestClient::Connection::SetBasicAuth(const std::string& username,
+ const std::string& password) {
+ this->basicAuth.username = username;
+ this->basicAuth.password = password;
+}
+
+/**
+ * @brief helper function to get called from the actual request methods to
+ * prepare the curlHandle for transfer with generic options, perform the
+ * request and record some stats from the last request and then reset the
+ * handle with curl_easy_reset to its default state. This will keep things
+ * like connections and session ID intact but makes sure you can change
+ * parameters on the object for another request.
+ *
+ * @param uri URI to query
+ * @param ret Reference to the Response struct that should be filled
+ *
+ * @return 0 on success and 1 on error
+ */
+RestClient::Response
+RestClient::Connection::performCurlRequest(const std::string& uri) {
+ // init return type
+ RestClient::Response ret = {};
+
+ std::string url = std::string(this->baseUrl + uri);
+ std::string headerString;
+ CURLcode res = CURLE_OK;
+ curl_slist* headerList = NULL;
+
+ // FIXME:
+ // CURLOPT_FOLLOWLOCATION
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_FOLLOWLOCATION, url.c_str());
+
+ /** set query URL */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_URL, url.c_str());
+ /** set callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_WRITEFUNCTION,
+ Helpers::write_callback);
+ /** set data object to pass to callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_WRITEDATA, &ret);
+ /** set the header callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HEADERFUNCTION,
+ Helpers::header_callback);
+ /** callback object for headers */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HEADERDATA, &ret);
+ /** set http headers */
+ for (HeaderFields::const_iterator it = this->headerFields.begin();
+ it != this->headerFields.end(); ++it) {
+ headerString = it->first;
+ headerString += ": ";
+ headerString += it->second;
+ headerList = qcurl_slist_append(headerList, headerString.c_str());
+ }
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HTTPHEADER,
+ headerList);
+
+ // set basic auth if configured
+ if (this->basicAuth.username.length() > 0) {
+ std::string authString = std::string(this->basicAuth.username + ":" +
+ this->basicAuth.password);
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_USERPWD, authString.c_str());
+ }
+ /** set user agent */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_USERAGENT,
+ this->GetUserAgent().c_str());
+
+ // set timeout
+ if (this->timeout) {
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_TIMEOUT, this->timeout);
+ // dont want to get a sig alarm on timeout
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_NOSIGNAL, 1);
+ }
+ // set follow redirect
+ if (this->followRedirects == true) {
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_FOLLOWLOCATION, 1L);
+ }
+ // if provided, supply CA path
+ if (!this->caInfoFilePath.empty()) {
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_CAINFO,
+ this->caInfoFilePath.c_str());
+ }
+ res = qcurl_easy_perform(this->curlHandle);
+ if (res != CURLE_OK) {
+ if (res == CURLE_OPERATION_TIMEDOUT) {
+ ret.code = res;
+ ret.body = "Operation Timeout.";
+ } else {
+ ret.body = "Failed to query.";
+ ret.code = -1;
+ }
+ } else {
+ int64_t http_code = 0;
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_RESPONSE_CODE, &http_code);
+ ret.code = static_cast<int>(http_code);
+ }
+
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_TOTAL_TIME,
+ &this->lastRequest.totalTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_NAMELOOKUP_TIME,
+ &this->lastRequest.nameLookupTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_CONNECT_TIME,
+ &this->lastRequest.connectTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_APPCONNECT_TIME,
+ &this->lastRequest.appConnectTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_PRETRANSFER_TIME,
+ &this->lastRequest.preTransferTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_STARTTRANSFER_TIME,
+ &this->lastRequest.startTransferTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_REDIRECT_TIME,
+ &this->lastRequest.redirectTime);
+ qcurl_easy_getinfo(this->curlHandle, CURLINFO_REDIRECT_COUNT,
+ &this->lastRequest.redirectCount);
+ // free header list
+ qcurl_slist_free_all(headerList);
+ // reset curl handle
+ qcurl_easy_reset(this->curlHandle);
+ return ret;
+}
+
+/**
+ * @brief HTTP GET method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::get(const std::string& url) {
+ return this->performCurlRequest(url);
+}
+/**
+ * @brief HTTP POST method
+ *
+ * @param url to query
+ * @param data HTTP POST body
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::post(const std::string& url,
+ const std::string& data) {
+ /** Now specify we want to POST data */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_POST, 1L);
+ /** set post fields */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDS, data.c_str());
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_POSTFIELDSIZE, data.size());
+
+ return this->performCurlRequest(url);
+}
+/**
+ * @brief HTTP PUT method
+ *
+ * @param url to query
+ * @param data HTTP PUT body
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::put(const std::string& url,
+ const std::string& data) {
+ /** initialize upload object */
+ RestClient::Helpers::UploadObject up_obj;
+ up_obj.data = data.c_str();
+ up_obj.length = data.size();
+
+ /** Now specify we want to PUT data */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_PUT, 1L);
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_UPLOAD, 1L);
+ /** set read callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_READFUNCTION,
+ RestClient::Helpers::read_callback);
+ /** set data object to pass to callback function */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_READDATA, &up_obj);
+ /** set data size */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_INFILESIZE,
+ static_cast<int64_t>(up_obj.length));
+
+ return this->performCurlRequest(url);
+}
+/**
+ * @brief HTTP DELETE method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response
+RestClient::Connection::del(const std::string& url) {
+ /** we want HTTP DELETE */
+ const char* http_delete = "DELETE";
+
+ /** set HTTP DELETE METHOD */
+ qcurl_easy_setopt(this->curlHandle, CURLOPT_CUSTOMREQUEST, http_delete);
+
+ return this->performCurlRequest(url);
+}
+
diff --git a/external/restclient/helpers.cpp b/external/restclient/helpers.cpp
new file mode 100644
index 0000000..7a99edc
--- /dev/null
+++ b/external/restclient/helpers.cpp
@@ -0,0 +1,96 @@
+/**
+ * @file helpers.cpp
+ * @brief implementation of the restclient helpers
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ */
+
+#include "restclient/helpers.h"
+
+#ifdef USE_LOCAL_HEADERS
+ #include "../libcurl-7.35.0/curl/curl.h"
+#else
+ #include <curl/curl.h>
+#endif
+
+#include <cstring>
+
+#include "restclient/restclient.h"
+
+/**
+ * @brief write callback function for libcurl
+ *
+ * @param data returned data of size (size*nmemb)
+ * @param size size parameter
+ * @param nmemb memblock parameter
+ * @param userdata pointer to user data to save/work with return data
+ *
+ * @return (size * nmemb)
+ */
+size_t RestClient::Helpers::write_callback(void *data, size_t size,
+ size_t nmemb, void *userdata) {
+ RestClient::Response* r;
+ r = reinterpret_cast<RestClient::Response*>(userdata);
+ r->body.append(reinterpret_cast<char*>(data), size*nmemb);
+
+ return (size * nmemb);
+}
+
+/**
+ * @brief header callback for libcurl
+ *
+ * @param data returned (header line)
+ * @param size of data
+ * @param nmemb memblock
+ * @param userdata pointer to user data object to save headr data
+ * @return size * nmemb;
+ */
+size_t RestClient::Helpers::header_callback(void *data, size_t size,
+ size_t nmemb, void *userdata) {
+ RestClient::Response* r;
+ r = reinterpret_cast<RestClient::Response*>(userdata);
+ std::string header(reinterpret_cast<char*>(data), size*nmemb);
+ size_t seperator = header.find_first_of(":");
+ if ( std::string::npos == seperator ) {
+ // roll with non seperated headers...
+ trim(header);
+ if (0 == header.length()) {
+ return (size * nmemb); // blank line;
+ }
+ r->headers[header] = "present";
+ } else {
+ std::string key = header.substr(0, seperator);
+ trim(key);
+ std::string value = header.substr(seperator + 1);
+ trim(value);
+ r->headers[key] = value;
+ }
+
+ return (size * nmemb);
+}
+
+/**
+ * @brief read callback function for libcurl
+ *
+ * @param data pointer of max size (size*nmemb) to write data to
+ * @param size size parameter
+ * @param nmemb memblock parameter
+ * @param userdata pointer to user data to read data from
+ *
+ * @return (size * nmemb)
+ */
+size_t RestClient::Helpers::read_callback(void *data, size_t size,
+ size_t nmemb, void *userdata) {
+ /** get upload struct */
+ RestClient::Helpers::UploadObject* u;
+ u = reinterpret_cast<RestClient::Helpers::UploadObject*>(userdata);
+ /** set correct sizes */
+ size_t curl_size = size * nmemb;
+ size_t copy_size = (u->length < curl_size) ? u->length : curl_size;
+ /** copy data to buffer */
+ std::memcpy(data, u->data, copy_size);
+ /** decrement length and increment data pointer */
+ u->length -= copy_size;
+ u->data += copy_size;
+ /** return copied size */
+ return copy_size;
+}
diff --git a/external/restclient/restclient.cpp b/external/restclient/restclient.cpp
new file mode 100644
index 0000000..0138c79
--- /dev/null
+++ b/external/restclient/restclient.cpp
@@ -0,0 +1,118 @@
+/**
+ * @file restclient.cpp
+ * @brief implementation of the restclient class
+ *
+ * This just provides static wrappers around the Connection class REST
+ * methods. However since I didn't want to have to pull in a whole URI parsing
+ * library just now, the Connection constructor is passed an empty string and
+ * the full URL is passed to the REST methods. All those methods to is
+ * concatenate them anyways. So this should do for now.
+ *
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ */
+
+#include "restclient/restclient.h"
+
+#include "../../src/client/cl_curl.h"
+#ifdef USE_LOCAL_HEADERS
+ #include "../libcurl-7.35.0/curl/curl.h"
+#else
+ #include <curl/curl.h>
+#endif
+
+#include "restclient/version.h"
+#include "restclient/connection.h"
+
+/**
+ * @brief global init function. Call this before you start any threads.
+ */
+int RestClient::init() {
+#ifdef USE_CURL_DLOPEN
+ CL_cURL_Init();
+#endif
+ CURLcode res = qcurl_global_init(CURL_GLOBAL_ALL);
+ if (res == CURLE_OK) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ * @brief global disable function. Call this before you terminate your
+ * program.
+ */
+void RestClient::disable() {
+ qcurl_global_cleanup();
+}
+
+/**
+ * @brief HTTP GET method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::get(const std::string& url) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ ret = conn->get(url);
+ delete conn;
+ return ret;
+}
+
+/**
+ * @brief HTTP POST method
+ *
+ * @param url to query
+ * @param ctype content type as string
+ * @param data HTTP POST body
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::post(const std::string& url,
+ const std::string& ctype,
+ const std::string& data) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ conn->AppendHeader("Content-Type", ctype);
+ ret = conn->post(url, data);
+ delete conn;
+ return ret;
+}
+
+/**
+ * @brief HTTP PUT method
+ *
+ * @param url to query
+ * @param ctype content type as string
+ * @param data HTTP PUT body
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::put(const std::string& url,
+ const std::string& ctype,
+ const std::string& data) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ conn->AppendHeader("Content-Type", ctype);
+ ret = conn->put(url, data);
+ delete conn;
+ return ret;
+}
+
+/**
+ * @brief HTTP DELETE method
+ *
+ * @param url to query
+ *
+ * @return response struct
+ */
+RestClient::Response RestClient::del(const std::string& url) {
+ RestClient::Response ret;
+ RestClient::Connection *conn = new RestClient::Connection("");
+ ret = conn->del(url);
+ delete conn;
+ return ret;
+}
+
diff --git a/external/restclient/restclient/connection.h b/external/restclient/restclient/connection.h
new file mode 100644
index 0000000..475b190
--- /dev/null
+++ b/external/restclient/restclient/connection.h
@@ -0,0 +1,169 @@
+/**
+ * @file connection.h
+ * @brief header definitions for restclient-cpp connection class
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ * @version
+ * @date 2010-10-11
+ */
+
+#ifndef INCLUDE_RESTCLIENT_CPP_CONNECTION_H_
+#define INCLUDE_RESTCLIENT_CPP_CONNECTION_H_
+
+#include <string>
+#include <map>
+#include <cstdlib>
+
+#include "restclient.h"
+#include "version.h"
+
+typedef void CURL;
+/**
+ * @brief namespace for all RestClient definitions
+ */
+namespace RestClient {
+
+/**
+ * @brief Connection object for advanced usage
+ */
+class Connection {
+ public:
+ /**
+ * @struct RequestInfo
+ * @brief holds some diagnostics information
+ * about a request
+ * @var RequestInfo::totalTime
+ * Member 'totalTime' contains the total time of the last request in
+ * seconds Total time of previous transfer. See CURLINFO_TOTAL_TIME
+ * @var RequestInfo::nameLookupTime
+ * Member 'nameLookupTime' contains the time spent in DNS lookup in
+ * seconds Time from start until name resolving completed. See
+ * CURLINFO_NAMELOOKUP_TIME
+ * @var RequestInfo::connectTime
+ * Member 'connectTime' contains the time it took until Time from start
+ * until remote host or proxy completed. See CURLINFO_CONNECT_TIME
+ * @var RequestInfo::appConnectTime
+ * Member 'appConnectTime' contains the time from start until SSL/SSH
+ * handshake completed. See CURLINFO_APPCONNECT_TIME
+ * @var RequestInfo::preTransferTime
+ * Member 'preTransferTime' contains the total time from start until
+ * just before the transfer begins. See CURLINFO_PRETRANSFER_TIME
+ * @var RequestInfo::startTransferTime
+ * Member 'startTransferTime' contains the total time from start until
+ * just when the first byte is received. See CURLINFO_STARTTRANSFER_TIME
+ * @var RequestInfo::redirectTime
+ * Member 'redirectTime' contains the total time taken for all redirect
+ * steps before the final transfer. See CURLINFO_REDIRECT_TIME
+ * @var RequestInfo::redirectCount
+ * Member 'redirectCount' contains the number of redirects followed. See
+ * CURLINFO_REDIRECT_COUNT
+ */
+ typedef struct {
+ double totalTime;
+ double nameLookupTime;
+ double connectTime;
+ double appConnectTime;
+ double preTransferTime;
+ double startTransferTime;
+ double redirectTime;
+ int redirectCount;
+ } RequestInfo;
+ /**
+ * @struct Info
+ * @brief holds some diagnostics information
+ * about the connection object it came from
+ * @var Info::baseUrl
+ * Member 'baseUrl' contains the base URL for the connection object
+ * @var Info::headers
+ * Member 'headers' contains the HeaderFields map
+ * @var Info::timeout
+ * Member 'timeout' contains the configured timeout
+ * @var Info::followRedirects
+ * Member 'followRedirects' contains whether or not to follow redirects
+ * @var Info::basicAuth
+ * Member 'basicAuth' contains information about basic auth
+ * @var basicAuth::username
+ * Member 'username' contains the basic auth username
+ * @var basicAuth::password
+ * Member 'password' contains the basic auth password
+ * @var Info::customUserAgent
+ * Member 'customUserAgent' contains the custom user agent
+ * @var Info::lastRequest
+ * Member 'lastRequest' contains metrics about the last request
+ */
+ typedef struct {
+ std::string baseUrl;
+ RestClient::HeaderFields headers;
+ int timeout;
+ bool followRedirects;
+ struct {
+ std::string username;
+ std::string password;
+ } basicAuth;
+ std::string customUserAgent;
+ RequestInfo lastRequest;
+ } Info;
+
+
+ explicit Connection(const std::string baseUrl);
+ ~Connection();
+
+ // Instance configuration methods
+ // configure basic auth
+ void SetBasicAuth(const std::string& username,
+ const std::string& password);
+
+ // set connection timeout to seconds
+ void SetTimeout(int seconds);
+
+ // set whether to follow redirects
+ void FollowRedirects(bool follow);
+
+ // set custom user agent
+ // (this will result in the UA "foo/cool restclient-cpp/VERSION")
+ void SetUserAgent(const std::string& userAgent);
+
+ // set the Certificate Authority (CA) Info which is the path to file holding
+ // certificates to be used to verify peers. See CURLOPT_CAINFO
+ void SetCAInfoFilePath(const std::string& caInfoFilePath);
+
+ std::string GetUserAgent();
+
+ RestClient::Connection::Info GetInfo();
+
+ // set headers
+ void SetHeaders(RestClient::HeaderFields headers);
+
+ // get headers
+ RestClient::HeaderFields GetHeaders();
+
+ // append additional headers
+ void AppendHeader(const std::string& key,
+ const std::string& value);
+
+
+ // Basic HTTP verb methods
+ RestClient::Response get(const std::string& uri);
+ RestClient::Response post(const std::string& uri,
+ const std::string& data);
+ RestClient::Response put(const std::string& uri,
+ const std::string& data);
+ RestClient::Response del(const std::string& uri);
+
+ private:
+ CURL* curlHandle;
+ std::string baseUrl;
+ RestClient::HeaderFields headerFields;
+ int timeout;
+ bool followRedirects;
+ struct {
+ std::string username;
+ std::string password;
+ } basicAuth;
+ std::string customUserAgent;
+ std::string caInfoFilePath;
+ RequestInfo lastRequest;
+ RestClient::Response performCurlRequest(const std::string& uri);
+};
+}; // namespace RestClient
+
+#endif // INCLUDE_RESTCLIENT_CPP_CONNECTION_H_
diff --git a/external/restclient/restclient/helpers.h b/external/restclient/restclient/helpers.h
new file mode 100644
index 0000000..8695a41
--- /dev/null
+++ b/external/restclient/restclient/helpers.h
@@ -0,0 +1,74 @@
+/**
+ * @file helpers.h
+ * @brief header file for restclient-cpp helpers
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ * @version
+ * @date 2010-10-11
+ */
+
+#ifndef INCLUDE_RESTCLIENT_CPP_HELPERS_H_
+#define INCLUDE_RESTCLIENT_CPP_HELPERS_H_
+
+#include <string>
+#include <algorithm>
+#include <functional>
+
+#include "version.h"
+
+/**
+ * @brief namespace for all RestClient definitions
+ */
+namespace RestClient {
+
+/**
+ * @brief: namespace for all helper functions
+ */
+namespace Helpers {
+
+ /** @struct UploadObject
+ * @brief This structure represents the payload to upload on POST
+ * requests
+ * @var UploadObject::data
+ * Member 'data' contains the data to upload
+ * @var UploadObject::length
+ * Member 'length' contains the length of the data to upload
+ */
+ typedef struct {
+ const char* data;
+ size_t length;
+ } UploadObject;
+
+ // writedata callback function
+ size_t write_callback(void *ptr, size_t size, size_t nmemb,
+ void *userdata);
+
+ // header callback function
+ size_t header_callback(void *ptr, size_t size, size_t nmemb,
+ void *userdata);
+ // read callback function
+ size_t read_callback(void *ptr, size_t size, size_t nmemb,
+ void *userdata);
+
+ // trim from start
+ static inline std::string &ltrim(std::string &s) { // NOLINT
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))));
+ return s;
+ }
+
+ // trim from end
+ static inline std::string &rtrim(std::string &s) { // NOLINT
+ s.erase(std::find_if(s.rbegin(), s.rend(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
+ return s;
+ }
+
+ // trim from both ends
+ static inline std::string &trim(std::string &s) { // NOLINT
+ return ltrim(rtrim(s));
+ }
+}; // namespace Helpers
+
+}; // namespace RestClient
+
+#endif // INCLUDE_RESTCLIENT_CPP_HELPERS_H_
diff --git a/external/restclient/restclient/restclient.h b/external/restclient/restclient/restclient.h
new file mode 100644
index 0000000..d6fa77c
--- /dev/null
+++ b/external/restclient/restclient/restclient.h
@@ -0,0 +1,63 @@
+/**
+ * @file restclient.h
+ * @brief libcurl wrapper for REST calls
+ * @author Daniel Schauenberg <d@unwiredcouch.com>
+ * @version
+ * @date 2010-10-11
+ */
+
+#ifndef INCLUDE_RESTCLIENT_CPP_RESTCLIENT_H_
+#define INCLUDE_RESTCLIENT_CPP_RESTCLIENT_H_
+
+#include <string>
+#include <map>
+#include <cstdlib>
+
+#include "version.h"
+
+/**
+ * @brief namespace for all RestClient definitions
+ */
+namespace RestClient {
+
+/**
+ * public data definitions
+ */
+typedef std::map<std::string, std::string> HeaderFields;
+
+/** @struct Response
+ * @brief This structure represents the HTTP response data
+ * @var Response::code
+ * Member 'code' contains the HTTP response code
+ * @var Response::body
+ * Member 'body' contains the HTTP response body
+ * @var Response::headers
+ * Member 'headers' contains the HTTP response headers
+ */
+typedef struct {
+ int code;
+ std::string body;
+ HeaderFields headers;
+} Response;
+
+// init and disable functions
+int init();
+void disable();
+
+/**
+ * public methods for the simple API. These don't allow a lot of
+ * configuration but are meant for simple HTTP calls.
+ *
+ */
+Response get(const std::string& url);
+Response post(const std::string& url,
+ const std::string& content_type,
+ const std::string& data);
+Response put(const std::string& url,
+ const std::string& content_type,
+ const std::string& data);
+Response del(const std::string& url);
+
+}; // namespace RestClient
+
+#endif // INCLUDE_RESTCLIENT_CPP_RESTCLIENT_H_
diff --git a/external/restclient/restclient/version.h b/external/restclient/restclient/version.h
new file mode 100644
index 0000000..a1c4bd6
--- /dev/null
+++ b/external/restclient/restclient/version.h
@@ -0,0 +1,4 @@
+#ifndef INCLUDE_RESTCLIENT_CPP_VERSION_H_
+#define INCLUDE_RESTCLIENT_CPP_VERSION_H_
+#define RESTCLIENT_VERSION "0.4.4-dirty"
+#endif // INCLUDE_RESTCLIENT_CPP_VERSION_H_