Skip to content

Commit

Permalink
Started porting CurlClient
Browse files Browse the repository at this point in the history
  • Loading branch information
cinemast committed Jul 6, 2018
1 parent c458b64 commit c22eb55
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 29 deletions.
3 changes: 2 additions & 1 deletion .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"includePath": [
"${workspaceFolder}/src",
"${workspaceFolder}/src/test",
"C:\\vcpkg\\installed\\x86-windows\\include"
"C:\\vcpkg\\installed\\x86-windows\\include",
"C:\\vcpkg\\installed\\x64-windows\\include"
],
"defines": [
"_DEBUG",
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)

option(COMPILE_TESTS "compile with testing support" ON)
option(JSONRPC_SERVER "jsonrpc server" ON)
option(JSONRPC_CLIENT "jsonrpc client" ON)
option(CONNECTOR_MICROHTTPD "libmicrohttpd based server connector" ON)
option(CONNECTOR_CURL "libcurl based client connector" ON)

include(GNUInstallDirs)

Expand All @@ -35,4 +38,7 @@ if(CONNECTOR_MICROHTTPD)
add_subdirectory(src/connector/microhttpd)
endif()

if(CONNECTOR_CURL)
add_subdirectory(src/connector/curl)
endif()

2 changes: 1 addition & 1 deletion src/connector/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
install(FILES iclientconnectionhandler.h abstractserverconnector.h
install(FILES iclientconnectionhandler.h abstractserverconnector.h iclientconnector.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/jsonrpccpp/connector
)

Expand Down
17 changes: 17 additions & 0 deletions src/connector/curl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
find_package(CURL REQUIRED)

add_library(jsonrpccpp-connector-curl curlclient.h curlclient.cpp)
target_link_libraries(jsonrpccpp-connector-curl ${CURL_LIBRARIES})

set_target_properties(jsonrpccpp-connector-curl PROPERTIES
PUBLIC_HEADER "curlclient.h"
SOVERSION ${SO_VERSION}
VERSION ${VERSION_STRING}
)

install(TARGETS jsonrpccpp-connector-curl
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/jsonrpccpp/connector/curl
)
77 changes: 77 additions & 0 deletions src/connector/curl/curlclient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@

#include "curlclient.h"
#include <curl/curl.h>
#include <sstream>
#include <string>
#include "../../exception.h"

using namespace jsonrpc;
using namespace std;

// Rationale, see here: http://curl.haxx.se/libcurl/c/curl_global_init.html
class curl_initializer {
public:
curl_initializer() { curl_global_init(CURL_GLOBAL_ALL); }
~curl_initializer() { curl_global_cleanup(); }
};
static curl_initializer _curl_init = curl_initializer();

CurlClient::CurlClient(const string &url, long timeout, bool verifyTLS)
: url(url), timeout(timeout), verifyTLS(verifyTLS) {
this->AddHeader("Content-Type", "application/json");
this->AddHeader("charsets", "utf-8");
}

size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp) {
((std::string *)userp)->append((char *)contents, size * nmemb);
return size * nmemb;
}

string CurlClient::SendRPCMessage(const string &message) {
CURL *curl = curl_easy_init();
string response = "";

struct curl_slist *headers = NULL;
for (auto header : this->headers) {
headers = curl_slist_append(headers, (header.first + ": " + header.second).c_str());
}

curl_easy_setopt(curl, CURLOPT_URL, this->url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, message.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

if (!this->verifyTLS) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
}

CURLcode res = curl_easy_perform(curl);
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);

curl_slist_free_all(headers);
curl_easy_cleanup(curl);

if (res == 7) {
throw JsonRpcException(ExceptionCode::ERROR_CLIENT_CONNECTOR, "Could not connect to " + this->url);
} else if (res == 28) {
throw JsonRpcException(ExceptionCode::ERROR_CLIENT_CONNECTOR, "Operation timed out " + this->url);
} else if (res != CURLE_OK) {
stringstream message;
message << "Unkown libcurl error " << res << ": " << curl_easy_strerror(res);
throw JsonRpcException(ExceptionCode::ERROR_CLIENT_CONNECTOR, message.str());
} else if (http_code != 200) {
stringstream message;
message << "Received HTTP status code " << http_code << ": " << response;
throw JsonRpcException(ExceptionCode::ERROR_CLIENT_CONNECTOR, message.str());
}

return response;
}

void CurlClient::AddHeader(const std::string &attr, const std::string &val) { this->headers[attr] = val; }

void CurlClient::RemoveHeader(const std::string &attr) { this->headers.erase(attr); }
26 changes: 26 additions & 0 deletions src/connector/curl/curlclient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#pragma once

#include <map>
#include "../iclientconnector.h"

namespace jsonrpc {
class CurlClient : public IClientConnector {
public:
/**
* @param timeout - timeout in milliseconds, if zero, no timeout is set
*/
CurlClient(const std::string &url, long timeout = 0, bool verifyTLS = true);
virtual std::string SendRPCMessage(const std::string &message);

void setTLSVerification(bool enabled);

void AddHeader(const std::string &attr, const std::string &val);
void RemoveHeader(const std::string &attr);

private:
std::map<std::string, std::string> headers;
std::string url;
long timeout;
bool verifyTLS;
};
}
11 changes: 11 additions & 0 deletions src/connector/iclientconnector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <string>

namespace jsonrpc {
class IClientConnector {
public:
virtual ~IClientConnector() {}
virtual std::string SendRPCMessage(const std::string& message) = 0;
};
}
24 changes: 24 additions & 0 deletions src/exception.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once

#include <exception>
#include <sstream>
#include <string>

namespace jsonrpc {
enum ExceptionCode { ERROR_CLIENT_CONNECTOR = -32003 };

class JsonRpcException : public std::exception {
public:
JsonRpcException(int code, const std::string& message) : code(code) {
std::stringstream str;
str << "JsonRpcException " << code << ": " << message;
this->message = str.str();
}

virtual const char* what() const throw() { return message.c_str(); }

private:
int code;
std::string message;
};
}
52 changes: 25 additions & 27 deletions src/jsonrpccpp/common/exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,35 @@
#ifndef JSONRPC_CPP_EXCEPTION_H_
#define JSONRPC_CPP_EXCEPTION_H_

#include <string>
#include <sstream>
#include <exception>
#include <sstream>
#include <string>

#include "errors.h"

namespace jsonrpc
{
class JsonRpcException: public std::exception
{
public:
JsonRpcException(int code);
JsonRpcException(int code, const std::string& message);
JsonRpcException(int code, const std::string& message, const Json::Value &data);
JsonRpcException(const std::string& message);

virtual ~JsonRpcException() throw ();

int GetCode() const;
const std::string& GetMessage() const;
const Json::Value& GetData() const;

virtual const char* what() const throw ();

private:
int code;
std::string message;
std::string whatString;
Json::Value data;
void setWhatMessage();
};
namespace jsonrpc {
class JsonRpcException : public std::exception {
public:
JsonRpcException(int code);
JsonRpcException(int code, const std::string& message);
JsonRpcException(int code, const std::string& message, const Json::Value& data);
JsonRpcException(const std::string& message);

virtual ~JsonRpcException() throw();

int GetCode() const;
const std::string& GetMessage() const;
const Json::Value& GetData() const;

virtual const char* what() const throw();

private:
int code;
std::string message;
std::string whatString;
Json::Value data;
void setWhatMessage();
};

} /* namespace jsonrpc */
#endif /* JSONRPC_CPP_EXCEPTION_H_ */

0 comments on commit c22eb55

Please sign in to comment.