diff --git a/example/rest_book_async_client/main.cc b/example/rest_book_async_client/main.cc index 266f41f..c3761f6 100644 --- a/example/rest_book_async_client/main.cc +++ b/example/rest_book_async_client/main.cc @@ -2,8 +2,8 @@ #include "json/json.h" -#include "webcc/rest_async_client.h" #include "webcc/logger.h" +#include "webcc/rest_async_client.h" // ----------------------------------------------------------------------------- @@ -50,7 +50,7 @@ class BookListClient { // ----------------------------------------------------------------------------- class BookDetailClient { -public: + public: BookDetailClient(boost::asio::io_context& io_context, const std::string& host, const std::string& port) : rest_client_(io_context, host, port) { @@ -83,7 +83,7 @@ public: rest_client_.Delete("/book/" + id, handler); } -private: + private: webcc::RestAsyncClient rest_client_; }; @@ -112,8 +112,7 @@ int main(int argc, char* argv[]) { BookDetailClient detail_client(io_context, host, port); // Response handler. - auto handler = [](std::shared_ptr response, - webcc::Error error, + auto handler = [](webcc::HttpResponsePtr response, webcc::Error error, bool timed_out) { if (error == webcc::kNoError) { std::cout << response->content() << std::endl; diff --git a/example/soap_book_client/book_client.cc b/example/soap_book_client/book_client.cc index c997c43..8871dfa 100644 --- a/example/soap_book_client/book_client.cc +++ b/example/soap_book_client/book_client.cc @@ -23,7 +23,8 @@ BookClient::BookClient(const std::string& host, const std::string& port) soap_client_.set_indent_str(" "); } -bool BookClient::CreateBook(const std::string& title, double price, std::string* id) { +bool BookClient::CreateBook(const std::string& title, double price, + std::string* id) { PrintSeparateLine(); std::cout << "CreateBook: " << title << ", " << price << std::endl; @@ -91,7 +92,8 @@ bool BookClient::Call0(const std::string& operation, std::string* result_str) { } -bool BookClient::Call1(const std::string& operation, webcc::SoapParameter&& parameter, +bool BookClient::Call1(const std::string& operation, + webcc::SoapParameter&& parameter, std::string* result_str) { std::vector parameters{ { std::move(parameter) } diff --git a/webcc/CMakeLists.txt b/webcc/CMakeLists.txt index 08b44b4..2d8b5cc 100644 --- a/webcc/CMakeLists.txt +++ b/webcc/CMakeLists.txt @@ -65,6 +65,7 @@ endif() if(WEBCC_ENABLE_SOAP) set(SOAP_HEADERS + soap_async_client.h soap_client.h soap_message.h soap_parameter.h @@ -77,6 +78,7 @@ if(WEBCC_ENABLE_SOAP) ) set(SOAP_SOURCES + soap_async_client.cc soap_client.cc soap_message.cc soap_response.cc diff --git a/webcc/http_async_client.h b/webcc/http_async_client.h index 6526af9..ba43199 100644 --- a/webcc/http_async_client.h +++ b/webcc/http_async_client.h @@ -16,7 +16,7 @@ namespace webcc { -// Request handler/callback. +// Response handler/callback. typedef std::function HttpResponseHandler; class HttpAsyncClient : public std::enable_shared_from_this { diff --git a/webcc/rest_async_client.cc b/webcc/rest_async_client.cc index 5dfb680..ac97c2d 100644 --- a/webcc/rest_async_client.cc +++ b/webcc/rest_async_client.cc @@ -12,8 +12,6 @@ void RestAsyncClient::Request(const std::string& method, const std::string& url, std::string&& content, HttpResponseHandler response_handler) { - response_handler_ = response_handler; - HttpRequestPtr request(new webcc::HttpRequest()); request->set_method(method); @@ -33,7 +31,7 @@ void RestAsyncClient::Request(const std::string& method, http_client->set_timeout_seconds(timeout_seconds_); } - http_client->Request(request, response_handler_); + http_client->Request(request, response_handler); } } // namespace webcc diff --git a/webcc/rest_async_client.h b/webcc/rest_async_client.h index 7d05994..b3525e8 100644 --- a/webcc/rest_async_client.h +++ b/webcc/rest_async_client.h @@ -51,8 +51,6 @@ class RestAsyncClient { std::string host_; std::string port_; - HttpResponseHandler response_handler_; - // Timeout in seconds; only effective when > 0. int timeout_seconds_; }; diff --git a/webcc/rest_client.h b/webcc/rest_client.h index 68dcecf..2e0f383 100644 --- a/webcc/rest_client.h +++ b/webcc/rest_client.h @@ -24,21 +24,7 @@ class RestClient { timeout_seconds_ = timeout_seconds; } - HttpResponsePtr response() const { return 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 timed_out_; } - - Error error() const { return error_; } + // Requests inline bool Get(const std::string& url) { return Request(kHttpGet, url, ""); @@ -60,6 +46,24 @@ class RestClient { return Request(kHttpDelete, url, ""); } + // Response & Result + + HttpResponsePtr response() const { return 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 timed_out_; } + + Error error() const { return error_; } + private: bool Request(const std::string& method, const std::string& url, std::string&& content); diff --git a/webcc/soap_async_client.cc b/webcc/soap_async_client.cc new file mode 100644 index 0000000..0545b02 --- /dev/null +++ b/webcc/soap_async_client.cc @@ -0,0 +1,91 @@ +#include "webcc/soap_async_client.h" + +#include +#include // for move() + +#include "webcc/http_async_client.h" +#include "webcc/soap_request.h" +#include "webcc/soap_response.h" + +namespace webcc { + +SoapAsyncClient::SoapAsyncClient(boost::asio::io_context& io_context, + const std::string& host, + const std::string& port) + : io_context_(io_context), + host_(host), port_(port), + soapenv_ns_(kSoapEnvNamespace), + format_raw_(true), timeout_seconds_(0) { + 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); + } + } +} + +void SoapAsyncClient::Request(const std::string& operation, + std::vector&& parameters, + SoapResponseHandler soap_response_handler) { + assert(service_ns_.IsValid()); + assert(!url_.empty() && !host_.empty()); + assert(!result_name_.empty()); + + SoapRequest soap_request; + + soap_request.set_soapenv_ns(soapenv_ns_); + soap_request.set_service_ns(service_ns_); + + soap_request.set_operation(operation); + + for (SoapParameter& p : parameters) { + soap_request.AddParameter(std::move(p)); + } + + std::string http_content; + soap_request.ToXml(format_raw_, indent_str_, &http_content); + + HttpRequestPtr http_request; + + http_request->set_method(kHttpPost); + http_request->set_url(url_); + http_request->SetContent(std::move(http_content), true); + http_request->SetContentType(kTextXmlUtf8); + http_request->SetHost(host_, port_); + http_request->SetHeader(kSoapAction, operation); + http_request->UpdateStartLine(); + + HttpAsyncClientPtr http_client(new HttpAsyncClient(io_context_)); + + if (timeout_seconds_ > 0) { + http_client->set_timeout_seconds(timeout_seconds_); + } + + auto http_response_handler = std::bind(&SoapAsyncClient::ResponseHandler, + this, soap_response_handler, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3); + + http_client->Request(http_request, http_response_handler); +} + +void SoapAsyncClient::ResponseHandler(SoapResponseHandler soap_response_handler, + HttpResponsePtr http_response, + Error error, bool timed_out) { + if (error != kNoError) { + soap_response_handler("", error, timed_out); + } else { + SoapResponse soap_response; + soap_response.set_result_name(result_name_); + + if (!soap_response.FromXml(http_response->content())) { + soap_response_handler("", kXmlError, false); + } else { + soap_response_handler(soap_response.result_moved(), kNoError, false); + } + } +} + +} // namespace webcc diff --git a/webcc/soap_async_client.h b/webcc/soap_async_client.h new file mode 100644 index 0000000..1d1451a --- /dev/null +++ b/webcc/soap_async_client.h @@ -0,0 +1,85 @@ +#ifndef WEBCC_SOAP_ASYNC_CLIENT_H_ +#define WEBCC_SOAP_ASYNC_CLIENT_H_ + +#include +#include +#include + +#include "webcc/http_async_client.h" +#include "webcc/soap_message.h" +#include "webcc/soap_parameter.h" + +namespace webcc { + +// Response handler/callback. +typedef std::function SoapResponseHandler; + +class SoapAsyncClient { + public: + // If |port| is empty, |host| will be checked to see if it contains port or + // not (separated by ':'). + SoapAsyncClient(boost::asio::io_context& io_context, // NOLINT + const std::string& host, const std::string& port = ""); + + ~SoapAsyncClient() = default; + + DELETE_COPY_AND_ASSIGN(SoapAsyncClient); + + void set_timeout_seconds(int timeout_seconds) { + timeout_seconds_ = timeout_seconds; + } + + void set_url(const std::string& url) { url_ = url; } + + void set_service_ns(const SoapNamespace& service_ns) { + service_ns_ = service_ns; + } + + void set_result_name(const std::string& result_name) { + result_name_ = result_name; + } + + void set_format_raw(bool format_raw) { format_raw_ = format_raw; } + + void set_indent_str(const std::string& indent_str) { + indent_str_ = indent_str; + } + + void Request(const std::string& operation, + std::vector&& parameters, + SoapResponseHandler soap_response_handler); + + private: + void ResponseHandler(SoapResponseHandler soap_response_handler, + HttpResponsePtr http_response, + Error error, bool timed_out); + + boost::asio::io_context& io_context_; + + std::string host_; + std::string port_; // Leave this empty to use default 80. + + // Request URL. + std::string url_; + + SoapNamespace soapenv_ns_; // SOAP envelope namespace. + SoapNamespace service_ns_; // Namespace for your web service. + + // Response result XML node name. + // E.g., "Result". + std::string result_name_; + + // Format request XML without any indentation or line breaks. + bool format_raw_; + + // Indent string for request XML. + // Applicable when |format_raw_| is false. + std::string indent_str_; + + // Timeout in seconds; only effective when > 0. + int timeout_seconds_; +}; + +} // namespace webcc + +#endif // WEBCC_SOAP_ASYNC_CLIENT_H_ diff --git a/webcc/soap_client.cc b/webcc/soap_client.cc index ea89f3b..5dfd283 100644 --- a/webcc/soap_client.cc +++ b/webcc/soap_client.cc @@ -4,8 +4,6 @@ #include // for move() #include "webcc/http_client.h" -#include "webcc/http_request.h" -#include "webcc/http_response.h" #include "webcc/soap_request.h" #include "webcc/soap_response.h" diff --git a/webcc/soap_client.h b/webcc/soap_client.h index d69506b..c90d431 100644 --- a/webcc/soap_client.h +++ b/webcc/soap_client.h @@ -39,14 +39,14 @@ class SoapClient { indent_str_ = indent_str; } - bool timed_out() const { return timed_out_; } - - Error error() const { return error_; } - bool Request(const std::string& operation, std::vector&& parameters, std::string* result); + bool timed_out() const { return timed_out_; } + + Error error() const { return error_; } + private: std::string host_; std::string port_; // Leave this empty to use default 80.