diff --git a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp index 767a2131..1bbe0721 100644 --- a/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp +++ b/libraries/plugins/peerplays_sidechain/common/rpc_client.cpp @@ -1,10 +1,15 @@ #include +#include #include #include +#include +#include +#include #include #include +#include #include @@ -18,6 +23,35 @@ rpc_client::rpc_client(std::string _url, std::string _user, std::string _passwor password(_password), debug_rpc_calls(_debug_rpc_calls), request_id(0) { + + std::string reg_expr = "^((?Phttps|http):\\/\\/)?(?P[a-zA-Z0-9\\-\\.]+)(:(?P\\d{1,5}))?(?P\\/.+)?"; + boost::xpressive::sregex sr = boost::xpressive::sregex::compile(reg_expr); + + boost::xpressive::smatch sm; + + if (boost::xpressive::regex_search(url, sm, sr)) { + protocol = sm["Protocol"]; + if (protocol.empty()) { + protocol = "http"; + } + + host = sm["Host"]; + if (host.empty()) { + host + "localhost"; + } + + port = sm["Port"]; + if (port.empty()) { + port = "80"; + } + + target = sm["Target"]; + if (target.empty()) { + target = "/"; + } + } else { + elog("Invalid URL: ${url}", ("url", url)); + } } std::string rpc_client::retrieve_array_value_from_reply(std::string reply_str, std::string array_path, uint32_t idx) { @@ -98,57 +132,65 @@ std::string rpc_client::send_post_request(std::string method, std::string params return ""; } -static size_t write_callback(char *ptr, size_t size, size_t nmemb, rpc_reply *reply) { - size_t retval = 0; - if (reply != nullptr) { - reply->body.append(ptr, size * nmemb); - retval = size * nmemb; - } - return retval; -} - rpc_reply rpc_client::send_post_request(std::string body, bool show_log) { - struct curl_slist *headers = nullptr; - headers = curl_slist_append(headers, "Accept: application/json"); - headers = curl_slist_append(headers, "Content-Type: application/json"); - headers = curl_slist_append(headers, "charset: utf-8"); + // The io_context is required for all I/O + boost::beast::net::io_context ioc; - CURL *curl = curl_easy_init(); + // These objects perform our I/O + boost::beast::net::ip::tcp::resolver resolver(ioc); + boost::beast::tcp_stream stream(ioc); - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - if (url.find("https://", 0) == 0) { - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false); - } + // Look up the domain name + auto const results = resolver.resolve(host, port); - if (!user.empty()) { - curl_easy_setopt(curl, CURLOPT_USERNAME, user.c_str()); - curl_easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); - } + // Make the connection on the IP address we get from a lookup + stream.connect(results); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); + // Set up an HTTP GET request message + boost::beast::http::request req{boost::beast::http::verb::post, target, 11}; + req.set(boost::beast::http::field::host, host + ":" + port); + req.set(boost::beast::http::field::accept, "application/json"); + req.set(boost::beast::http::field::content_type, "application/json"); + req.set(boost::beast::http::field::content_encoding, "utf-8"); + req.set(boost::beast::http::field::content_length, body.length()); + req.body() = body; - //curl_easy_setopt(curl, CURLOPT_VERBOSE, true); + // Send the HTTP request to the remote host + boost::beast::http::write(stream, req); + // This buffer is used for reading and must be persisted + boost::beast::flat_buffer buffer; + + // Declare a container to hold the response + boost::beast::http::response res; + + // Receive the HTTP response + boost::beast::http::read(stream, buffer, res); + + //// Write the message to standard out + //std::cout << res << std::endl; + + // Gracefully close the socket + boost::beast::error_code ec; + stream.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + + // not_connected happens sometimes + // so don't bother reporting it. + // + if (ec && ec != boost::beast::errc::not_connected) + throw boost::beast::system_error{ec}; + + std::string rbody{boost::asio::buffers_begin(res.body().data()), + boost::asio::buffers_end(res.body().data())}; rpc_reply reply; - - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &reply); - - curl_easy_perform(curl); - - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &reply.status); - - curl_easy_cleanup(curl); - curl_slist_free_all(headers); + reply.status = 200; + reply.body = rbody; if (show_log) { ilog("### Request URL: ${url}", ("url", url)); ilog("### Request: ${body}", ("body", body)); - std::stringstream ss(std::string(reply.body.begin(), reply.body.end())); - ilog("### Response: ${ss}", ("ss", ss.str())); + ilog("### Response: ${rbody}", ("rbody", rbody)); } return reply; diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp index 11d715ba..c7cc8921 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/common/rpc_client.hpp @@ -20,6 +20,11 @@ protected: std::string send_post_request(std::string method, std::string params, bool show_log); std::string url; + std::string protocol; + std::string host; + std::string port; + std::string target; + std::string user; std::string password; bool debug_rpc_calls;