Use HttpClient as member variable inside RestClient and SoapClient.

master
Chunting Gu 7 years ago
parent d2e2935f9d
commit 921defc0e3

@ -29,7 +29,7 @@ class BookClientBase {
BookClientBase(const std::string& host, const std::string& port, BookClientBase(const std::string& host, const std::string& port,
int timeout_seconds) int timeout_seconds)
: rest_client_(host, port) { : rest_client_(host, port) {
rest_client_.set_timeout_seconds(timeout_seconds); rest_client_.SetTimeout(timeout_seconds);
} }
virtual ~BookClientBase() = default; virtual ~BookClientBase() = default;

@ -4,6 +4,7 @@
#include <functional> #include <functional>
#include <string> #include <string>
#include "pugixml/pugixml.hpp"
#include "webcc/soap_client.h" #include "webcc/soap_client.h"
#include "example/common/book.h" #include "example/common/book.h"

@ -9,7 +9,7 @@ class CalcClient {
public: public:
CalcClient(const std::string& host, const std::string& port) CalcClient(const std::string& host, const std::string& port)
: soap_client_(host, port) { : soap_client_(host, port) {
soap_client_.set_timeout_seconds(5); soap_client_.SetTimeout(5);
soap_client_.set_url("/calculator"); soap_client_.set_url("/calculator");
soap_client_.set_service_ns({ soap_client_.set_service_ns({

@ -9,7 +9,7 @@ class CalcClient {
public: public:
CalcClient(const std::string& host, const std::string& port) CalcClient(const std::string& host, const std::string& port)
: soap_client_(host, port) { : soap_client_(host, port) {
soap_client_.set_timeout_seconds(5); soap_client_.SetTimeout(5);
soap_client_.set_url("/glue/calculator"); soap_client_.set_url("/glue/calculator");
soap_client_.set_service_ns({ soap_client_.set_service_ns({

@ -11,7 +11,7 @@ namespace webcc {
HttpAsyncClient::HttpAsyncClient(boost::asio::io_context& io_context) HttpAsyncClient::HttpAsyncClient(boost::asio::io_context& io_context)
: socket_(io_context), : socket_(io_context),
resolver_(new tcp::resolver(io_context)), resolver_(io_context),
buffer_(kBufferSize), buffer_(kBufferSize),
deadline_(io_context), deadline_(io_context),
timeout_seconds_(kMaxReadSeconds), timeout_seconds_(kMaxReadSeconds),
@ -34,11 +34,11 @@ void HttpAsyncClient::Request(std::shared_ptr<HttpRequest> request,
request_ = request; request_ = request;
response_handler_ = response_handler; response_handler_ = response_handler;
resolver_->async_resolve(tcp::v4(), request->host(), request->port(kHttpPort), resolver_.async_resolve(tcp::v4(), request->host(), request->port(kHttpPort),
std::bind(&HttpAsyncClient::ResolveHandler, std::bind(&HttpAsyncClient::ResolveHandler,
shared_from_this(), shared_from_this(),
std::placeholders::_1, std::placeholders::_1,
std::placeholders::_2)); std::placeholders::_2));
} }
void HttpAsyncClient::Stop() { void HttpAsyncClient::Stop() {
@ -65,11 +65,8 @@ void HttpAsyncClient::ResolveHandler(boost::system::error_code ec,
request_->host().c_str(), request_->port().c_str()); request_->host().c_str(), request_->port().c_str());
response_handler_(response_, kHostResolveError, timed_out_); response_handler_(response_, kHostResolveError, timed_out_);
} else { } else {
// Start the connect actor.
endpoints_ = endpoints;
// ConnectHandler: void(boost::system::error_code, tcp::endpoint) // ConnectHandler: void(boost::system::error_code, tcp::endpoint)
boost::asio::async_connect(socket_, endpoints_, boost::asio::async_connect(socket_, endpoints,
std::bind(&HttpAsyncClient::ConnectHandler, std::bind(&HttpAsyncClient::ConnectHandler,
shared_from_this(), shared_from_this(),
std::placeholders::_1, std::placeholders::_1,

@ -19,6 +19,10 @@ namespace webcc {
// Response handler/callback. // Response handler/callback.
typedef std::function<void(HttpResponsePtr, Error, bool)> HttpResponseHandler; typedef std::function<void(HttpResponsePtr, Error, bool)> HttpResponseHandler;
// HTTP client session in asynchronous mode.
// A request will return without waiting for the response, the callback handler
// will be invoked when the response is received or timeout occurs.
// Don't use the same HttpAsyncClient object in multiple threads.
class HttpAsyncClient : public std::enable_shared_from_this<HttpAsyncClient> { class HttpAsyncClient : public std::enable_shared_from_this<HttpAsyncClient> {
public: public:
explicit HttpAsyncClient(boost::asio::io_context& io_context); explicit HttpAsyncClient(boost::asio::io_context& io_context);
@ -55,9 +59,8 @@ class HttpAsyncClient : public std::enable_shared_from_this<HttpAsyncClient> {
void AsyncWaitDeadline(); void AsyncWaitDeadline();
void DeadlineHandler(boost::system::error_code ec); void DeadlineHandler(boost::system::error_code ec);
tcp::resolver resolver_;
tcp::socket socket_; tcp::socket socket_;
std::unique_ptr<tcp::resolver> resolver_;
tcp::resolver::results_type endpoints_;
std::shared_ptr<HttpRequest> request_; std::shared_ptr<HttpRequest> request_;
std::vector<char> buffer_; std::vector<char> buffer_;

@ -27,11 +27,19 @@ HttpClient::HttpClient()
error_(kNoError) { error_(kNoError) {
} }
void HttpClient::SetTimeout(int seconds) {
if (seconds > 0) {
timeout_seconds_ = seconds;
}
}
bool HttpClient::Request(const HttpRequest& request) { bool HttpClient::Request(const HttpRequest& request) {
response_.reset(new HttpResponse()); response_.reset(new HttpResponse());
response_parser_.reset(new HttpResponseParser(response_.get())); response_parser_.reset(new HttpResponseParser(response_.get()));
stopped_ = timed_out_ = false; stopped_ = false;
timed_out_ = false;
error_ = kNoError;
if ((error_ = Connect(request)) != kNoError) { if ((error_ = Connect(request)) != kNoError) {
return false; return false;

@ -16,6 +16,9 @@
namespace webcc { namespace webcc {
// HTTP client session in synchronous mode.
// A request will not return until the response is received or timeout occurs.
// Don't use the same HttpClient object in multiple threads.
class HttpClient { class HttpClient {
public: public:
HttpClient(); HttpClient();
@ -23,10 +26,9 @@ class HttpClient {
DELETE_COPY_AND_ASSIGN(HttpClient); DELETE_COPY_AND_ASSIGN(HttpClient);
void set_timeout_seconds(int timeout_seconds) { // Set the timeout seconds for reading response.
assert(timeout_seconds > 0); // The |seconds| is only effective when greater than 0.
timeout_seconds_ = timeout_seconds; void SetTimeout(int seconds);
}
// Connect to server, send request, wait until response is received. // Connect to server, send request, wait until response is received.
bool Request(const HttpRequest& request); bool Request(const HttpRequest& request);

@ -1,14 +1,11 @@
#include "webcc/rest_client.h" #include "webcc/rest_client.h"
#include "webcc/http_client.h"
#include "webcc/http_request.h" #include "webcc/http_request.h"
namespace webcc { namespace webcc {
RestClient::RestClient(const std::string& host, const std::string& port) RestClient::RestClient(const std::string& host, const std::string& port)
: host_(host), port_(port), : host_(host), port_(port) {
timeout_seconds_(0), timed_out_(false),
error_(kNoError) {
if (port_.empty()) { if (port_.empty()) {
std::size_t i = host_.find_last_of(':'); std::size_t i = host_.find_last_of(':');
if (i != std::string::npos) { if (i != std::string::npos) {
@ -20,11 +17,6 @@ RestClient::RestClient(const std::string& host, const std::string& port)
bool RestClient::Request(const std::string& method, const std::string& url, bool RestClient::Request(const std::string& method, const std::string& url,
std::string&& content) { std::string&& content) {
response_.reset();
error_ = kNoError;
timed_out_ = false;
HttpRequest http_request; HttpRequest http_request;
http_request.set_method(method); http_request.set_method(method);
@ -38,19 +30,10 @@ bool RestClient::Request(const std::string& method, const std::string& url,
http_request.UpdateStartLine(); http_request.UpdateStartLine();
HttpClient http_client; if (!http_client_.Request(http_request)) {
if (timeout_seconds_ > 0) {
http_client.set_timeout_seconds(timeout_seconds_);
}
if (!http_client.Request(http_request)) {
error_ = http_client.error();
timed_out_ = http_client.timed_out();
return false; return false;
} }
response_ = http_client.response();
return true; return true;
} }

@ -6,6 +6,7 @@
#include <utility> // for move() #include <utility> // for move()
#include "webcc/globals.h" #include "webcc/globals.h"
#include "webcc/http_client.h"
#include "webcc/http_response.h" #include "webcc/http_response.h"
namespace webcc { namespace webcc {
@ -14,20 +15,23 @@ class RestClient {
public: public:
// If |port| is empty, |host| will be checked to see if it contains port or // If |port| is empty, |host| will be checked to see if it contains port or
// not (separated by ':'). // not (separated by ':').
RestClient(const std::string& host, const std::string& port = ""); explicit RestClient(const std::string& host, const std::string& port = "");
~RestClient() = default; ~RestClient() = default;
DELETE_COPY_AND_ASSIGN(RestClient); DELETE_COPY_AND_ASSIGN(RestClient);
void set_timeout_seconds(int timeout_seconds) { void SetTimeout(int seconds) {
timeout_seconds_ = timeout_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. // HTTP GET request.
// The return value indicates if the socket communication is successful
// or not. If it's failed, check error() and timed_out() for more details.
// For HTTP status, check response_status() instead.
inline bool Get(const std::string& url) { inline bool Get(const std::string& url) {
return Request(kHttpGet, url, ""); return Request(kHttpGet, url, "");
} }
@ -52,21 +56,27 @@ class RestClient {
return Request(kHttpDelete, url, ""); return Request(kHttpDelete, url, "");
} }
HttpResponsePtr response() const { return response_; } HttpResponsePtr response() const {
return http_client_.response();
}
int response_status() const { int response_status() const {
assert(response_); assert(response());
return response_->status(); return response()->status();
} }
const std::string& response_content() const { const std::string& response_content() const {
assert(response_); assert(response());
return response_->content(); return response()->content();
} }
bool timed_out() const { return timed_out_; } bool timed_out() const {
return http_client_.timed_out();
}
Error error() const { return error_; } Error error() const {
return http_client_.error();
}
private: private:
bool Request(const std::string& method, const std::string& url, bool Request(const std::string& method, const std::string& url,
@ -75,15 +85,7 @@ class RestClient {
std::string host_; std::string host_;
std::string port_; std::string port_;
// Timeout in seconds; only effective when > 0. HttpClient http_client_;
int timeout_seconds_;
HttpResponsePtr response_;
// If the error was caused by timeout or not.
bool timed_out_;
Error error_;
}; };
} // namespace webcc } // namespace webcc

@ -3,8 +3,6 @@
#include <cassert> #include <cassert>
#include <utility> // for move() #include <utility> // for move()
#include "webcc/http_client.h"
#include "webcc/soap_globals.h"
#include "webcc/soap_request.h" #include "webcc/soap_request.h"
#include "webcc/soap_response.h" #include "webcc/soap_response.h"
@ -13,8 +11,7 @@ namespace webcc {
SoapClient::SoapClient(const std::string& host, const std::string& port) SoapClient::SoapClient(const std::string& host, const std::string& port)
: host_(host), port_(port), : host_(host), port_(port),
soapenv_ns_(kSoapEnvNamespace), soapenv_ns_(kSoapEnvNamespace),
format_raw_(true), timeout_seconds_(0), timed_out_(false), format_raw_(true), error_(kNoError) {
error_(kNoError) {
if (port_.empty()) { if (port_.empty()) {
std::size_t i = host_.find_last_of(':'); std::size_t i = host_.find_last_of(':');
if (i != std::string::npos) { if (i != std::string::npos) {
@ -31,6 +28,8 @@ bool SoapClient::Request(const std::string& operation,
assert(!url_.empty() && !host_.empty()); assert(!url_.empty() && !host_.empty());
assert(!result_name_.empty()); assert(!result_name_.empty());
error_ = kNoError;
SoapRequest soap_request; SoapRequest soap_request;
soap_request.set_soapenv_ns(soapenv_ns_); soap_request.set_soapenv_ns(soapenv_ns_);
@ -55,22 +54,15 @@ bool SoapClient::Request(const std::string& operation,
http_request.SetHeader(kSoapAction, operation); http_request.SetHeader(kSoapAction, operation);
http_request.UpdateStartLine(); http_request.UpdateStartLine();
HttpClient http_client; if (!http_client_.Request(http_request)) {
error_ = http_client_.error();
if (timeout_seconds_ > 0) {
http_client.set_timeout_seconds(timeout_seconds_);
}
if (!http_client.Request(http_request)) {
error_ = http_client.error();
timed_out_ = http_client.timed_out();
return false; return false;
} }
SoapResponse soap_response; SoapResponse soap_response;
soap_response.set_result_name(result_name_); soap_response.set_result_name(result_name_);
if (!soap_response.FromXml(http_client.response()->content())) { if (!soap_response.FromXml(http_client_.response()->content())) {
error_ = kXmlError; error_ = kXmlError;
return false; return false;
} }

@ -4,7 +4,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "webcc/soap_message.h" #include "webcc/http_client.h"
#include "webcc/soap_globals.h"
#include "webcc/soap_parameter.h" #include "webcc/soap_parameter.h"
namespace webcc { namespace webcc {
@ -13,14 +14,14 @@ class SoapClient {
public: public:
// If |port| is empty, |host| will be checked to see if it contains port or // If |port| is empty, |host| will be checked to see if it contains port or
// not (separated by ':'). // not (separated by ':').
SoapClient(const std::string& host, const std::string& port = ""); explicit SoapClient(const std::string& host, const std::string& port = "");
~SoapClient() = default; ~SoapClient() = default;
DELETE_COPY_AND_ASSIGN(SoapClient); DELETE_COPY_AND_ASSIGN(SoapClient);
void set_timeout_seconds(int timeout_seconds) { void SetTimeout(int seconds) {
timeout_seconds_ = timeout_seconds; http_client_.SetTimeout(seconds);
} }
void set_url(const std::string& url) { url_ = url; } void set_url(const std::string& url) { url_ = url; }
@ -33,7 +34,9 @@ class SoapClient {
result_name_ = result_name; result_name_ = result_name;
} }
void set_format_raw(bool format_raw) { format_raw_ = format_raw; } void set_format_raw(bool format_raw) {
format_raw_ = format_raw;
}
void set_indent_str(const std::string& indent_str) { void set_indent_str(const std::string& indent_str) {
indent_str_ = indent_str; indent_str_ = indent_str;
@ -43,7 +46,9 @@ class SoapClient {
std::vector<SoapParameter>&& parameters, std::vector<SoapParameter>&& parameters,
std::string* result); std::string* result);
bool timed_out() const { return timed_out_; } bool timed_out() const {
return http_client_.timed_out();
}
Error error() const { return error_; } Error error() const { return error_; }
@ -68,11 +73,7 @@ class SoapClient {
// Applicable when |format_raw_| is false. // Applicable when |format_raw_| is false.
std::string indent_str_; std::string indent_str_;
// Timeout in seconds; only effective when > 0. HttpClient http_client_;
int timeout_seconds_;
// If the error was caused by timeout or not.
bool timed_out_;
Error error_; Error error_;
}; };

@ -10,4 +10,9 @@ const std::string kSoapAction = "SOAPAction";
// See: https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L26854 // See: https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L26854
const std::string kTextXmlUtf8 = "text/xml; charset=utf-8"; const std::string kTextXmlUtf8 = "text/xml; charset=utf-8";
const SoapNamespace kSoapEnvNamespace{
"soap",
"http://schemas.xmlsoap.org/soap/envelope/"
};
} // namespace webcc } // namespace webcc

@ -12,6 +12,22 @@ extern const std::string kSoapAction;
extern const std::string kTextXmlUtf8; extern const std::string kTextXmlUtf8;
// -----------------------------------------------------------------------------
// XML namespace name/url pair.
// E.g., { "soap", "http://schemas.xmlsoap.org/soap/envelope/" }
struct SoapNamespace {
std::string name;
std::string url;
bool IsValid() const {
return !name.empty() && !url.empty();
}
};
// CSoap's default namespace for SOAP Envelope.
extern const SoapNamespace kSoapEnvNamespace;
} // namespace webcc } // namespace webcc
#endif // WEBCC_SOAP_GLOBALS_H_ #endif // WEBCC_SOAP_GLOBALS_H_

@ -6,11 +6,6 @@
namespace webcc { namespace webcc {
const SoapNamespace kSoapEnvNamespace{
"soap",
"http://schemas.xmlsoap.org/soap/envelope/"
};
void SoapMessage::ToXml(bool format_raw, const std::string& indent, void SoapMessage::ToXml(bool format_raw, const std::string& indent,
std::string* xml_string) { std::string* xml_string) {
assert(soapenv_ns_.IsValid() && service_ns_.IsValid() && !operation_.empty()); assert(soapenv_ns_.IsValid() && service_ns_.IsValid() && !operation_.empty());

@ -5,28 +5,14 @@
#include "pugixml/pugixml.hpp" #include "pugixml/pugixml.hpp"
#include "webcc/globals.h" #include "webcc/soap_globals.h"
namespace webcc { namespace webcc {
// XML namespace name/url pair.
// E.g., { "soap", "http://schemas.xmlsoap.org/soap/envelope/" }
struct SoapNamespace {
std::string name;
std::string url;
bool IsValid() const {
return !name.empty() && !url.empty();
}
};
// CSoap's default namespace for SOAP Envelope.
extern const SoapNamespace kSoapEnvNamespace;
// Base class for SOAP request and response. // Base class for SOAP request and response.
class SoapMessage { class SoapMessage {
public: public:
virtual ~SoapMessage() {} virtual ~SoapMessage() = default;
// E.g., set as kSoapEnvNamespace. // E.g., set as kSoapEnvNamespace.
void set_soapenv_ns(const SoapNamespace& soapenv_ns) { void set_soapenv_ns(const SoapNamespace& soapenv_ns) {

Loading…
Cancel
Save