Cleanup async client APIs.

This commit is contained in:
Chunting Gu
2019-03-07 16:02:49 +08:00
parent ffa0794926
commit 31d0ea3c9d
74 changed files with 267 additions and 2106 deletions
-12
View File
@@ -15,8 +15,6 @@ include(GNUInstallDirs)
set(HEADERS
globals.h
# http_async_client_base.h
# http_async_client.h
http_client_base.h
http_client.h
http_client_session.h
@@ -31,7 +29,6 @@ set(HEADERS
http_response_parser.h
http_server.h
http_ssl_client.h
# http_ssl_async_client.h
queue.h
url.h
utility.h
@@ -40,8 +37,6 @@ set(HEADERS
set(SOURCES
globals.cc
# http_async_client_base.cc
# http_async_client.cc
http_client_base.cc
http_client.cc
http_client_session.cc
@@ -55,7 +50,6 @@ set(SOURCES
http_response_parser.cc
http_server.cc
http_ssl_client.cc
# http_ssl_async_client.cc
logger.cc
url.cc
utility.cc
@@ -63,16 +57,12 @@ set(SOURCES
if(WEBCC_ENABLE_REST)
set(REST_HEADERS
# rest_async_client.h
# rest_client.h
rest_request_handler.h
rest_server.h
rest_service.h
rest_service_manager.h
)
set(REST_SOURCES
# rest_async_client.cc
# rest_client.cc
rest_request_handler.cc
rest_service_manager.cc
rest_service.cc
@@ -84,7 +74,6 @@ endif()
if(WEBCC_ENABLE_SOAP)
set(SOAP_HEADERS
# soap_async_client.h
soap_client.h
soap_globals.h
soap_message.h
@@ -98,7 +87,6 @@ if(WEBCC_ENABLE_SOAP)
)
set(SOAP_SOURCES
# soap_async_client.cc
soap_client.cc
soap_globals.cc
soap_message.cc
-35
View File
@@ -1,35 +0,0 @@
#include "webcc/http_async_client.h"
#include "boost/asio/connect.hpp"
#include "boost/asio/read.hpp"
#include "boost/asio/write.hpp"
#include "webcc/logger.h"
#include "webcc/utility.h"
namespace webcc {
HttpAsyncClient::HttpAsyncClient(boost::asio::io_context& io_context,
std::size_t buffer_size)
: HttpAsyncClientBase(io_context, buffer_size),
socket_(io_context) {
}
void HttpAsyncClient::SocketAsyncConnect(const Endpoints& endpoints,
ConnectHandler&& handler) {
boost::asio::async_connect(socket_, endpoints, std::move(handler));
}
void HttpAsyncClient::SocketAsyncWrite(WriteHandler&& handler) {
boost::asio::async_write(socket_, request_->ToBuffers(), std::move(handler));
}
void HttpAsyncClient::SocketAsyncReadSome(ReadHandler&& handler) {
socket_.async_read_some(boost::asio::buffer(buffer_), std::move(handler));
}
void HttpAsyncClient::SocketClose(boost::system::error_code* ec) {
socket_.close(*ec);
}
} // namespace webcc
-51
View File
@@ -1,51 +0,0 @@
#ifndef WEBCC_HTTP_ASYNC_CLIENT_H_
#define WEBCC_HTTP_ASYNC_CLIENT_H_
#include "webcc/http_async_client_base.h"
namespace webcc {
class HttpAsyncClient;
typedef std::shared_ptr<HttpAsyncClient> HttpAsyncClientPtr;
// HTTP asynchronous client.
class HttpAsyncClient : public HttpAsyncClientBase {
public:
~HttpAsyncClient() = default;
// Forbid to create HttpAsyncClient in stack since it's derived from
// std::shared_from_this.
static HttpAsyncClientPtr New(boost::asio::io_context& io_context,
std::size_t buffer_size = 0) {
return HttpAsyncClientPtr{
new HttpAsyncClient(io_context, buffer_size)
};
}
private:
explicit HttpAsyncClient(boost::asio::io_context& io_context,
std::size_t buffer_size = 0);
void Resolve() final {
DoResolve(kHttpPort);
}
void OnConnected() final {
DoWrite();
}
void SocketAsyncConnect(const Endpoints& endpoints,
ConnectHandler&& handler) final;
void SocketAsyncWrite(WriteHandler&& handler) final;
void SocketAsyncReadSome(ReadHandler&& handler) final;
void SocketClose(boost::system::error_code* ec) final;
tcp::socket socket_;
};
} // namespace webcc
#endif // WEBCC_HTTP_ASYNC_CLIENT_H_
-236
View File
@@ -1,236 +0,0 @@
#include "webcc/http_async_client_base.h"
#include "boost/asio/connect.hpp"
#include "boost/asio/read.hpp"
#include "boost/asio/write.hpp"
#include "webcc/logger.h"
#include "webcc/utility.h"
namespace webcc {
HttpAsyncClientBase::HttpAsyncClientBase(boost::asio::io_context& io_context,
std::size_t buffer_size)
: resolver_(io_context),
buffer_(buffer_size == 0 ? kBufferSize : buffer_size),
deadline_(io_context),
timeout_seconds_(kMaxReadSeconds),
stopped_(false),
timed_out_(false) {
}
void HttpAsyncClientBase::SetTimeout(int seconds) {
if (seconds > 0) {
timeout_seconds_ = seconds;
}
}
void HttpAsyncClientBase::Request(std::shared_ptr<HttpRequest> request,
HttpResponseCallback response_callback) {
assert(request);
assert(response_callback);
response_.reset(new HttpResponse());
response_parser_.reset(new HttpResponseParser(response_.get()));
stopped_ = false;
timed_out_ = false;
LOG_VERB("HTTP request:\n%s", request->Dump(4, "> ").c_str());
request_ = request;
response_callback_ = response_callback;
DoResolve(kHttpSslPort);
}
void HttpAsyncClientBase::Stop() {
LOG_INFO("The user asks to cancel the request.");
DoStop();
}
void HttpAsyncClientBase::DoResolve(const std::string& default_port) {
auto handler = std::bind(&HttpAsyncClientBase::OnResolve, shared_from_this(),
std::placeholders::_1, std::placeholders::_2);
resolver_.async_resolve(tcp::v4(), request_->host(),
request_->port(default_port), handler);
}
void HttpAsyncClientBase::OnResolve(boost::system::error_code ec,
tcp::resolver::results_type endpoints) {
if (ec) {
LOG_ERRO("Host resolve error (%s): %s, %s.", ec.message().c_str(),
request_->host().c_str(), request_->port().c_str());
response_callback_(response_, kHostResolveError, timed_out_);
} else {
LOG_VERB("Host resolved.");
DoConnect(endpoints);
}
}
void HttpAsyncClientBase::DoConnect(const Endpoints& endpoints) {
auto handler = std::bind(&HttpAsyncClientBase::OnConnect,
shared_from_this(),
std::placeholders::_1, std::placeholders::_2);
SocketAsyncConnect(endpoints, std::move(handler));
}
void HttpAsyncClientBase::OnConnect(boost::system::error_code ec,
tcp::endpoint endpoint) {
if (ec) {
LOG_ERRO("Socket connect error (%s).", ec.message().c_str());
DoStop();
response_callback_(response_, kEndpointConnectError, timed_out_);
return;
}
LOG_VERB("Socket connected.");
// Even though the connect operation notionally succeeded, the user could
// have stopped the operation by calling Stop(). And if we started the
// deadline timer, it could also be stopped due to timeout.
if (stopped_) {
// TODO: Use some other error.
response_callback_(response_, kEndpointConnectError, timed_out_);
return;
}
// Connection established.
OnConnected();
}
void HttpAsyncClientBase::DoWrite() {
// NOTE:
// It doesn't make much sense to set a timeout for socket write.
// I find that it's almost impossible to simulate a situation in the server
// side to test this timeout.
SocketAsyncWrite(std::bind(&HttpAsyncClientBase::OnWrite, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
}
void HttpAsyncClientBase::OnWrite(boost::system::error_code ec,
std::size_t /*length*/) {
if (stopped_) {
// TODO: Use some other error.
response_callback_(response_, kSocketWriteError, timed_out_);
return;
}
if (ec) {
LOG_ERRO("Socket write error (%s).", ec.message().c_str());
DoStop();
response_callback_(response_, kSocketWriteError, timed_out_);
} else {
LOG_INFO("Request sent.");
LOG_VERB("Read response (timeout: %ds)...", timeout_seconds_);
deadline_.expires_from_now(boost::posix_time::seconds(timeout_seconds_));
DoWaitDeadline();
DoRead();
}
}
void HttpAsyncClientBase::DoRead() {
auto handler = std::bind(&HttpAsyncClientBase::OnRead, shared_from_this(),
std::placeholders::_1, std::placeholders::_2);
SocketAsyncReadSome(std::move(handler));
}
void HttpAsyncClientBase::OnRead(boost::system::error_code ec,
std::size_t length) {
LOG_VERB("Socket async read handler.");
if (ec || length == 0) {
DoStop();
LOG_ERRO("Socket read error (%s).", ec.message().c_str());
response_callback_(response_, kSocketReadError, timed_out_);
return;
}
LOG_INFO("Read data, length: %u.", length);
// Parse the response piece just read.
// If the content has been fully received, |finished()| will be true.
if (!response_parser_->Parse(buffer_.data(), length)) {
DoStop();
LOG_ERRO("Failed to parse HTTP response.");
response_callback_(response_, kHttpError, timed_out_);
return;
}
if (response_parser_->finished()) {
DoStop();
LOG_INFO("Finished to read and parse HTTP response.");
LOG_VERB("HTTP response:\n%s", response_->Dump(4, "> ").c_str());
response_callback_(response_, kNoError, timed_out_);
return;
}
if (!stopped_) {
DoRead();
}
}
void HttpAsyncClientBase::DoWaitDeadline() {
deadline_.async_wait(std::bind(&HttpAsyncClientBase::OnDeadline,
shared_from_this(), std::placeholders::_1));
}
void HttpAsyncClientBase::OnDeadline(boost::system::error_code ec) {
if (stopped_) {
return;
}
LOG_VERB("OnDeadline.");
// NOTE: Can't check this:
// if (ec == boost::asio::error::operation_aborted) {
// LOG_VERB("Deadline timer canceled.");
// return;
// }
if (deadline_.expires_at() <=
boost::asio::deadline_timer::traits_type::now()) {
// The deadline has passed.
// The socket is closed so that any outstanding asynchronous operations
// are canceled.
LOG_WARN("HTTP client timed out.");
timed_out_ = true;
Stop();
return;
}
// Put the actor back to sleep.
DoWaitDeadline();
}
void HttpAsyncClientBase::DoStop() {
if (stopped_) {
return;
}
stopped_ = true;
LOG_INFO("Close socket...");
boost::system::error_code ec;
SocketClose(&ec);
if (ec) {
LOG_ERRO("Socket close error (%s).", ec.message().c_str());
}
LOG_INFO("Cancel deadline timer...");
deadline_.cancel();
}
} // namespace webcc
-130
View File
@@ -1,130 +0,0 @@
#ifndef WEBCC_HTTP_ASYNC_CLIENT_BASE_H_
#define WEBCC_HTTP_ASYNC_CLIENT_BASE_H_
#include <functional>
#include <memory>
#include <vector>
#include "boost/asio/deadline_timer.hpp"
#include "boost/asio/io_context.hpp"
#include "boost/asio/ip/tcp.hpp"
#include "webcc/globals.h"
#include "webcc/http_request.h"
#include "webcc/http_response.h"
#include "webcc/http_response_parser.h"
namespace webcc {
// Response callback.
typedef std::function<void(HttpResponsePtr, Error, bool)> HttpResponseCallback;
// 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 HttpAsyncClientBase
: public std::enable_shared_from_this<HttpAsyncClientBase> {
public:
// The |buffer_size| is the bytes of the buffer for reading response.
// 0 means default value (e.g., 1024) will be used.
explicit HttpAsyncClientBase(boost::asio::io_context& io_context,
std::size_t buffer_size = 0);
virtual ~HttpAsyncClientBase() = default;
WEBCC_DELETE_COPY_ASSIGN(HttpAsyncClientBase);
// Set the timeout seconds for reading response.
// The |seconds| is only effective when greater than 0.
void SetTimeout(int seconds);
// Asynchronously connect to the server, send the request, read the response,
// and call the |response_callback| when all these finish.
void Request(HttpRequestPtr request, HttpResponseCallback response_callback);
// Called by the user to cancel the request.
void Stop();
protected:
using tcp = boost::asio::ip::tcp;
typedef tcp::resolver::results_type Endpoints;
typedef std::function<void(boost::system::error_code, std::size_t)>
ReadHandler;
typedef std::function<void(boost::system::error_code, tcp::endpoint)>
ConnectHandler;
typedef std::function<void(boost::system::error_code, std::size_t)>
WriteHandler;
// To enable_shared_from_this for both parent and derived.
// See https://stackoverflow.com/q/657155/6825348
template <typename Derived>
std::shared_ptr<Derived> shared_from_base() {
return std::static_pointer_cast<Derived>(shared_from_this());
}
protected:
virtual void Resolve() = 0;
void DoResolve(const std::string& default_port);
void OnResolve(boost::system::error_code ec,
tcp::resolver::results_type results);
void DoConnect(const Endpoints& endpoints);
void OnConnect(boost::system::error_code ec, tcp::endpoint endpoint);
virtual void OnConnected() = 0;
void DoWrite();
void OnWrite(boost::system::error_code ec, std::size_t length);
void DoRead();
void OnRead(boost::system::error_code ec, std::size_t length);
void DoWaitDeadline();
void OnDeadline(boost::system::error_code ec);
// Terminate all the actors to shut down the connection.
void DoStop();
virtual void SocketAsyncConnect(const Endpoints& endpoints,
ConnectHandler&& handler) = 0;
virtual void SocketAsyncWrite(WriteHandler&& handler) = 0;
virtual void SocketAsyncReadSome(ReadHandler&& handler) = 0;
virtual void SocketClose(boost::system::error_code* ec) = 0;
tcp::resolver resolver_;
HttpRequestPtr request_;
std::vector<char> buffer_;
HttpResponsePtr response_;
std::unique_ptr<HttpResponseParser> response_parser_;
HttpResponseCallback response_callback_;
// Timer for the timeout control.
boost::asio::deadline_timer deadline_;
// Maximum seconds to wait before the client cancels the operation.
// Only for receiving response from server.
int timeout_seconds_;
// Request stopped due to timeout or socket error.
bool stopped_;
// If the error was caused by timeout or not.
// Will be passed to the response handler/callback.
bool timed_out_;
};
} // namespace webcc
#endif // WEBCC_HTTP_ASYNC_CLIENT_BASE_H_
+2 -2
View File
@@ -7,12 +7,12 @@ namespace webcc {
// HTTP synchronous client.
class HttpClient : public HttpClientBase {
public:
public:
explicit HttpClient(std::size_t buffer_size = 0);
~HttpClient() = default;
private:
private:
Error Connect(const HttpRequest& request) final {
return DoConnect(request, kPort80);
}
+2 -2
View File
@@ -22,7 +22,7 @@ namespace webcc {
// or timeout occurs.
// Please don't use the same client object in multiple threads.
class HttpClientBase {
public:
public:
// The |buffer_size| is the bytes of the buffer for reading response.
// 0 means default value (e.g., 1024) will be used.
explicit HttpClientBase(std::size_t buffer_size = 0);
@@ -56,7 +56,7 @@ class HttpClientBase {
Error error() const { return error_; }
protected:
public:
typedef boost::asio::ip::tcp::resolver::results_type Endpoints;
typedef std::function<void(boost::system::error_code, std::size_t)>
+9 -3
View File
@@ -14,14 +14,20 @@ HttpResponsePtr HttpClientSession::Request(HttpRequestArgs&& args) {
assert(args.parameters_.size() % 2 == 0);
assert(args.headers_.size() % 2 == 0);
HttpRequest request{ args.method_, args.url_, args.parameters_ };
HttpRequest request{ args.method_, args.url_ };
for (std::size_t i = 1; i < args.parameters_.size(); i += 2) {
request.AddParameter(args.parameters_[i - 1], args.parameters_[i]);
}
if (!args.data_.empty()) {
request.SetContent(std::move(args.data_), true);
// TODO: charset/encoding
// TODO: Request-level charset.
if (args.json_) {
request.SetContentType(http::media_types::kApplicationJson, "");
request.SetContentType(http::media_types::kApplicationJson, charset_);
} else if (!content_type_.empty()) {
request.SetContentType(content_type_, charset_);
}
}
+15 -1
View File
@@ -15,6 +15,14 @@ public:
~HttpClientSession() = default;
void set_content_type(const std::string& content_type) {
content_type_ = content_type;
}
void set_charset(const std::string& charset) {
charset_ = charset;
}
void AddHeader(const std::string& key, const std::string& value) {
headers_.Add(key, value);
}
@@ -34,7 +42,13 @@ public:
private:
void InitHeaders();
// Headers to be sent on each request sent from this session.
// E.g., "application/json".
std::string content_type_;
// E.g., "utf-8".
std::string charset_;
// Headers for each request sent from this session.
HttpHeaderDict headers_;
};
-6
View File
@@ -73,12 +73,6 @@ void HttpMessage::SetContent(std::string&& content, bool set_length) {
}
}
void HttpMessage::SetContentInAppJsonUtf8(std::string&& content,
bool set_length) {
SetContent(std::move(content), set_length);
SetContentType(http::media_types::kApplicationJson, http::charsets::kUtf8);
}
// ATTENTION: The buffers don't hold the memory!
std::vector<boost::asio::const_buffer> HttpMessage::ToBuffers() const {
assert(!start_line_.empty());
-2
View File
@@ -88,8 +88,6 @@ public:
// TODO: Remove parameter |set_length|.
void SetContent(std::string&& content, bool set_length);
void SetContentInAppJsonUtf8(std::string&& content, bool set_length);
// Make the message (e.g., update start line).
// Must be called before ToBuffers()!
virtual bool Prepare() = 0;
+2 -2
View File
@@ -11,7 +11,7 @@ class HttpMessage;
// HttpParser parses HTTP request and response.
class HttpParser {
public:
public:
explicit HttpParser(HttpMessage* message);
virtual ~HttpParser() = default;
@@ -24,7 +24,7 @@ class HttpParser {
bool Parse(const char* data, std::size_t length);
protected:
public:
// Parse headers from pending data.
// Return false only on syntax errors.
bool ParseHeaders();
-23
View File
@@ -4,16 +4,6 @@
namespace webcc {
HttpRequest::HttpRequest(const std::string& method,
const std::string& url,
const std::vector<std::string>& parameters)
: method_(method), url_(url) {
assert(parameters.size() % 2 == 0);
for (std::size_t i = 1; i < parameters.size(); i += 2) {
url_.AddParameter(parameters[i - 1], parameters[i]);
}
}
bool HttpRequest::Prepare() {
if (url_.host().empty()) {
LOG_ERRO("Invalid request: host is missing.");
@@ -41,17 +31,4 @@ bool HttpRequest::Prepare() {
return true;
}
HttpRequestPtr HttpRequest::New(const std::string& method,
const std::string& url,
const std::vector<std::string>& parameters,
bool prepare) {
HttpRequestPtr request{ new HttpRequest{ method, url, parameters } };
if (prepare) {
request->Prepare();
}
return request;
}
} // namespace webcc
+16 -30
View File
@@ -11,7 +11,6 @@
namespace webcc {
class HttpRequest;
class HttpRequestParser;
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
@@ -19,13 +18,25 @@ class HttpRequest : public HttpMessage {
public:
HttpRequest() = default;
// TODO: Move parameters
HttpRequest(const std::string& method,
const std::string& url,
const std::vector<std::string>& parameters = {});
HttpRequest(const std::string& method, const std::string& url)
: method_(method), url_(url) {
}
~HttpRequest() override = default;
void set_method(const std::string& method) {
method_ = method;
}
void set_url(const std::string& url) {
url_.Init(url);
}
// Add URL query parameter.
void AddParameter(const std::string& key, const std::string& value) {
url_.AddParameter(key, value);
}
const std::string& method() const {
return method_;
}
@@ -46,36 +57,11 @@ public:
return port().empty() ? default_port : port();
}
// Shortcut to set `Accept` header.
void Accept(const std::string& media_type) {
SetHeader(http::headers::kAccept, media_type);
}
// Shortcut to set `Accept` header.
void AcceptAppJson() {
SetHeader(http::headers::kAccept, http::media_types::kApplicationJson);
}
// Prepare payload.
// Compose start line, set Host header, etc.
bool Prepare() override;
// TODO: Re-place
static HttpRequestPtr New(const std::string& method,
const std::string& url,
const std::vector<std::string>& parameters = {},
bool prepare = true);
private:
friend class HttpRequestParser;
void set_method(const std::string& method) {
method_ = method;
}
void set_url(const std::string& url) {
url_.Init(url);
}
std::string method_;
Url url_;
};
+2 -2
View File
@@ -19,8 +19,8 @@ bool HttpRequestParser::ParseStartLine(const std::string& line) {
return false;
}
request_->set_method(strs[0]);
request_->set_url(strs[1]);
request_->set_method(std::move(strs[0]));
request_->set_url(std::move(strs[1]));
// HTTP version is ignored.
+2 -2
View File
@@ -10,12 +10,12 @@ namespace webcc {
class HttpRequest;
class HttpRequestParser : public HttpParser {
public:
public:
explicit HttpRequestParser(HttpRequest* request);
~HttpRequestParser() override = default;
private:
private:
bool ParseStartLine(const std::string& line) override;
HttpRequest* request_;
+2 -2
View File
@@ -9,7 +9,7 @@
namespace webcc {
class HttpResponse : public HttpMessage {
public:
public:
HttpResponse() : status_(http::Status::kOK) {}
~HttpResponse() override = default;
@@ -25,7 +25,7 @@ class HttpResponse : public HttpMessage {
// TODO: Avoid copy.
static HttpResponse Fault(http::Status status);
private:
private:
int status_;
};
+2 -2
View File
@@ -10,12 +10,12 @@ namespace webcc {
class HttpResponse;
class HttpResponseParser : public HttpParser {
public:
public:
explicit HttpResponseParser(HttpResponse* response);
~HttpResponseParser() override = default;
private:
private:
// Parse HTTP start line; E.g., "HTTP/1.1 200 OK".
bool ParseStartLine(const std::string& line) override;
+2 -2
View File
@@ -17,7 +17,7 @@ class HttpRequestHandler;
// HTTP server accepts TCP connections from TCP clients.
// NOTE: Only support IPv4.
class HttpServer {
public:
public:
HttpServer(std::uint16_t port, std::size_t workers);
virtual ~HttpServer() = default;
@@ -27,7 +27,7 @@ class HttpServer {
// Run the server's io_service loop.
void Run();
private:
private:
// Register to handle the signals that indicate when the server should exit.
void RegisterSignals();
-71
View File
@@ -1,71 +0,0 @@
#include "webcc/http_ssl_async_client.h"
#include "boost/asio/connect.hpp"
#include "webcc/logger.h"
using tcp = boost::asio::ip::tcp;
namespace ssl = boost::asio::ssl;
namespace webcc {
HttpSslAsyncClient::HttpSslAsyncClient(boost::asio::io_context& io_context,
std::size_t buffer_size,
bool ssl_verify)
: HttpAsyncClientBase(io_context, buffer_size),
ssl_context_(ssl::context::sslv23),
ssl_socket_(io_context, ssl_context_),
ssl_verify_(ssl_verify) {
// Use the default paths for finding CA certificates.
ssl_context_.set_default_verify_paths();
}
void HttpSslAsyncClient::Resolve() {
DoResolve(kHttpSslPort);
}
void HttpSslAsyncClient::DoHandshake() {
if (ssl_verify_) {
ssl_socket_.set_verify_mode(ssl::verify_peer);
} else {
ssl_socket_.set_verify_mode(ssl::verify_none);
}
ssl_socket_.set_verify_callback(ssl::rfc2818_verification(request_->host()));
ssl_socket_.async_handshake(ssl::stream_base::client,
std::bind(&HttpSslAsyncClient::OnHandshake,
shared_from_this(),
std::placeholders::_1));
}
void HttpSslAsyncClient::OnHandshake(boost::system::error_code ec) {
if (ec) {
LOG_ERRO("Handshake error (%s).", ec.message().c_str());
response_callback_(response_, kHandshakeError, false);
return;
}
DoWrite();
}
void HttpSslAsyncClient::SocketAsyncConnect(const Endpoints& endpoints,
ConnectHandler&& handler) {
boost::asio::async_connect(ssl_socket_.lowest_layer(), endpoints,
std::move(handler));
}
void HttpSslAsyncClient::SocketAsyncWrite(WriteHandler&& handler) {
boost::asio::async_write(ssl_socket_, request_->ToBuffers(),
std::move(handler));
}
void HttpSslAsyncClient::SocketAsyncReadSome(ReadHandler&& handler) {
ssl_socket_.async_read_some(boost::asio::buffer(buffer_), std::move(handler));
}
void HttpSslAsyncClient::SocketClose(boost::system::error_code* ec) {
ssl_socket_.lowest_layer().close(*ec);
}
} // namespace webcc
-69
View File
@@ -1,69 +0,0 @@
#ifndef WEBCC_HTTP_SSL_ASYNC_CLIENT_H_
#define WEBCC_HTTP_SSL_ASYNC_CLIENT_H_
#include "webcc/http_async_client_base.h"
#include "boost/asio/ssl.hpp"
namespace webcc {
class HttpSslAsyncClient;
typedef std::shared_ptr<HttpSslAsyncClient> HttpSslAsyncClientPtr;
// HTTP SSL (a.k.a., HTTPS) asynchronous client.
class HttpSslAsyncClient : public HttpAsyncClientBase {
public:
~HttpSslAsyncClient() = default;
// Forbid to create HttpSslAsyncClient in stack since it's derived from
// std::shared_from_this.
static HttpSslAsyncClientPtr New(boost::asio::io_context& io_context,
std::size_t buffer_size = 0,
bool ssl_verify = true) {
return HttpSslAsyncClientPtr{
new HttpSslAsyncClient(io_context, buffer_size, ssl_verify)
};
}
// See https://stackoverflow.com/q/657155/6825348
std::shared_ptr<HttpSslAsyncClient> shared_from_this() {
return shared_from_base<HttpSslAsyncClient>();
}
private:
// SSL verification (|ssl_verify|) 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.
explicit HttpSslAsyncClient(boost::asio::io_context& io_context,
std::size_t buffer_size = 0,
bool ssl_verify = true);
void Resolve() final;
// Override to do handshake after connected.
void OnConnected() final {
DoHandshake();
}
void DoHandshake();
void OnHandshake(boost::system::error_code ec);
void SocketAsyncConnect(const Endpoints& endpoints,
ConnectHandler&& handler) final;
void SocketAsyncWrite(WriteHandler&& handler) final;
void SocketAsyncReadSome(ReadHandler&& handler) final;
void SocketClose(boost::system::error_code* ec) final;
boost::asio::ssl::context ssl_context_;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket_;
// Verify the certificate of the peer (remote server) or not.
bool ssl_verify_;
};
} // namespace webcc
#endif // WEBCC_HTTP_SSL_ASYNC_CLIENT_H_
+2 -2
View File
@@ -9,7 +9,7 @@ namespace webcc {
// HTTP SSL (a.k.a., HTTPS) synchronous client.
class HttpSslClient : public HttpClientBase {
public:
public:
// SSL verification (|ssl_verify|) 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.
@@ -17,7 +17,7 @@ class HttpSslClient : public HttpClientBase {
~HttpSslClient() = default;
private:
private:
Error Handshake(const std::string& host);
// Override to do handshake after connected.
+2 -2
View File
@@ -12,7 +12,7 @@ namespace webcc {
template <typename T>
class Queue {
public:
public:
Queue() = default;
Queue(const Queue&) = delete;
@@ -49,7 +49,7 @@ class Queue {
not_empty_cv_.notify_one();
}
private:
private:
std::list<T> message_list_;
std::mutex mutex_;
std::condition_variable not_empty_cv_;
-38
View File
@@ -1,38 +0,0 @@
#include "webcc/rest_async_client.h"
namespace webcc {
RestAsyncClient::RestAsyncClient(boost::asio::io_context& io_context,
const std::string& host,
const std::string& port,
std::size_t buffer_size)
: io_context_(io_context),
host_(host), port_(port),
timeout_seconds_(0),
buffer_size_(buffer_size) {
}
void RestAsyncClient::Request(const std::string& method,
const std::string& url,
std::string&& content,
HttpResponseCallback callback) {
HttpRequestPtr http_request(new HttpRequest(method, url, host_, port_));
if (!content.empty()) {
http_request->SetContent(std::move(content), true);
http_request->SetContentType(http::media_types::kApplicationJson,
http::charsets::kUtf8);
}
http_request->Prepare();
auto http_async_client = HttpAsyncClient::New(io_context_, buffer_size_);
if (timeout_seconds_ > 0) {
http_async_client->SetTimeout(timeout_seconds_);
}
http_async_client->Request(http_request, callback);
}
} // namespace webcc
-61
View File
@@ -1,61 +0,0 @@
#ifndef WEBCC_REST_ASYNC_CLIENT_H_
#define WEBCC_REST_ASYNC_CLIENT_H_
#include <string>
#include <utility> // for move()
#include "webcc/http_async_client.h"
namespace webcc {
class RestAsyncClient {
public:
RestAsyncClient(boost::asio::io_context& io_context,
const std::string& host, const std::string& port,
std::size_t buffer_size = 0);
void SetTimeout(int seconds) {
timeout_seconds_ = seconds;
}
void Get(const std::string& url, HttpResponseCallback callback) {
Request(kHttpGet, url, "", callback);
}
void Post(const std::string& url, std::string&& content,
HttpResponseCallback callback) {
Request(kHttpPost, url, std::move(content), callback);
}
void Put(const std::string& url, std::string&& content,
HttpResponseCallback callback) {
Request(kHttpPut, url, std::move(content), callback);
}
void Patch(const std::string& url, std::string&& content,
HttpResponseCallback callback) {
Request(kHttpPatch, url, std::move(content), callback);
}
void Delete(const std::string& url, HttpResponseCallback callback) {
Request(kHttpDelete, url, "", callback);
}
private:
void Request(const std::string& method, const std::string& url,
std::string&& content, HttpResponseCallback callback);
boost::asio::io_context& io_context_;
std::string host_;
std::string port_;
// Timeout in seconds; only effective when > 0.
int timeout_seconds_;
std::size_t buffer_size_;
};
} // namespace webcc
#endif // WEBCC_REST_ASYNC_CLIENT_H_
-34
View File
@@ -1,34 +0,0 @@
#include "webcc/rest_client.h"
#include "webcc/utility.h"
namespace webcc {
RestClient::RestClient(const std::string& host, const std::string& port,
std::size_t buffer_size)
: host_(host), port_(port), http_client_(buffer_size) {
AdjustHostPort(host_, port_);
}
bool RestClient::Request(const std::string& method, const std::string& url,
std::string&& content, std::size_t buffer_size) {
HttpRequest http_request(method, url, host_, port_);
http_request.SetHeader(http::headers::kAccept,
http::media_types::kApplicationJson);
if (!content.empty()) {
http_request.SetContent(std::move(content), true);
http_request.SetContentType(http::media_types::kApplicationJson,
http::charsets::kUtf8);
}
http_request.Prepare();
if (!http_client_.Request(http_request, buffer_size)) {
return false;
}
return true;
}
} // namespace webcc
-94
View File
@@ -1,94 +0,0 @@
#ifndef WEBCC_REST_CLIENT_H_
#define WEBCC_REST_CLIENT_H_
#include <cassert>
#include <string>
#include <utility> // for move()
#include "webcc/globals.h"
#include "webcc/http_client.h"
#include "webcc/http_request.h"
#include "webcc/http_response.h"
namespace webcc {
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 = "",
std::size_t buffer_size = 0);
~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, std::size_t buffer_size = 0) {
return Request("GET", url, "", buffer_size);
}
inline bool Post(const std::string& url, std::string&& content,
std::size_t buffer_size = 0) {
return Request("POST", url, std::move(content), buffer_size);
}
inline bool Put(const std::string& url, std::string&& content,
std::size_t buffer_size = 0) {
return Request("PUT", url, std::move(content), buffer_size);
}
inline bool Patch(const std::string& url, std::string&& content,
std::size_t buffer_size = 0) {
return Request("PATCH", url, std::move(content), buffer_size);
}
inline bool Delete(const std::string& url, std::size_t buffer_size = 0) {
return Request(kHttpDelete, url, "", buffer_size);
}
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::size_t buffer_size);
std::string host_;
std::string port_;
HttpClient http_client_;
};
} // namespace webcc
#endif // WEBCC_REST_CLIENT_H_
+2 -2
View File
@@ -12,7 +12,7 @@
namespace webcc {
class RestServer : public HttpServer {
public:
public:
RestServer(std::uint16_t port, std::size_t workers)
: HttpServer(port, workers) {
}
@@ -31,7 +31,7 @@ class RestServer : public HttpServer {
return request_handler_.Bind(service, url, is_regex);
}
private:
private:
HttpRequestHandler* GetRequestHandler() override {
return &request_handler_;
}
+5 -5
View File
@@ -46,7 +46,7 @@ struct RestResponse {
// Base class for your REST service.
class RestService {
public:
public:
virtual ~RestService() = default;
// Handle REST request, output response.
@@ -58,10 +58,10 @@ typedef std::shared_ptr<RestService> RestServicePtr;
// -----------------------------------------------------------------------------
class RestListService : public RestService {
public:
public:
void Handle(const RestRequest& request, RestResponse* response) final;
protected:
public:
RestListService() = default;
virtual void Get(const UrlQuery& query, RestResponse* response) {
@@ -75,10 +75,10 @@ class RestListService : public RestService {
// -----------------------------------------------------------------------------
class RestDetailService : public RestService {
public:
public:
void Handle(const RestRequest& request, RestResponse* response) final;
protected:
public:
virtual void Get(const UrlSubMatches& url_sub_matches,
const UrlQuery& query,
RestResponse* response) {
+3 -3
View File
@@ -11,7 +11,7 @@
namespace webcc {
class RestServiceManager {
public:
public:
RestServiceManager() = default;
WEBCC_DELETE_COPY_ASSIGN(RestServiceManager);
@@ -30,9 +30,9 @@ class RestServiceManager {
RestServicePtr GetService(const std::string& url,
std::vector<std::string>* sub_matches);
private:
private:
class ServiceItem {
public:
public:
ServiceItem(RestServicePtr _service, const std::string& _url,
bool _is_regex)
: service(_service), url(_url), is_regex(_is_regex) {
-54
View File
@@ -1,54 +0,0 @@
#include "webcc/rest_ssl_client.h"
#include "boost/algorithm/string.hpp"
#include "webcc/utility.h"
namespace webcc {
RestClientBase::RestClientBase(HttpClientBase* http_client_base,
const SSMap& headers)
: http_client_base_(http_client_base),
content_media_type_(http::media_types::kApplicationJson),
content_charset_(http::charsets::kUtf8),
headers_(headers) {
}
RestSslClient::RestSslClient(const std::string& host, const std::string& port,
bool ssl_verify, const SSMap& headers,
std::size_t buffer_size)
: RestClientBase(&http_ssl_client_, headers),
host_(host), port_(port),
http_ssl_client_(ssl_verify, buffer_size) {
AdjustHostPort(host_, port_);
}
bool RestSslClient::Request(const std::string& method, const std::string& url,
std::string&& content, const SSMap& headers,
std::size_t buffer_size) {
HttpRequest http_request(method, url, host_, port_);
if (!content.empty()) {
http_request.SetContent(std::move(content), true);
http_request.SetContentType(content_media_type_, content_charset_);
}
for (auto& h : headers_) {
http_request.SetHeader(h.first, h.second);
}
for (auto& h : headers) {
http_request.SetHeader(h.first, h.second);
}
http_request.Prepare();
if (!http_ssl_client_.Request(http_request, buffer_size)) {
return false;
}
return true;
}
} // namespace webcc
-130
View File
@@ -1,130 +0,0 @@
#ifndef WEBCC_REST_SSL_CLIENT_H_
#define WEBCC_REST_SSL_CLIENT_H_
#include <cassert>
#include <map>
#include <string>
#include <utility> // 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 std::map<std::string, std::string> SSMap;
class RestClientBase {
public:
RestClientBase(HttpClientBase* http_client_base,
const SSMap& headers = {});
virtual ~RestClientBase() = default;
WEBCC_DELETE_COPY_ASSIGN(RestClientBase);
void SetTimeout(int seconds) {
http_client_base_->SetTimeout(seconds);
}
// Overwrite the default content type (json & utf-8).
void SetContentType(const std::string& media_type,
const std::string& charset) {
content_media_type_ = media_type;
content_charset_ = charset;
}
HttpResponsePtr response() const {
return http_client_base_->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_base_->timed_out();
}
Error error() const {
return http_client_base_->error();
}
protected:
// Default: "application/json".
std::string content_media_type_;
// Default: "utf-8".
std::string content_charset_;
// Default headers for each request sent from this session.
std::map<std::string, std::string> headers_;
private:
HttpClientBase* http_client_base_;
};
class RestSslClient : public RestClientBase {
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,
const SSMap& headers = {},
std::size_t buffer_size = 0);
~RestSslClient() = default;
// 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, const SSMap& headers = {},
std::size_t buffer_size = 0) {
return Request(kHttpGet, url, "", headers, buffer_size);
}
inline bool Post(const std::string& url, std::string&& content,
const SSMap& headers = {}, std::size_t buffer_size = 0) {
return Request(Post, url, std::move(content), headers, buffer_size);
}
inline bool Put(const std::string& url, std::string&& content,
const SSMap& headers = {}, std::size_t buffer_size = 0) {
return Request(kHttpPut, url, std::move(content), headers, buffer_size);
}
inline bool Patch(const std::string& url, std::string&& content,
const SSMap& headers = {}, std::size_t buffer_size = 0) {
return Request(kHttpPatch, url, std::move(content), headers, buffer_size);
}
inline bool Delete(const std::string& url, const SSMap& headers = {},
std::size_t buffer_size = 0) {
return Request(kHttpDelete, url, "", headers, buffer_size);
}
bool Request(const std::string& method, const std::string& url,
std::string&& content, const SSMap& headers = {},
std::size_t buffer_size = 0);
private:
std::string host_;
std::string port_;
HttpSslClient http_ssl_client_;
};
} // namespace webcc
#endif // WEBCC_REST_SSL_CLIENT_H_
-102
View File
@@ -1,102 +0,0 @@
#include "webcc/soap_async_client.h"
#include <cassert>
#include <utility> // for move()
#include "webcc/soap_globals.h"
#include "webcc/soap_request.h"
#include "webcc/soap_response.h"
#include "webcc/utility.h"
namespace webcc {
SoapAsyncClient::SoapAsyncClient(boost::asio::io_context& io_context,
const std::string& host,
const std::string& port,
SoapVersion soap_version,
std::size_t buffer_size)
: io_context_(io_context),
host_(host), port_(port),
soap_version_(soap_version),
buffer_size_(buffer_size),
format_raw_(true), timeout_seconds_(0) {
AdjustHostPort(host_, port_);
}
void SoapAsyncClient::Request(const std::string& operation,
std::vector<SoapParameter>&& parameters,
SoapResponseCallback soap_response_callback) {
assert(service_ns_.IsValid());
assert(!url_.empty() && !host_.empty());
assert(!result_name_.empty());
SoapRequest soap_request;
// Set SOAP envelope namespace according to SOAP version.
if (soap_version_ == kSoapV11) {
soap_request.set_soapenv_ns(kSoapEnvNamespaceV11);
} else {
soap_request.set_soapenv_ns(kSoapEnvNamespaceV12);
}
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(new HttpRequest(kHttpPost, url_, host_, port_));
http_request->SetContent(std::move(http_content), true);
if (soap_version_ == kSoapV11) {
http_request->SetContentType(http::media_types::kTextXml,
http::charsets::kUtf8);
} else {
http_request->SetContentType(http::media_types::kApplicationSoapXml,
http::charsets::kUtf8);
}
http_request->SetHeader(kSoapAction, operation);
http_request->Prepare();
auto http_async_client = HttpAsyncClient::New(io_context_, buffer_size_);
if (timeout_seconds_ > 0) {
http_async_client->SetTimeout(timeout_seconds_);
}
auto http_response_callback = std::bind(&SoapAsyncClient::OnHttpResponse,
this, soap_response_callback,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3);
http_async_client->Request(http_request, http_response_callback);
}
void SoapAsyncClient::OnHttpResponse(SoapResponseCallback soap_response_callback,
HttpResponsePtr http_response,
Error error, bool timed_out) {
if (error != kNoError) {
soap_response_callback("", error, timed_out);
} else {
SoapResponse soap_response;
// TODO
//soap_response.set_result_name(result_name_);
if (!soap_response.FromXml(http_response->content())) {
soap_response_callback("", kXmlError, false);
} else {
// TODO
//soap_response_callback(soap_response.result_moved(), kNoError, false);
}
}
}
} // namespace webcc
-91
View File
@@ -1,91 +0,0 @@
#ifndef WEBCC_SOAP_ASYNC_CLIENT_H_
#define WEBCC_SOAP_ASYNC_CLIENT_H_
#include <functional>
#include <string>
#include <vector>
#include "webcc/http_async_client.h"
#include "webcc/soap_message.h"
#include "webcc/soap_parameter.h"
namespace webcc {
// Response callback.
typedef std::function<void(std::string, Error, bool)> SoapResponseCallback;
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 = "",
SoapVersion soap_version = kSoapV12,
std::size_t buffer_size = 0);
~SoapAsyncClient() = default;
WEBCC_DELETE_COPY_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<SoapParameter>&& parameters,
SoapResponseCallback soap_response_callback);
private:
void OnHttpResponse(SoapResponseCallback soap_response_callback,
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.
SoapVersion soap_version_;
std::size_t buffer_size_;
// Request URL.
std::string url_;
// Namespace for your web service.
SoapNamespace service_ns_;
// 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_
+2 -2
View File
@@ -12,7 +12,7 @@
namespace webcc {
class SoapClient {
public:
public:
// If |port| is empty, |host| will be checked to see if it contains port or
// not (separated by ':').
explicit SoapClient(const std::string& host, const std::string& port = "",
@@ -69,7 +69,7 @@ class SoapClient {
std::shared_ptr<SoapFault> fault() const { return fault_; }
private:
private:
std::string host_;
std::string port_; // Leave this empty to use default 80.
+2 -2
View File
@@ -11,7 +11,7 @@ namespace webcc {
// Base class for SOAP request and response.
class SoapMessage {
public:
public:
virtual ~SoapMessage() = default;
// E.g., set as kSoapEnvNamespace.
@@ -38,7 +38,7 @@ class SoapMessage {
// Parse from SOAP XML.
bool FromXml(const std::string& xml_string);
protected:
public:
// Convert to SOAP body XML.
virtual void ToXmlBody(pugi::xml_node xbody) = 0;
+2 -2
View File
@@ -9,7 +9,7 @@ namespace webcc {
// Key-value SOAP parameter.
class SoapParameter {
public:
public:
SoapParameter() : as_cdata_(false) {
}
@@ -77,7 +77,7 @@ class SoapParameter {
bool as_cdata() const { return as_cdata_; }
private:
private:
std::string key_;
std::string value_;
bool as_cdata_;
+3 -3
View File
@@ -13,7 +13,7 @@ namespace webcc {
// Used to compose the SOAP request envelope XML which will be sent as the HTTP
// request body.
class SoapRequest : public SoapMessage {
public:
public:
void AddParameter(const SoapParameter& parameter);
void AddParameter(SoapParameter&& parameter);
@@ -21,11 +21,11 @@ class SoapRequest : public SoapMessage {
// Get parameter value by key.
const std::string& GetParameter(const std::string& key) const;
protected:
public:
void ToXmlBody(pugi::xml_node xbody) override;
bool FromXmlBody(pugi::xml_node xbody) override;
private:
private:
std::vector<SoapParameter> parameters_;
};
+5 -5
View File
@@ -12,7 +12,7 @@
namespace webcc {
class SoapResponse : public SoapMessage {
public:
public:
// Response result parser.
// Called on each child of the response node.
// Example:
@@ -50,11 +50,11 @@ class SoapResponse : public SoapMessage {
// - composer(xxxResponse);
// The composer then add proper children to xxxResponse as the result.
class Composer {
public:
public:
void operator()(pugi::xml_node xresponse) {
Compose(xresponse);
}
private:
private:
virtual void Compose(pugi::xml_node xresponse) = 0;
};
@@ -127,12 +127,12 @@ class SoapResponse : public SoapMessage {
// TODO: Set fault from server.
protected:
public:
void ToXmlBody(pugi::xml_node xbody) override;
bool FromXmlBody(pugi::xml_node xbody) override;
private:
private:
// Fault element if any.
std::shared_ptr<SoapFault> fault_;
+2 -2
View File
@@ -11,7 +11,7 @@
namespace webcc {
class SoapServer : public HttpServer {
public:
public:
SoapServer(std::uint16_t port, std::size_t workers,
SoapVersion soap_version = kSoapV12)
: HttpServer(port, workers),
@@ -36,7 +36,7 @@ class SoapServer : public HttpServer {
return request_handler_.Bind(service, url);
}
private:
private:
HttpRequestHandler* GetRequestHandler() override {
return &request_handler_;
}
+2 -2
View File
@@ -12,14 +12,14 @@ class SoapResponse;
// Base class for your SOAP service.
class SoapService {
public:
public:
virtual ~SoapService() = default;
// Handle SOAP request, output the response.
virtual bool Handle(const SoapRequest& soap_request,
SoapResponse* soap_response) = 0;
protected:
public:
http::Status http_status_ = http::Status::kOK;
};
+2 -2
View File
@@ -73,7 +73,7 @@ std::string GetNSAttr(const pugi::xml_node& xnode,
// XmlStringWriter writer(&xml_string);
// xdoc.save/print(writer);
class XmlStringWriter : public pugi::xml_writer {
public:
public:
explicit XmlStringWriter(std::string* result) : result_(result) {
result_->clear();
}
@@ -82,7 +82,7 @@ class XmlStringWriter : public pugi::xml_writer {
result_->append(static_cast<const char*>(data), size);
}
private:
private:
std::string* result_;
};
+30 -1
View File
@@ -7,6 +7,8 @@
#include <utility>
#include <vector>
#include "webcc/globals.h"
namespace webcc {
// -----------------------------------------------------------------------------
@@ -57,9 +59,36 @@ class Url {
public:
Url() = default;
// TODO: decode/encode/encoded?
explicit Url(const std::string& str, bool decode = true);
#if WEBCC_DEFAULT_MOVE_COPY_ASSIGN
Url(Url&&) = default;
Url& operator=(Url&&) = default;
#else
Url(Url&& rhs)
: scheme_(std::move(rhs.scheme_)),
host_(std::move(rhs.host_)),
port_(std::move(rhs.port_)),
path_(std::move(rhs.path_)),
query_(std::move(rhs.query_)) {
}
Url& operator=(Url&& rhs) {
if (&rhs != this) {
scheme_ = std::move(rhs.scheme_);
host_ = std::move(rhs.host_);
port_ = std::move(rhs.port_);
path_ = std::move(rhs.path_);
query_ = std::move(rhs.query_);
}
return *this;
}
#endif // WEBCC_DEFAULT_MOVE_COPY_ASSIGN
void Init(const std::string& str, bool decode = true, bool clear = true);
const std::string& scheme() const {