From ae9d4efcf1641c003044bfd14ee30527134c5bdd Mon Sep 17 00:00:00 2001 From: Chunting Gu Date: Fri, 1 Feb 2019 14:50:06 +0800 Subject: [PATCH] Abdandon the template RestBasicClient. --- example/http_ssl_client/main.cc | 6 +- webcc/CMakeLists.txt | 3 +- webcc/http_ssl_client.cc | 11 +-- webcc/http_ssl_client.h | 16 +++-- webcc/rest_basic_client.h | 123 -------------------------------- webcc/rest_client.cc | 38 ++++++++++ webcc/rest_client.h | 81 ++++++++++++++++++++- webcc/rest_ssl_client.cc | 39 ++++++++++ webcc/rest_ssl_client.h | 83 ++++++++++++++++++++- 9 files changed, 258 insertions(+), 142 deletions(-) delete mode 100644 webcc/rest_basic_client.h create mode 100644 webcc/rest_client.cc create mode 100644 webcc/rest_ssl_client.cc diff --git a/example/http_ssl_client/main.cc b/example/http_ssl_client/main.cc index ed204a2..a9b67d7 100644 --- a/example/http_ssl_client/main.cc +++ b/example/http_ssl_client/main.cc @@ -27,13 +27,13 @@ int main(int argc, char* argv[]) { request.set_host(host); // Leave port to default value. request.Make(); - webcc::HttpSslClient client; - // Verify the certificate of the peer or not. // See HttpSslClient::Request() for more details. bool ssl_verify = false; - if (client.Request(request, ssl_verify)) { + webcc::HttpSslClient client(ssl_verify); + + if (client.Request(request)) { std::cout << client.response()->content() << std::endl; } else { std::cout << webcc::DescribeError(client.error()); diff --git a/webcc/CMakeLists.txt b/webcc/CMakeLists.txt index 32b032d..af684e3 100644 --- a/webcc/CMakeLists.txt +++ b/webcc/CMakeLists.txt @@ -29,7 +29,6 @@ set(HEADERS logger.h queue.h rest_async_client.h - rest_basic_client.h rest_client.h rest_request_handler.h rest_server.h @@ -55,6 +54,7 @@ set(SOURCES http_server.cc logger.cc rest_async_client.cc + rest_client.cc rest_request_handler.cc rest_service_manager.cc rest_service.cc @@ -70,6 +70,7 @@ if(WEBCC_ENABLE_SSL) set(SOURCES ${SOURCES} http_ssl_client.cc + rest_ssl_client.cc ) endif() diff --git a/webcc/http_ssl_client.cc b/webcc/http_ssl_client.cc index 8ae7ef9..5f3c728 100644 --- a/webcc/http_ssl_client.cc +++ b/webcc/http_ssl_client.cc @@ -15,11 +15,12 @@ namespace ssl = boost::asio::ssl; namespace webcc { -HttpSslClient::HttpSslClient() +HttpSslClient::HttpSslClient(bool ssl_verify) : ssl_context_(ssl::context::sslv23), ssl_socket_(io_context_, ssl_context_), buffer_(kBufferSize), deadline_(io_context_), + ssl_verify_(ssl_verify), timeout_seconds_(kMaxReadSeconds), stopped_(false), timed_out_(false), @@ -34,7 +35,7 @@ void HttpSslClient::SetTimeout(int seconds) { } } -bool HttpSslClient::Request(const HttpRequest& request, bool ssl_verify) { +bool HttpSslClient::Request(const HttpRequest& request) { io_context_.restart(); response_.reset(new HttpResponse()); @@ -48,7 +49,7 @@ bool HttpSslClient::Request(const HttpRequest& request, bool ssl_verify) { return false; } - if ((error_ = Handshake(request.host(), ssl_verify)) != kNoError) { + if ((error_ = Handshake(request.host())) != kNoError) { return false; } @@ -95,8 +96,8 @@ Error HttpSslClient::Connect(const HttpRequest& request) { } // NOTE: Don't check timeout. It doesn't make much sense. -Error HttpSslClient::Handshake(const std::string& host, bool ssl_verify) { - if (ssl_verify) { +Error HttpSslClient::Handshake(const std::string& host) { + if (ssl_verify_) { ssl_socket_.set_verify_mode(ssl::verify_peer); } else { ssl_socket_.set_verify_mode(ssl::verify_none); diff --git a/webcc/http_ssl_client.h b/webcc/http_ssl_client.h index a2827d4..6d1d269 100644 --- a/webcc/http_ssl_client.h +++ b/webcc/http_ssl_client.h @@ -23,7 +23,11 @@ namespace webcc { // Don't use the same HttpClient object in multiple threads. class HttpSslClient { public: - HttpSslClient(); + // NOTE: + // SSL verification (ssl_verify=true) needs CA certificates to be found + // in the default verify paths of OpenSSL. On Windows, it means you need to + // set environment variable SSL_CERT_FILE properly. + HttpSslClient(bool ssl_verify = true); ~HttpSslClient() = default; @@ -34,10 +38,7 @@ class HttpSslClient { void SetTimeout(int seconds); // Connect to server, send request, wait until response is received. - // NOTE: SSL verification (ssl_verify=true) needs CA certificates to be found - // in the default verify paths of OpenSSL. On Windows, it means you need to - // set environment variable SSL_CERT_FILE properly. - bool Request(const HttpRequest& request, bool ssl_verify = true); + bool Request(const HttpRequest& request); HttpResponsePtr response() const { return response_; } @@ -48,7 +49,7 @@ class HttpSslClient { private: Error Connect(const HttpRequest& request); - Error Handshake(const std::string& host, bool ssl_verify); + Error Handshake(const std::string& host); Error SendReqeust(const HttpRequest& request); @@ -73,6 +74,9 @@ class HttpSslClient { boost::asio::deadline_timer deadline_; + // Verify the certificate of the peer (remote server) or not. + bool ssl_verify_; + // Maximum seconds to wait before the client cancels the operation. // Only for receiving response from server. int timeout_seconds_; diff --git a/webcc/rest_basic_client.h b/webcc/rest_basic_client.h deleted file mode 100644 index bafb6ee..0000000 --- a/webcc/rest_basic_client.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef WEBCC_REST_BASIC_CLIENT_H_ -#define WEBCC_REST_BASIC_CLIENT_H_ - -#include -#include -#include // for move() - -#include "webcc/globals.h" -#include "webcc/http_request.h" -#include "webcc/http_response.h" - -namespace webcc { - -template -class RestBasicClient { - public: - // If |port| is empty, |host| will be checked to see if it contains port or - // not (separated by ':'). - explicit RestBasicClient(const std::string& host, - const std::string& port = "") - : host_(host), port_(port) { - if (port_.empty()) { - std::size_t i = host_.find_last_of(':'); - if (i != std::string::npos) { - port_ = host_.substr(i + 1); - host_ = host_.substr(0, i); - } - } - } - - ~RestBasicClient() = default; - - WEBCC_DELETE_COPY_ASSIGN(RestBasicClient); - - void SetTimeout(int seconds) { - http_client_.SetTimeout(seconds); - } - - // NOTE: - // The return value of the following methods (Get, Post, etc.) only indicates - // if the socket communication is successful or not. Check error() and - // timed_out() for more information if it's failed. Check response_status() - // instead for the HTTP status code. - - // HTTP GET request. - inline bool Get(const std::string& url) { - return Request(kHttpGet, url, ""); - } - - // HTTP POST request. - inline bool Post(const std::string& url, std::string&& content) { - return Request(kHttpPost, url, std::move(content)); - } - - // HTTP PUT request. - inline bool Put(const std::string& url, std::string&& content) { - return Request(kHttpPut, url, std::move(content)); - } - - // HTTP PATCH request. - inline bool Patch(const std::string& url, std::string&& content) { - return Request(kHttpPatch, url, std::move(content)); - } - - // HTTP DELETE request. - inline bool Delete(const std::string& url) { - return Request(kHttpDelete, url, ""); - } - - HttpResponsePtr response() const { - return http_client_.response(); - } - - int response_status() const { - assert(response()); - return response()->status(); - } - - const std::string& response_content() const { - assert(response()); - return response()->content(); - } - - bool timed_out() const { - return http_client_.timed_out(); - } - - Error error() const { - return http_client_.error(); - } - - private: - bool Request(const std::string& method, const std::string& url, - std::string&& content) { - HttpRequest http_request; - - http_request.set_method(method); - http_request.set_url(url); - http_request.set_host(host_, port_); - - if (!content.empty()) { - http_request.SetContent(std::move(content), true); - http_request.SetContentType(kAppJsonUtf8); - } - - http_request.Make(); - - if (!http_client_.Request(http_request)) { - return false; - } - - return true; - } - - std::string host_; - std::string port_; - - HttpClientType http_client_; -}; - -} // namespace webcc - -#endif // WEBCC_REST_BASIC_CLIENT_H_ diff --git a/webcc/rest_client.cc b/webcc/rest_client.cc new file mode 100644 index 0000000..a93c117 --- /dev/null +++ b/webcc/rest_client.cc @@ -0,0 +1,38 @@ +#include "webcc/rest_client.h" + +namespace webcc { + +RestClient::RestClient(const std::string& host, const std::string& port) + : host_(host), port_(port) { + if (port_.empty()) { + std::size_t i = host_.find_last_of(':'); + if (i != std::string::npos) { + port_ = host_.substr(i + 1); + host_ = host_.substr(0, i); + } + } +} + +bool RestClient::Request(const std::string& method, const std::string& url, + std::string&& content) { + HttpRequest http_request; + + http_request.set_method(method); + http_request.set_url(url); + http_request.set_host(host_, port_); + + if (!content.empty()) { + http_request.SetContent(std::move(content), true); + http_request.SetContentType(kAppJsonUtf8); + } + + http_request.Make(); + + if (!http_client_.Request(http_request)) { + return false; + } + + return true; +} + +} // namespace webcc diff --git a/webcc/rest_client.h b/webcc/rest_client.h index 4f7630b..7b5afc5 100644 --- a/webcc/rest_client.h +++ b/webcc/rest_client.h @@ -1,12 +1,89 @@ #ifndef WEBCC_REST_CLIENT_H_ #define WEBCC_REST_CLIENT_H_ -#include "webcc/rest_basic_client.h" +#include +#include +#include // for move() + +#include "webcc/globals.h" #include "webcc/http_client.h" +#include "webcc/http_request.h" +#include "webcc/http_response.h" namespace webcc { -typedef RestBasicClient RestClient; +class RestClient { + public: + // If |port| is empty, |host| will be checked to see if it contains port or + // not (separated by ':'). + explicit RestClient(const std::string& host, + const std::string& port = ""); + + ~RestClient() = default; + + WEBCC_DELETE_COPY_ASSIGN(RestClient); + + void SetTimeout(int seconds) { + http_client_.SetTimeout(seconds); + } + + // NOTE: + // The return value of the following methods (Get, Post, etc.) only indicates + // if the socket communication is successful or not. Check error() and + // timed_out() for more information if it's failed. Check response_status() + // instead for the HTTP status code. + + inline bool Get(const std::string& url) { + return Request(kHttpGet, url, ""); + } + + inline bool Post(const std::string& url, std::string&& content) { + return Request(kHttpPost, url, std::move(content)); + } + + inline bool Put(const std::string& url, std::string&& content) { + return Request(kHttpPut, url, std::move(content)); + } + + inline bool Patch(const std::string& url, std::string&& content) { + return Request(kHttpPatch, url, std::move(content)); + } + + inline bool Delete(const std::string& url) { + return Request(kHttpDelete, url, ""); + } + + HttpResponsePtr response() const { + return http_client_.response(); + } + + int response_status() const { + assert(response()); + return response()->status(); + } + + const std::string& response_content() const { + assert(response()); + return response()->content(); + } + + bool timed_out() const { + return http_client_.timed_out(); + } + + Error error() const { + return http_client_.error(); + } + + private: + bool Request(const std::string& method, const std::string& url, + std::string&& content); + + std::string host_; + std::string port_; + + HttpClient http_client_; +}; } // namespace webcc diff --git a/webcc/rest_ssl_client.cc b/webcc/rest_ssl_client.cc new file mode 100644 index 0000000..91f4519 --- /dev/null +++ b/webcc/rest_ssl_client.cc @@ -0,0 +1,39 @@ +#include "webcc/rest_ssl_client.h" + +namespace webcc { + +RestSslClient::RestSslClient(const std::string& host, const std::string& port, + bool ssl_verify) + : host_(host), port_(port), http_client_(ssl_verify) { + if (port_.empty()) { + std::size_t i = host_.find_last_of(':'); + if (i != std::string::npos) { + port_ = host_.substr(i + 1); + host_ = host_.substr(0, i); + } + } +} + +bool RestSslClient::Request(const std::string& method, const std::string& url, + std::string&& content) { + HttpRequest http_request; + + http_request.set_method(method); + http_request.set_url(url); + http_request.set_host(host_, port_); + + if (!content.empty()) { + http_request.SetContent(std::move(content), true); + http_request.SetContentType(kAppJsonUtf8); + } + + http_request.Make(); + + if (!http_client_.Request(http_request)) { + return false; + } + + return true; +} + +} // namespace webcc diff --git a/webcc/rest_ssl_client.h b/webcc/rest_ssl_client.h index 9181a83..559592d 100644 --- a/webcc/rest_ssl_client.h +++ b/webcc/rest_ssl_client.h @@ -1,12 +1,91 @@ #ifndef WEBCC_REST_SSL_CLIENT_H_ #define WEBCC_REST_SSL_CLIENT_H_ -#include "webcc/rest_basic_client.h" +#include +#include +#include // for move() + +#include "webcc/globals.h" +#include "webcc/http_request.h" +#include "webcc/http_response.h" #include "webcc/http_ssl_client.h" namespace webcc { -typedef RestBasicClient RestSslClient; +class RestSslClient { + public: + // If |port| is empty, |host| will be checked to see if it contains port or + // not (separated by ':'). + explicit RestSslClient(const std::string& host, + const std::string& port = "", + bool ssl_verify = true); + + ~RestSslClient() = default; + + WEBCC_DELETE_COPY_ASSIGN(RestSslClient); + + void SetTimeout(int seconds) { + http_client_.SetTimeout(seconds); + } + + // NOTE: + // The return value of the following methods (Get, Post, etc.) only indicates + // if the socket communication is successful or not. Check error() and + // timed_out() for more information if it's failed. Check response_status() + // instead for the HTTP status code. + + inline bool Get(const std::string& url) { + return Request(kHttpGet, url, ""); + } + + inline bool Post(const std::string& url, std::string&& content) { + return Request(kHttpPost, url, std::move(content)); + } + + inline bool Put(const std::string& url, std::string&& content) { + return Request(kHttpPut, url, std::move(content)); + } + + inline bool Patch(const std::string& url, std::string&& content) { + return Request(kHttpPatch, url, std::move(content)); + } + + inline bool Delete(const std::string& url) { + return Request(kHttpDelete, url, ""); + } + + HttpResponsePtr response() const { + return http_client_.response(); + } + + int response_status() const { + assert(response()); + return response()->status(); + } + + const std::string& response_content() const { + assert(response()); + return response()->content(); + } + + bool timed_out() const { + return http_client_.timed_out(); + } + + Error error() const { + return http_client_.error(); + } + +private: + bool Request(const std::string& method, + const std::string& url, + std::string&& content); + + std::string host_; + std::string port_; + + HttpSslClient http_client_; +}; } // namespace webcc