Add a base class for http async clients; refine examples.
This commit is contained in:
@@ -15,6 +15,7 @@ include(GNUInstallDirs)
|
||||
|
||||
set(HEADERS
|
||||
globals.h
|
||||
http_async_client_base.h
|
||||
http_async_client.h
|
||||
http_client_base.h
|
||||
http_client.h
|
||||
@@ -27,7 +28,7 @@ set(HEADERS
|
||||
http_response.h
|
||||
http_response_parser.h
|
||||
http_server.h
|
||||
logger.h
|
||||
http_ssl_async_client.h
|
||||
queue.h
|
||||
rest_async_client.h
|
||||
rest_client.h
|
||||
@@ -42,6 +43,7 @@ set(HEADERS
|
||||
|
||||
set(SOURCES
|
||||
globals.cc
|
||||
http_async_client_base.cc
|
||||
http_async_client.cc
|
||||
http_client_base.cc
|
||||
http_client.cc
|
||||
@@ -54,6 +56,7 @@ set(SOURCES
|
||||
http_response.cc
|
||||
http_response_parser.cc
|
||||
http_server.cc
|
||||
http_ssl_async_client.cc
|
||||
logger.cc
|
||||
rest_async_client.cc
|
||||
rest_client.cc
|
||||
|
||||
+11
-208
@@ -11,222 +11,25 @@ namespace webcc {
|
||||
|
||||
HttpAsyncClient::HttpAsyncClient(boost::asio::io_context& io_context,
|
||||
std::size_t buffer_size)
|
||||
: socket_(io_context),
|
||||
resolver_(io_context),
|
||||
buffer_(buffer_size == 0 ? kBufferSize : buffer_size),
|
||||
deadline_(io_context),
|
||||
timeout_seconds_(kMaxReadSeconds),
|
||||
stopped_(false),
|
||||
timed_out_(false) {
|
||||
: HttpAsyncClientBase(io_context, buffer_size),
|
||||
socket_(io_context) {
|
||||
}
|
||||
|
||||
void HttpAsyncClient::SetTimeout(int seconds) {
|
||||
if (seconds > 0) {
|
||||
timeout_seconds_ = seconds;
|
||||
}
|
||||
void HttpAsyncClient::SocketAsyncConnect(const Endpoints& endpoints,
|
||||
ConnectHandler&& handler) {
|
||||
boost::asio::async_connect(socket_, endpoints, std::move(handler));
|
||||
}
|
||||
|
||||
void HttpAsyncClient::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;
|
||||
|
||||
resolver_.async_resolve(tcp::v4(), request->host(), request->port(kHttpPort),
|
||||
std::bind(&HttpAsyncClient::OnResolve,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
void HttpAsyncClient::SocketAsyncWrite(WriteHandler&& handler) {
|
||||
boost::asio::async_write(socket_, request_->ToBuffers(), std::move(handler));
|
||||
}
|
||||
|
||||
void HttpAsyncClient::Stop() {
|
||||
LOG_INFO("The user asks to cancel the request.");
|
||||
|
||||
DoStop();
|
||||
void HttpAsyncClient::SocketAsyncReadSome(ReadHandler&& handler) {
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_), std::move(handler));
|
||||
}
|
||||
|
||||
void HttpAsyncClient::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("Connect to server...");
|
||||
|
||||
// ConnectHandler: void(boost::system::error_code, tcp::endpoint)
|
||||
boost::asio::async_connect(socket_, endpoints,
|
||||
std::bind(&HttpAsyncClient::OnConnect,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
}
|
||||
|
||||
void HttpAsyncClient::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.
|
||||
DoWrite();
|
||||
}
|
||||
|
||||
void HttpAsyncClient::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.
|
||||
|
||||
boost::asio::async_write(socket_,
|
||||
request_->ToBuffers(),
|
||||
std::bind(&HttpAsyncClient::OnWrite,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void HttpAsyncClient::OnWrite(boost::system::error_code ec) {
|
||||
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 HttpAsyncClient::DoRead() {
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||
std::bind(&HttpAsyncClient::OnRead,
|
||||
shared_from_this(),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2));
|
||||
}
|
||||
|
||||
void HttpAsyncClient::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 HttpAsyncClient::DoWaitDeadline() {
|
||||
deadline_.async_wait(std::bind(&HttpAsyncClient::OnDeadline,
|
||||
shared_from_this(), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void HttpAsyncClient::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 HttpAsyncClient::DoStop() {
|
||||
if (stopped_) {
|
||||
return;
|
||||
}
|
||||
|
||||
stopped_ = true;
|
||||
|
||||
LOG_INFO("Close socket...");
|
||||
|
||||
boost::system::error_code ec;
|
||||
socket_.close(ec);
|
||||
if (ec) {
|
||||
LOG_ERRO("Socket close error (%s).", ec.message().c_str());
|
||||
}
|
||||
|
||||
LOG_INFO("Cancel deadline timer...");
|
||||
deadline_.cancel();
|
||||
void HttpAsyncClient::SocketClose(boost::system::error_code* ec) {
|
||||
socket_.close(*ec);
|
||||
}
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
+15
-69
@@ -1,91 +1,37 @@
|
||||
#ifndef WEBCC_HTTP_ASYNC_CLIENT_H_
|
||||
#define WEBCC_HTTP_ASYNC_CLIENT_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"
|
||||
#include "webcc/http_async_client_base.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 HttpAsyncClient : public std::enable_shared_from_this<HttpAsyncClient> {
|
||||
// HTTP asynchronous client.
|
||||
class HttpAsyncClient : public 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 HttpAsyncClient(boost::asio::io_context& io_context,
|
||||
std::size_t buffer_size = 0);
|
||||
|
||||
WEBCC_DELETE_COPY_ASSIGN(HttpAsyncClient);
|
||||
|
||||
// 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();
|
||||
~HttpAsyncClient() = default;
|
||||
|
||||
private:
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
void Resolve() final {
|
||||
DoResolve(kHttpPort);
|
||||
}
|
||||
|
||||
void OnResolve(boost::system::error_code ec,
|
||||
tcp::resolver::results_type results);
|
||||
void OnConnected() final {
|
||||
DoWrite();
|
||||
}
|
||||
|
||||
void OnConnect(boost::system::error_code ec, tcp::endpoint endpoint);
|
||||
void SocketAsyncConnect(const Endpoints& endpoints,
|
||||
ConnectHandler&& handler) final;
|
||||
|
||||
void DoWrite();
|
||||
void OnWrite(boost::system::error_code ec);
|
||||
void SocketAsyncWrite(WriteHandler&& handler) final;
|
||||
|
||||
void DoRead();
|
||||
void OnRead(boost::system::error_code ec, std::size_t length);
|
||||
void SocketAsyncReadSome(ReadHandler&& handler) final;
|
||||
|
||||
void DoWaitDeadline();
|
||||
void OnDeadline(boost::system::error_code ec);
|
||||
void SocketClose(boost::system::error_code* ec) final;
|
||||
|
||||
// Terminate all the actors to shut down the connection.
|
||||
void DoStop();
|
||||
|
||||
tcp::resolver resolver_;
|
||||
tcp::socket socket_;
|
||||
|
||||
std::shared_ptr<HttpRequest> 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_;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<HttpAsyncClient> HttpAsyncClientPtr;
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
#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
|
||||
@@ -0,0 +1,128 @@
|
||||
#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);
|
||||
|
||||
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_
|
||||
@@ -20,9 +20,8 @@ void HttpClient::SocketWrite(const HttpRequest& request,
|
||||
boost::asio::write(socket_, request.ToBuffers(), *ec);
|
||||
}
|
||||
|
||||
void HttpClient::SocketAsyncReadSome(std::vector<char>& buffer,
|
||||
ReadHandler handler) {
|
||||
socket_.async_read_some(boost::asio::buffer(buffer), handler);
|
||||
void HttpClient::SocketAsyncReadSome(ReadHandler&& handler) {
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_), std::move(handler));
|
||||
}
|
||||
|
||||
void HttpClient::SocketClose(boost::system::error_code* ec) {
|
||||
|
||||
+2
-7
@@ -5,17 +5,13 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// HTTP client 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.
|
||||
// HTTP synchronous client.
|
||||
class HttpClient : public HttpClientBase {
|
||||
public:
|
||||
explicit HttpClient(std::size_t buffer_size = 0);
|
||||
|
||||
~HttpClient() = default;
|
||||
|
||||
WEBCC_DELETE_COPY_ASSIGN(HttpClient);
|
||||
|
||||
private:
|
||||
Error Connect(const HttpRequest& request) final {
|
||||
return DoConnect(request, kHttpPort);
|
||||
@@ -27,8 +23,7 @@ class HttpClient : public HttpClientBase {
|
||||
void SocketWrite(const HttpRequest& request,
|
||||
boost::system::error_code* ec) final;
|
||||
|
||||
void SocketAsyncReadSome(std::vector<char>& buffer,
|
||||
ReadHandler handler) final;
|
||||
void SocketAsyncReadSome(ReadHandler&& handler) final;
|
||||
|
||||
void SocketClose(boost::system::error_code* ec) final;
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include "webcc/http_client_base.h"
|
||||
|
||||
#include "boost/asio/connect.hpp"
|
||||
#include "boost/asio/read.hpp"
|
||||
#include "boost/asio/write.hpp"
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
|
||||
#include "webcc/logger.h"
|
||||
@@ -44,7 +41,7 @@ bool HttpClientBase::Request(const HttpRequest& request,
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((error_ = SendReqeust(request)) != kNoError) {
|
||||
if ((error_ = WriteReqeust(request)) != kNoError) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -87,7 +84,7 @@ Error HttpClientBase::DoConnect(const HttpRequest& request,
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
Error HttpClientBase::SendReqeust(const HttpRequest& request) {
|
||||
Error HttpClientBase::WriteReqeust(const HttpRequest& request) {
|
||||
LOG_VERB("HTTP request:\n%s", request.Dump(4, "> ").c_str());
|
||||
|
||||
// NOTE:
|
||||
@@ -130,8 +127,8 @@ Error HttpClientBase::ReadResponse() {
|
||||
void HttpClientBase::DoReadResponse(Error* error) {
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
|
||||
auto read_handler = [this, &ec, error](boost::system::error_code inner_ec,
|
||||
std::size_t length) {
|
||||
auto handler = [this, &ec, error](boost::system::error_code inner_ec,
|
||||
std::size_t length) {
|
||||
ec = inner_ec;
|
||||
|
||||
LOG_VERB("Socket async read handler.");
|
||||
@@ -168,7 +165,7 @@ void HttpClientBase::DoReadResponse(Error* error) {
|
||||
}
|
||||
};
|
||||
|
||||
SocketAsyncReadSome(buffer_, read_handler);
|
||||
SocketAsyncReadSome(std::move(handler));
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
do {
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// The base class of synchronous HTTP clients.
|
||||
// In synchronous mode, a request won't return until the response is received
|
||||
// or timeout occurs.
|
||||
// Please don't use the same client object in multiple threads.
|
||||
class HttpClientBase {
|
||||
public:
|
||||
// The |buffer_size| is the bytes of the buffer for reading response.
|
||||
@@ -38,6 +42,16 @@ class HttpClientBase {
|
||||
|
||||
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_; }
|
||||
@@ -48,12 +62,11 @@ class HttpClientBase {
|
||||
typedef std::function<void(boost::system::error_code, std::size_t)>
|
||||
ReadHandler;
|
||||
|
||||
virtual Error Connect(const HttpRequest& request) = 0;
|
||||
|
||||
Error DoConnect(const HttpRequest& request, const std::string& default_port);
|
||||
|
||||
boost::asio::io_context io_context_;
|
||||
|
||||
private:
|
||||
Error SendReqeust(const HttpRequest& request);
|
||||
Error WriteReqeust(const HttpRequest& request);
|
||||
|
||||
Error ReadResponse();
|
||||
|
||||
@@ -64,19 +77,18 @@ class HttpClientBase {
|
||||
|
||||
void Stop();
|
||||
|
||||
virtual Error Connect(const HttpRequest& request) = 0;
|
||||
|
||||
virtual void SocketConnect(const Endpoints& endpoints,
|
||||
boost::system::error_code* ec) = 0;
|
||||
|
||||
virtual void SocketWrite(const HttpRequest& request,
|
||||
boost::system::error_code* ec) = 0;
|
||||
|
||||
virtual void SocketAsyncReadSome(std::vector<char>& buffer,
|
||||
ReadHandler handler) = 0;
|
||||
virtual void SocketAsyncReadSome(ReadHandler&& handler) = 0;
|
||||
|
||||
virtual void SocketClose(boost::system::error_code* ec) = 0;
|
||||
|
||||
boost::asio::io_context io_context_;
|
||||
|
||||
std::vector<char> buffer_;
|
||||
|
||||
HttpResponsePtr response_;
|
||||
|
||||
@@ -46,7 +46,7 @@ class HttpMessage {
|
||||
|
||||
// Make the message (e.g., update start line).
|
||||
// Must be called before ToBuffers()!
|
||||
virtual void Make() = 0;
|
||||
virtual void Prepare() = 0;
|
||||
|
||||
// Convert the message into a vector of buffers. The buffers do not own the
|
||||
// underlying memory blocks, therefore the message object must remain valid
|
||||
|
||||
+18
-1
@@ -9,7 +9,7 @@ HttpRequest::HttpRequest(const std::string& method,
|
||||
: method_(method), url_(url), host_(host), port_(port) {
|
||||
}
|
||||
|
||||
void HttpRequest::Make() {
|
||||
void HttpRequest::Prepare() {
|
||||
start_line_ = method_;
|
||||
start_line_ += " ";
|
||||
start_line_ += url_;
|
||||
@@ -32,4 +32,21 @@ void HttpRequest::Make() {
|
||||
SetHeader(http::headers::kUserAgent, "Webcc/" WEBCC_VERSION);
|
||||
}
|
||||
|
||||
// static
|
||||
HttpRequestPtr HttpRequest::Make(const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& host,
|
||||
const std::string& port,
|
||||
bool prepare) {
|
||||
HttpRequestPtr request{
|
||||
new HttpRequest{ method, url, host, port }
|
||||
};
|
||||
|
||||
if (prepare) {
|
||||
request->Prepare();
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
+11
-3
@@ -8,8 +8,11 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpRequest;
|
||||
class HttpRequestParser;
|
||||
|
||||
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
|
||||
|
||||
class HttpRequest : public HttpMessage {
|
||||
public:
|
||||
HttpRequest() = default;
|
||||
@@ -36,8 +39,15 @@ class HttpRequest : public HttpMessage {
|
||||
return port_.empty() ? default_port : port_;
|
||||
}
|
||||
|
||||
// Prepare payload.
|
||||
// Compose start line, set Host header, etc.
|
||||
void Make() override;
|
||||
void Prepare() override;
|
||||
|
||||
static HttpRequestPtr Make(const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& host,
|
||||
const std::string& port = "",
|
||||
bool prepare = true);
|
||||
|
||||
private:
|
||||
friend class HttpRequestParser;
|
||||
@@ -57,8 +67,6 @@ class HttpRequest : public HttpMessage {
|
||||
std::string port_;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_REQUEST_H_
|
||||
|
||||
@@ -57,7 +57,7 @@ const std::string& ToString(int status) {
|
||||
|
||||
} // namespace status_strings
|
||||
|
||||
void HttpResponse::Make() {
|
||||
void HttpResponse::Prepare() {
|
||||
start_line_ = status_strings::ToString(status_);
|
||||
|
||||
// NOTE: C++11 requires a space between literal and string macro.
|
||||
@@ -72,7 +72,7 @@ HttpResponse HttpResponse::Fault(http::Status status) {
|
||||
HttpResponse response;
|
||||
response.set_status(status);
|
||||
|
||||
response.Make();
|
||||
response.Prepare();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class HttpResponse : public HttpMessage {
|
||||
void set_status(int status) { status_ = status; }
|
||||
|
||||
// Set start line according to status code.
|
||||
void Make() override;
|
||||
void Prepare() override;
|
||||
|
||||
// Get a fault response when HTTP status is not OK.
|
||||
// TODO: Avoid copy.
|
||||
|
||||
@@ -41,7 +41,7 @@ void HttpSession::SetResponseContent(std::string&& content,
|
||||
|
||||
void HttpSession::SendResponse(http::Status status) {
|
||||
response_.set_status(status);
|
||||
response_.Make();
|
||||
response_.Prepare();
|
||||
DoWrite();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#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
|
||||
@@ -0,0 +1,58 @@
|
||||
#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 {
|
||||
|
||||
// HTTP SSL (a.k.a., HTTPS) asynchronous client.
|
||||
class HttpSslAsyncClient : public HttpAsyncClientBase {
|
||||
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.
|
||||
explicit HttpSslAsyncClient(boost::asio::io_context& io_context,
|
||||
std::size_t buffer_size = 0,
|
||||
bool ssl_verify = true);
|
||||
|
||||
~HttpSslAsyncClient() = default;
|
||||
|
||||
// See https://stackoverflow.com/q/657155/6825348
|
||||
std::shared_ptr<HttpSslAsyncClient> shared_from_this() {
|
||||
return shared_from_base<HttpSslAsyncClient>();
|
||||
}
|
||||
|
||||
private:
|
||||
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_;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<HttpSslAsyncClient> HttpSslAsyncClientPtr;
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_SSL_ASYNC_CLIENT_H_
|
||||
@@ -61,9 +61,8 @@ void HttpSslClient::SocketWrite(const HttpRequest& request,
|
||||
boost::asio::write(ssl_socket_, request.ToBuffers(), *ec);
|
||||
}
|
||||
|
||||
void HttpSslClient::SocketAsyncReadSome(std::vector<char>& buffer,
|
||||
ReadHandler handler) {
|
||||
ssl_socket_.async_read_some(boost::asio::buffer(buffer), handler);
|
||||
void HttpSslClient::SocketAsyncReadSome(ReadHandler&& handler) {
|
||||
ssl_socket_.async_read_some(boost::asio::buffer(buffer_), std::move(handler));
|
||||
}
|
||||
|
||||
void HttpSslClient::SocketClose(boost::system::error_code* ec) {
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// HTTP SSL (a.k.a., HTTPS) client session in synchronous mode.
|
||||
// A request will not return until the response is received or timeout occurs.
|
||||
// Don't use the same HttpSslClient object in multiple threads.
|
||||
// HTTP SSL (a.k.a., HTTPS) synchronous client.
|
||||
class HttpSslClient : public HttpClientBase {
|
||||
public:
|
||||
// SSL verification (|ssl_verify|) needs CA certificates to be found
|
||||
@@ -19,8 +17,6 @@ class HttpSslClient : public HttpClientBase {
|
||||
|
||||
~HttpSslClient() = default;
|
||||
|
||||
WEBCC_DELETE_COPY_ASSIGN(HttpSslClient);
|
||||
|
||||
private:
|
||||
Error Handshake(const std::string& host);
|
||||
|
||||
@@ -33,8 +29,7 @@ class HttpSslClient : public HttpClientBase {
|
||||
void SocketWrite(const HttpRequest& request,
|
||||
boost::system::error_code* ec) final;
|
||||
|
||||
void SocketAsyncReadSome(std::vector<char>& buffer,
|
||||
ReadHandler handler) final;
|
||||
void SocketAsyncReadSome(ReadHandler&& handler) final;
|
||||
|
||||
void SocketClose(boost::system::error_code* ec) final;
|
||||
|
||||
|
||||
+1
-1
@@ -168,7 +168,7 @@ void LogWrite(int level, const char* file, int line, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
fprintf(stderr, "%s, %s, %7s, %24s, %4d, ",
|
||||
fprintf(stderr, "%s, %s, %7s, %25s, %4d, ",
|
||||
timestamp.c_str(), kLevelNames[level], thread_id.c_str(),
|
||||
file, line);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ void RestAsyncClient::Request(const std::string& method,
|
||||
http::charsets::kUtf8);
|
||||
}
|
||||
|
||||
http_request->Make();
|
||||
http_request->Prepare();
|
||||
|
||||
HttpAsyncClientPtr http_async_client{
|
||||
new HttpAsyncClient(io_context_, buffer_size_)
|
||||
|
||||
@@ -22,7 +22,7 @@ bool RestClient::Request(const std::string& method, const std::string& url,
|
||||
http::charsets::kUtf8);
|
||||
}
|
||||
|
||||
http_request.Make();
|
||||
http_request.Prepare();
|
||||
|
||||
if (!http_client_.Request(http_request, buffer_size)) {
|
||||
return false;
|
||||
|
||||
+3
-3
@@ -16,9 +16,9 @@ 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);
|
||||
explicit RestClient(const std::string& host,
|
||||
const std::string& port = "",
|
||||
std::size_t buffer_size = 0);
|
||||
|
||||
~RestClient() = default;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ bool RestSslClient::Request(const std::string& method, const std::string& url,
|
||||
http::charsets::kUtf8);
|
||||
}
|
||||
|
||||
http_request.Make();
|
||||
http_request.Prepare();
|
||||
|
||||
if (!http_client_.Request(http_request, buffer_size)) {
|
||||
return false;
|
||||
|
||||
@@ -63,7 +63,7 @@ void SoapAsyncClient::Request(const std::string& operation,
|
||||
}
|
||||
|
||||
http_request->SetHeader(kSoapAction, operation);
|
||||
http_request->Make();
|
||||
http_request->Prepare();
|
||||
|
||||
HttpAsyncClientPtr http_async_client{
|
||||
new HttpAsyncClient(io_context_, buffer_size_)
|
||||
|
||||
@@ -62,7 +62,7 @@ bool SoapClient::Request(const std::string& operation,
|
||||
|
||||
http_request.SetHeader(kSoapAction, operation);
|
||||
|
||||
http_request.Make();
|
||||
http_request.Prepare();
|
||||
|
||||
if (!http_client_.Request(http_request, buffer_size)) {
|
||||
error_ = http_client_.error();
|
||||
|
||||
+3
-5
@@ -22,8 +22,7 @@ void AdjustHostPort(std::string& host, std::string& port) {
|
||||
}
|
||||
}
|
||||
|
||||
void PrintEndpoint(std::ostream& ostream,
|
||||
const boost::asio::ip::tcp::endpoint& endpoint) {
|
||||
void PrintEndpoint(std::ostream& ostream, const TcpEndpoint& endpoint) {
|
||||
ostream << endpoint;
|
||||
if (endpoint.protocol() == tcp::v4()) {
|
||||
ostream << ", v4";
|
||||
@@ -32,8 +31,7 @@ void PrintEndpoint(std::ostream& ostream,
|
||||
}
|
||||
}
|
||||
|
||||
void PrintEndpoints(std::ostream& ostream,
|
||||
const tcp::resolver::results_type& endpoints) {
|
||||
void PrintEndpoints(std::ostream& ostream, const TcpEndpoints& endpoints) {
|
||||
ostream << "Endpoints: " << endpoints.size() << std::endl;
|
||||
tcp::resolver::results_type::iterator it = endpoints.begin();
|
||||
for (; it != endpoints.end(); ++it) {
|
||||
@@ -43,7 +41,7 @@ void PrintEndpoints(std::ostream& ostream,
|
||||
}
|
||||
}
|
||||
|
||||
std::string EndpointToString(const boost::asio::ip::tcp::endpoint& endpoint) {
|
||||
std::string EndpointToString(const TcpEndpoint& endpoint) {
|
||||
std::stringstream ss;
|
||||
PrintEndpoint(ss, endpoint);
|
||||
return ss.str();
|
||||
|
||||
+6
-6
@@ -12,14 +12,14 @@ namespace webcc {
|
||||
// If |port| is empty, try to extract it from |host| (separated by ':').
|
||||
void AdjustHostPort(std::string& host, std::string& port);
|
||||
|
||||
void PrintEndpoint(std::ostream& ostream,
|
||||
const boost::asio::ip::tcp::endpoint& endpoint);
|
||||
typedef boost::asio::ip::tcp::endpoint TcpEndpoint;
|
||||
typedef boost::asio::ip::tcp::resolver::results_type TcpEndpoints;
|
||||
|
||||
void PrintEndpoints(
|
||||
std::ostream& ostream,
|
||||
const boost::asio::ip::tcp::resolver::results_type& endpoints);
|
||||
void PrintEndpoint(std::ostream& ostream, const TcpEndpoint& endpoint);
|
||||
|
||||
std::string EndpointToString(const boost::asio::ip::tcp::endpoint& endpoint);
|
||||
void PrintEndpoints(std::ostream& ostream, const TcpEndpoints& endpoints);
|
||||
|
||||
std::string EndpointToString(const TcpEndpoint& endpoint);
|
||||
|
||||
// Get the timestamp for HTTP Date header field.
|
||||
// E.g., Wed, 21 Oct 2015 07:28:00 GMT
|
||||
|
||||
Reference in New Issue
Block a user