Code refactoring.
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
|
||||
#include "boost/lexical_cast.hpp"
|
||||
#include "boost/thread/thread.hpp"
|
||||
#include "json/json.h"
|
||||
#include "webcc/logger.h"
|
||||
|
||||
@@ -36,7 +36,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
||||
|
||||
unsigned short port = std::atoi(argv[1]);
|
||||
std::uint16_t port = static_cast<std::uint16_t>(std::atoi(argv[1]));
|
||||
|
||||
int sleep_seconds = 0;
|
||||
if (argc >= 3) {
|
||||
@@ -56,7 +56,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
server.Run();
|
||||
|
||||
} catch (std::exception& e) {
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "calc_client.h"
|
||||
|
||||
#include <iostream>
|
||||
#include "boost/lexical_cast.hpp"
|
||||
|
||||
#include "webcc/logger.h"
|
||||
|
||||
// Set to 0 to test our own calculator server created with webcc.
|
||||
@@ -80,8 +81,8 @@ bool CalcClient::Calc(const std::string& operation,
|
||||
|
||||
// Convert the result from string to double.
|
||||
try {
|
||||
*result = boost::lexical_cast<double>(result_str);
|
||||
} catch (boost::bad_lexical_cast&) {
|
||||
*result = std::stod(result_str);
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#include "calc_service.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
// Sleep several seconds for the client to test timeout control.
|
||||
#define SLEEP_FOR_TIMEOUT_TEST 0
|
||||
|
||||
#include "boost/lexical_cast.hpp"
|
||||
|
||||
#if SLEEP_FOR_TIMEOUT_TEST
|
||||
#include "boost/thread/thread.hpp"
|
||||
#endif
|
||||
@@ -82,10 +83,10 @@ bool CalcService::GetParameters(const webcc::SoapRequest& soap_request,
|
||||
double* x,
|
||||
double* y) {
|
||||
try {
|
||||
*x = boost::lexical_cast<double>(soap_request.GetParameter("x"));
|
||||
*y = boost::lexical_cast<double>(soap_request.GetParameter("y"));
|
||||
*x = std::stod(soap_request.GetParameter("x"));
|
||||
*y = std::stod(soap_request.GetParameter("y"));
|
||||
|
||||
} catch (boost::bad_lexical_cast& e) {
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERRO("Parameter cast error: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
||||
|
||||
unsigned short port = std::atoi(argv[1]);
|
||||
std::uint16_t port = static_cast<std::uint16_t>(std::atoi(argv[1]));
|
||||
|
||||
std::size_t workers = 2;
|
||||
|
||||
@@ -30,7 +30,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
server.Run();
|
||||
|
||||
} catch (std::exception& e) {
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# Don't use any deprecated definitions (e.g., io_service).
|
||||
add_definitions(-DBOOST_ASIO_NO_DEPRECATED)
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
set(SRCS
|
||||
async_http_client.cc
|
||||
async_http_client.h
|
||||
|
||||
@@ -18,12 +18,12 @@ extern void AdjustBufferSize(std::size_t content_length,
|
||||
|
||||
AsyncHttpClient::AsyncHttpClient(boost::asio::io_context& io_context)
|
||||
: socket_(io_context),
|
||||
resolver_(new tcp::resolver(io_context)),
|
||||
buffer_(kBufferSize),
|
||||
deadline_(io_context),
|
||||
timeout_seconds_(kMaxReceiveSeconds),
|
||||
deadline_(io_context) {
|
||||
resolver_.reset(new tcp::resolver(io_context));
|
||||
response_.reset(new HttpResponse());
|
||||
response_parser_.reset(new HttpResponseParser(response_.get()));
|
||||
stopped_(false),
|
||||
timed_out_(false) {
|
||||
}
|
||||
|
||||
Error AsyncHttpClient::Request(std::shared_ptr<HttpRequest> request,
|
||||
@@ -31,6 +31,9 @@ Error AsyncHttpClient::Request(std::shared_ptr<HttpRequest> request,
|
||||
assert(request);
|
||||
assert(response_handler);
|
||||
|
||||
response_.reset(new HttpResponse());
|
||||
response_parser_.reset(new HttpResponseParser(response_.get()));
|
||||
|
||||
LOG_VERB("HTTP request:\n%s", request->Dump(4, "> ").c_str());
|
||||
|
||||
request_ = request;
|
||||
@@ -53,8 +56,10 @@ Error AsyncHttpClient::Request(std::shared_ptr<HttpRequest> request,
|
||||
|
||||
void AsyncHttpClient::Stop() {
|
||||
stopped_ = true;
|
||||
|
||||
boost::system::error_code ignored_ec;
|
||||
socket_.close(ignored_ec);
|
||||
|
||||
deadline_.cancel();
|
||||
}
|
||||
|
||||
@@ -72,7 +77,8 @@ void AsyncHttpClient::ResolveHandler(boost::system::error_code ec,
|
||||
// Start the deadline actor. You will note that we're not setting any
|
||||
// particular deadline here. Instead, the connect and input actors will
|
||||
// update the deadline prior to each asynchronous operation.
|
||||
deadline_.async_wait(std::bind(&AsyncHttpClient::CheckDeadline, this));
|
||||
deadline_.async_wait(std::bind(&AsyncHttpClient::CheckDeadline,
|
||||
shared_from_this()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +116,6 @@ void AsyncHttpClient::ConnectHandler(boost::system::error_code ec,
|
||||
// of the asynchronous operation. If the socket is closed at this time then
|
||||
// the timeout handler must have run first.
|
||||
LOG_WARN("Connect timed out.");
|
||||
|
||||
// Try the next available endpoint.
|
||||
AsyncConnect(++endpoint_iter);
|
||||
} else if (ec) {
|
||||
@@ -118,7 +123,6 @@ void AsyncHttpClient::ConnectHandler(boost::system::error_code ec,
|
||||
// We need to close the socket used in the previous connection attempt
|
||||
// before starting a new one.
|
||||
socket_.close();
|
||||
|
||||
// Try the next available endpoint.
|
||||
AsyncConnect(++endpoint_iter);
|
||||
} else {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// Request handler/callback.
|
||||
typedef std::function<void(HttpResponsePtr, Error, bool)> HttpResponseHandler;
|
||||
|
||||
class AsyncHttpClient : public std::enable_shared_from_this<AsyncHttpClient> {
|
||||
@@ -57,29 +58,26 @@ class AsyncHttpClient : public std::enable_shared_from_this<AsyncHttpClient> {
|
||||
|
||||
void CheckDeadline();
|
||||
|
||||
bool stopped_ = false;
|
||||
bool timed_out_ = false;
|
||||
|
||||
tcp::socket socket_;
|
||||
|
||||
std::shared_ptr<HttpRequest> request_;
|
||||
|
||||
std::unique_ptr<tcp::resolver> resolver_;
|
||||
tcp::resolver::results_type endpoints_;
|
||||
|
||||
std::shared_ptr<HttpRequest> request_;
|
||||
std::vector<char> buffer_;
|
||||
|
||||
std::unique_ptr<HttpResponseParser> response_parser_;
|
||||
|
||||
HttpResponsePtr response_;
|
||||
std::unique_ptr<HttpResponseParser> response_parser_;
|
||||
HttpResponseHandler response_handler_;
|
||||
|
||||
// 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_;
|
||||
|
||||
// Timer for the timeout control.
|
||||
boost::asio::deadline_timer deadline_;
|
||||
bool stopped_;
|
||||
bool timed_out_;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<AsyncHttpClient> HttpAsyncClientPtr;
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
AsyncRestClient::AsyncRestClient(boost::asio::io_context& io_context,
|
||||
const std::string& host,
|
||||
const std::string& port)
|
||||
: io_context_(io_context), host_(host), port_(port), timeout_seconds_(0) {
|
||||
}
|
||||
|
||||
void AsyncRestClient::Request(const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& content,
|
||||
@@ -21,6 +27,11 @@ void AsyncRestClient::Request(const std::string& method,
|
||||
request->Build();
|
||||
|
||||
HttpAsyncClientPtr http_client(new AsyncHttpClient(io_context_));
|
||||
|
||||
if (timeout_seconds_ > 0) {
|
||||
http_client->set_timeout_seconds(timeout_seconds_);
|
||||
}
|
||||
|
||||
http_client->Request(request, response_handler_);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webcc/globals.h"
|
||||
#include "webcc/async_http_client.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class AsyncRestClient {
|
||||
public:
|
||||
AsyncRestClient(boost::asio::io_context& io_context,
|
||||
const std::string& host, const std::string& port)
|
||||
: io_context_(io_context), host_(host), port_(port) {
|
||||
AsyncRestClient(boost::asio::io_context& io_context, // NOLINT
|
||||
const std::string& host,
|
||||
const std::string& port);
|
||||
|
||||
void set_timeout_seconds(int timeout_seconds) {
|
||||
timeout_seconds_ = timeout_seconds;
|
||||
}
|
||||
|
||||
void Get(const std::string& url,
|
||||
@@ -50,9 +52,14 @@ class AsyncRestClient {
|
||||
HttpResponseHandler response_handler);
|
||||
|
||||
boost::asio::io_context& io_context_;
|
||||
|
||||
std::string host_;
|
||||
std::string port_;
|
||||
|
||||
HttpResponseHandler response_handler_;
|
||||
|
||||
// Timeout in seconds; only effective when > 0.
|
||||
int timeout_seconds_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
+16
-20
@@ -6,21 +6,25 @@ namespace webcc {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// NOTE:
|
||||
// Field names are case-insensitive.
|
||||
// See: https://stackoverflow.com/a/5259004
|
||||
// NOTE: Field names are case-insensitive.
|
||||
// See https://stackoverflow.com/a/5259004 for more details.
|
||||
const std::string kHost = "Host";
|
||||
const std::string kContentType = "Content-Type";
|
||||
const std::string kContentLength = "Content-Length";
|
||||
const std::string kSoapAction = "SOAPAction";
|
||||
const std::string kHost = "Host";
|
||||
|
||||
#ifdef WEBCC_ENABLE_SOAP
|
||||
const std::string kSoapAction = "SOAPAction";
|
||||
#endif // WEBCC_ENABLE_SOAP
|
||||
|
||||
const std::string kTextJsonUtf8 = "text/json; charset=utf-8";
|
||||
|
||||
#ifdef WEBCC_ENABLE_SOAP
|
||||
// According to www.w3.org when placing SOAP messages in HTTP bodies, the HTTP
|
||||
// Content-type header must be chosen as "application/soap+xml" [RFC 3902].
|
||||
// But in practice, many web servers cannot understand it.
|
||||
// See: https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L26854
|
||||
const std::string kTextXmlUtf8 = "text/xml; charset=utf-8";
|
||||
|
||||
const std::string kTextJsonUtf8 = "text/json; charset=utf-8";
|
||||
#endif // WEBCC_ENABLE_SOAP
|
||||
|
||||
const std::string kHttpHead = "HEAD";
|
||||
const std::string kHttpGet = "GET";
|
||||
@@ -65,35 +69,27 @@ Parameter::Parameter(const std::string& key, std::string&& value)
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string& key, int value)
|
||||
: key_(key) {
|
||||
value_ = std::to_string(value);
|
||||
: key_(key), value_(std::to_string(value)) {
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string& key, double value)
|
||||
: key_(key) {
|
||||
value_ = std::to_string(value);
|
||||
: key_(key), value_(std::to_string(value)) {
|
||||
}
|
||||
|
||||
Parameter::Parameter(const std::string& key, bool value)
|
||||
: key_(key) {
|
||||
value_ = value ? "true" : "false";
|
||||
: key_(key), value_(value ? "true" : "false") {
|
||||
}
|
||||
|
||||
Parameter::Parameter(Parameter&& rhs)
|
||||
: key_(std::move(rhs.key_)),
|
||||
value_(std::move(rhs.value_)) {
|
||||
: key_(std::move(rhs.key_)), value_(std::move(rhs.value_)) {
|
||||
}
|
||||
|
||||
Parameter& Parameter::operator=(Parameter&& rhs) {
|
||||
if (this != &rhs) {
|
||||
if (&rhs != this) {
|
||||
key_ = std::move(rhs.key_);
|
||||
value_ = std::move(rhs.value_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string Parameter::ToString() const {
|
||||
return key_ + "=" + value_;
|
||||
}
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
+17
-19
@@ -23,18 +23,25 @@ const std::size_t kBufferSize = 1024;
|
||||
const std::size_t kInvalidLength = static_cast<std::size_t>(-1);
|
||||
|
||||
// Timeout seconds.
|
||||
// TODO
|
||||
const int kMaxConnectSeconds = 10;
|
||||
const int kMaxSendSeconds = 10;
|
||||
const int kMaxSendSeconds = 30;
|
||||
const int kMaxReceiveSeconds = 30;
|
||||
|
||||
extern const std::string kHost;
|
||||
extern const std::string kContentType;
|
||||
extern const std::string kContentLength;
|
||||
extern const std::string kSoapAction;
|
||||
extern const std::string kHost;
|
||||
|
||||
extern const std::string kTextXmlUtf8;
|
||||
#ifdef WEBCC_ENABLE_SOAP
|
||||
extern const std::string kSoapAction;
|
||||
#endif // WEBCC_ENABLE_SOAP
|
||||
|
||||
extern const std::string kTextJsonUtf8;
|
||||
|
||||
#ifdef WEBCC_ENABLE_SOAP
|
||||
extern const std::string kTextXmlUtf8;
|
||||
#endif // WEBCC_ENABLE_SOAP
|
||||
|
||||
// HTTP methods (verbs) in string ("HEAD", "GET", etc.).
|
||||
// NOTE: Don't use enum to avoid converting back and forth.
|
||||
extern const std::string kHttpHead;
|
||||
@@ -99,25 +106,16 @@ class Parameter {
|
||||
// Use "= default" if drop the support of VS 2013.
|
||||
Parameter& operator=(Parameter&& rhs);
|
||||
|
||||
const std::string& key() const {
|
||||
return key_;
|
||||
}
|
||||
const std::string& key() const { return key_; }
|
||||
const std::string& value() const { return value_; }
|
||||
|
||||
const std::string& value() const {
|
||||
return value_;
|
||||
}
|
||||
const char* c_key() const { return key_.c_str(); }
|
||||
const char* c_value() const { return value_.c_str(); }
|
||||
|
||||
const char* c_key() const {
|
||||
return key_.c_str();
|
||||
std::string ToString() const {
|
||||
return key_ + "=" + value_;
|
||||
}
|
||||
|
||||
const char* c_value() const {
|
||||
return value_.c_str();
|
||||
}
|
||||
|
||||
// Return "key=value" string.
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
std::string key_;
|
||||
std::string value_;
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include "boost/lambda/lambda.hpp"
|
||||
|
||||
#include "webcc/logger.h"
|
||||
#include "webcc/http_request.h"
|
||||
#include "webcc/http_response.h"
|
||||
|
||||
// NOTE:
|
||||
// The timeout control is inspired by the following Asio example:
|
||||
@@ -34,17 +32,20 @@ void AdjustBufferSize(std::size_t content_length, std::vector<char>* buffer) {
|
||||
std::size_t min_buffer_size = content_length / kMaxTimes;
|
||||
if (min_buffer_size > buffer->size()) {
|
||||
buffer->resize(std::min(min_buffer_size, kMaxBufferSize));
|
||||
LOG_INFO("Resize read buffer to %d.", buffer->size());
|
||||
LOG_INFO("Resize read buffer to %u.", buffer->size());
|
||||
} else {
|
||||
LOG_INFO("Keep the current buffer size (%d).", buffer->size());
|
||||
LOG_INFO("Keep the current buffer size: %u.", buffer->size());
|
||||
}
|
||||
}
|
||||
|
||||
HttpClient::HttpClient()
|
||||
: socket_(io_context_),
|
||||
buffer_(kBufferSize),
|
||||
deadline_(io_context_),
|
||||
timeout_seconds_(kMaxReceiveSeconds),
|
||||
deadline_(io_context_) {
|
||||
stopped_(false),
|
||||
timed_out_(false),
|
||||
error_(kNoError) {
|
||||
}
|
||||
|
||||
bool HttpClient::Request(const HttpRequest& request) {
|
||||
@@ -189,7 +190,7 @@ void HttpClient::DoReadResponse(Error* error) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_INFO("Read data, length: %d.", length);
|
||||
LOG_INFO("Read data, length: %u.", length);
|
||||
|
||||
bool content_length_parsed = response_parser_->content_length_parsed();
|
||||
|
||||
|
||||
+9
-11
@@ -19,7 +19,6 @@ namespace webcc {
|
||||
class HttpClient {
|
||||
public:
|
||||
HttpClient();
|
||||
|
||||
~HttpClient() = default;
|
||||
|
||||
DELETE_COPY_AND_ASSIGN(HttpClient);
|
||||
@@ -31,10 +30,10 @@ class HttpClient {
|
||||
|
||||
HttpResponsePtr response() const { return response_; }
|
||||
|
||||
Error error() const { return error_; }
|
||||
|
||||
bool timed_out() const { return timed_out_; }
|
||||
|
||||
Error error() const { return error_; }
|
||||
|
||||
// Connect to server, send request, wait until response is received.
|
||||
bool Request(const HttpRequest& request);
|
||||
|
||||
@@ -53,7 +52,6 @@ class HttpClient {
|
||||
void CheckDeadline();
|
||||
|
||||
boost::asio::io_context io_context_;
|
||||
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
std::vector<char> buffer_;
|
||||
@@ -61,18 +59,18 @@ class HttpClient {
|
||||
HttpResponsePtr response_;
|
||||
std::unique_ptr<HttpResponseParser> response_parser_;
|
||||
|
||||
Error error_ = kNoError;
|
||||
|
||||
bool stopped_ = false;
|
||||
|
||||
// If the error was caused by timeout or not.
|
||||
bool timed_out_ = false;
|
||||
boost::asio::deadline_timer deadline_;
|
||||
|
||||
// Maximum seconds to wait before the client cancels the operation.
|
||||
// Only for receiving response from server.
|
||||
int timeout_seconds_;
|
||||
|
||||
boost::asio::deadline_timer deadline_;
|
||||
bool stopped_;
|
||||
|
||||
// If the error was caused by timeout or not.
|
||||
bool timed_out_;
|
||||
|
||||
Error error_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
@@ -91,7 +91,7 @@ void HttpConnection::AsyncWrite() {
|
||||
void HttpConnection::WriteHandler(boost::system::error_code ec,
|
||||
std::size_t length) {
|
||||
if (!ec) {
|
||||
LOG_INFO("Response has been sent back.");
|
||||
LOG_INFO("Response has been sent back, length: %u.", length);
|
||||
|
||||
// Initiate graceful connection closure.
|
||||
boost::system::error_code ec;
|
||||
|
||||
@@ -18,7 +18,7 @@ class HttpRequestHandler;
|
||||
|
||||
class HttpConnection : public std::enable_shared_from_this<HttpConnection> {
|
||||
public:
|
||||
HttpConnection(boost::asio::ip::tcp::socket socket,
|
||||
HttpConnection(boost::asio::ip::tcp::socket socket, // Will be moved
|
||||
HttpRequestHandler* handler);
|
||||
|
||||
~HttpConnection() = default;
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpHeader {
|
||||
public:
|
||||
struct HttpHeader {
|
||||
std::string name;
|
||||
std::string value;
|
||||
};
|
||||
@@ -21,20 +20,15 @@ class HttpMessage {
|
||||
public:
|
||||
virtual ~HttpMessage() = default;
|
||||
|
||||
const std::string& start_line() const {
|
||||
return start_line_;
|
||||
}
|
||||
const std::string& start_line() const { return start_line_; }
|
||||
|
||||
void set_start_line(const std::string& start_line) {
|
||||
start_line_ = start_line;
|
||||
}
|
||||
|
||||
std::size_t content_length() const {
|
||||
return content_length_;
|
||||
}
|
||||
std::size_t content_length() const { return content_length_; }
|
||||
|
||||
const std::string& content() const {
|
||||
return content_;
|
||||
}
|
||||
const std::string& content() const { return content_; }
|
||||
|
||||
void SetHeader(const std::string& name, const std::string& value);
|
||||
|
||||
|
||||
+12
-12
@@ -1,7 +1,6 @@
|
||||
#include "webcc/http_parser.h"
|
||||
|
||||
#include "boost/algorithm/string.hpp"
|
||||
#include "boost/lexical_cast.hpp"
|
||||
|
||||
#include "webcc/http_message.h"
|
||||
#include "webcc/logger.h"
|
||||
@@ -111,23 +110,24 @@ void HttpParser::ParseContentLength(const std::string& line) {
|
||||
std::string value = line.substr(pos);
|
||||
|
||||
try {
|
||||
content_length_ = boost::lexical_cast<std::size_t>(value);
|
||||
LOG_INFO("Content length: %d", content_length_);
|
||||
|
||||
// Reserve memory to avoid frequent reallocation when append.
|
||||
try {
|
||||
content_.reserve(content_length_);
|
||||
} catch (std::exception& e) {
|
||||
LOG_ERRO("Failed to reserve content memory: %s.", e.what());
|
||||
}
|
||||
} catch (boost::bad_lexical_cast&) {
|
||||
content_length_ = static_cast<std::size_t>(std::stoul(value));
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERRO("Invalid content length: %s.", value.c_str());
|
||||
}
|
||||
|
||||
LOG_INFO("Content length: %u.", content_length_);
|
||||
|
||||
try {
|
||||
// Reserve memory to avoid frequent reallocation when append.
|
||||
content_.reserve(content_length_);
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERRO("Failed to reserve content memory: %s.", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HttpParser::Finish() {
|
||||
// Move temp content to message.
|
||||
// Move content to message.
|
||||
message_->SetContent(std::move(content_));
|
||||
finished_ = true;
|
||||
}
|
||||
|
||||
@@ -40,8 +40,6 @@ class HttpParser {
|
||||
// The result HTTP message.
|
||||
HttpMessage* message_;
|
||||
|
||||
Error error_;
|
||||
|
||||
// Data waiting to be parsed.
|
||||
std::string pending_data_;
|
||||
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
namespace misc_strings {
|
||||
|
||||
const char NAME_VALUE_SEPARATOR[] = { ':', ' ' };
|
||||
const char CRLF[] = { '\r', '\n' };
|
||||
|
||||
} // misc_strings
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void HttpRequest::SetHost(const std::string& host, const std::string& port) {
|
||||
host_ = host;
|
||||
port_ = port;
|
||||
@@ -22,13 +33,6 @@ void HttpRequest::Build() {
|
||||
}
|
||||
}
|
||||
|
||||
namespace misc_strings {
|
||||
|
||||
const char NAME_VALUE_SEPARATOR[] = { ':', ' ' };
|
||||
const char CRLF[] = { '\r', '\n' };
|
||||
|
||||
} // misc_strings
|
||||
|
||||
// ATTENTION: The buffers don't hold the memory!
|
||||
std::vector<boost::asio::const_buffer> HttpRequest::ToBuffers() const {
|
||||
assert(!start_line_.empty());
|
||||
|
||||
@@ -19,29 +19,14 @@ class HttpRequest : public HttpMessage {
|
||||
|
||||
virtual ~HttpRequest() = default;
|
||||
|
||||
const std::string& method() const {
|
||||
return method_;
|
||||
}
|
||||
const std::string& method() const { return method_; }
|
||||
void set_method(const std::string& method) { method_ = method; }
|
||||
|
||||
void set_method(const std::string& method) {
|
||||
method_ = method;
|
||||
}
|
||||
const std::string& url() const { return url_; }
|
||||
void set_url(const std::string& url) { url_ = url; }
|
||||
|
||||
const std::string& url() const {
|
||||
return url_;
|
||||
}
|
||||
|
||||
void set_url(const std::string& url) {
|
||||
url_ = url;
|
||||
}
|
||||
|
||||
const std::string& host() const {
|
||||
return host_;
|
||||
}
|
||||
|
||||
const std::string& port() const {
|
||||
return port_;
|
||||
}
|
||||
const std::string& host() const { return host_; }
|
||||
const std::string& port() const { return port_; }
|
||||
|
||||
// Set host name and port number.
|
||||
// The |host| is a descriptive name or a numeric IP address. The |port| is
|
||||
|
||||
@@ -13,16 +13,13 @@ namespace webcc {
|
||||
|
||||
class HttpResponse : public HttpMessage {
|
||||
public:
|
||||
HttpResponse() = default;
|
||||
HttpResponse() : status_(HttpStatus::kOK) {
|
||||
}
|
||||
|
||||
~HttpResponse() override = default;
|
||||
|
||||
int status() const {
|
||||
return status_;
|
||||
}
|
||||
|
||||
void set_status(int status) {
|
||||
status_ = status;
|
||||
}
|
||||
int status() const { return status_; }
|
||||
void set_status(int status) { status_ = status; }
|
||||
|
||||
// Convert the response into a vector of buffers. The buffers do not own the
|
||||
// underlying memory blocks, therefore the response object must remain valid
|
||||
@@ -33,7 +30,7 @@ class HttpResponse : public HttpMessage {
|
||||
static HttpResponse Fault(HttpStatus::Enum status);
|
||||
|
||||
private:
|
||||
int status_ = HttpStatus::kOK;
|
||||
int status_;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "webcc/http_response_parser.h"
|
||||
|
||||
#include "boost/lexical_cast.hpp"
|
||||
|
||||
#include "webcc/logger.h"
|
||||
#include "webcc/http_response.h"
|
||||
|
||||
@@ -34,8 +32,8 @@ bool HttpResponseParser::ParseStartLine(const std::string& line) {
|
||||
std::string status_str = line.substr(off, pos - off);
|
||||
|
||||
try {
|
||||
response_->set_status(boost::lexical_cast<int>(status_str));
|
||||
} catch (boost::bad_lexical_cast&) {
|
||||
response_->set_status(std::stoi(status_str));
|
||||
} catch (const std::exception&) {
|
||||
LOG_ERRO("Invalid HTTP status: %s", status_str.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ using tcp = boost::asio::ip::tcp;
|
||||
|
||||
namespace webcc {
|
||||
|
||||
HttpServer::HttpServer(unsigned short port, std::size_t workers)
|
||||
HttpServer::HttpServer(std::uint16_t port, std::size_t workers)
|
||||
: signals_(io_context_) , workers_(workers) {
|
||||
// Register to handle the signals that indicate when the server should exit.
|
||||
// It is safe to register for the same signal multiple times in a program,
|
||||
|
||||
@@ -21,7 +21,7 @@ class HttpRequestHandler;
|
||||
// NOTE: Only support IPv4.
|
||||
class HttpServer {
|
||||
public:
|
||||
HttpServer(unsigned short port, std::size_t workers);
|
||||
HttpServer(std::uint16_t port, std::size_t workers);
|
||||
|
||||
virtual ~HttpServer() = default;
|
||||
|
||||
|
||||
+2
-2
@@ -56,7 +56,7 @@ namespace bfs = boost::filesystem;
|
||||
|
||||
static bfs::path InitLogPath(const std::string& dir) {
|
||||
if (dir.empty()) {
|
||||
return bfs::current_path() / WEBCC_LOG_FILE;
|
||||
return bfs::current_path() / WEBCC_LOG_FILE_NAME;
|
||||
}
|
||||
|
||||
bfs::path path = bfs::path(dir);
|
||||
@@ -67,7 +67,7 @@ static bfs::path InitLogPath(const std::string& dir) {
|
||||
}
|
||||
}
|
||||
|
||||
path /= WEBCC_LOG_FILE;
|
||||
path /= WEBCC_LOG_FILE_NAME;
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -8,18 +8,21 @@
|
||||
#include <cstring> // for strrchr()
|
||||
#include <string>
|
||||
|
||||
#define WEBCC_VERB 0
|
||||
// Log levels.
|
||||
#define WEBCC_VERB 0 // Similar to DEBUG in other projects.
|
||||
#define WEBCC_INFO 1
|
||||
#define WEBCC_WARN 2
|
||||
#define WEBCC_ERRO 3
|
||||
#define WEBCC_FATA 4
|
||||
|
||||
// Default log level.
|
||||
// You have to define a proper log level in CMakeLists.txt, e.g.,
|
||||
// add_definitions(-DWEBCC_LOG_LEVEL=2)
|
||||
#ifndef WEBCC_LOG_LEVEL
|
||||
#define WEBCC_LOG_LEVEL WEBCC_WARN
|
||||
#endif
|
||||
|
||||
#define WEBCC_LOG_FILE "webcc.log"
|
||||
#define WEBCC_LOG_FILE_NAME "webcc.log"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
@@ -129,7 +132,7 @@ void LogWrite(int level, const char* file, int line, const char* format, ...);
|
||||
|
||||
#else // WEBCC_ENABLE_LOG == 0
|
||||
|
||||
#define WEBCC_LOG_INIT(modes)
|
||||
#define WEBCC_LOG_INIT(dir, modes)
|
||||
|
||||
#if (defined(WIN32) || defined(_WIN64))
|
||||
#define LOG_VERB(format, ...)
|
||||
|
||||
@@ -5,10 +5,19 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
RestClient::RestClient(const std::string& host, const std::string& port)
|
||||
: host_(host),
|
||||
port_(port),
|
||||
timeout_seconds_(0),
|
||||
timed_out_(false),
|
||||
error_(kNoError) {
|
||||
}
|
||||
|
||||
bool RestClient::Request(const std::string& method,
|
||||
const std::string& url,
|
||||
const std::string& content) {
|
||||
response_.reset();
|
||||
|
||||
error_ = kNoError;
|
||||
timed_out_ = false;
|
||||
|
||||
|
||||
+16
-14
@@ -11,9 +11,11 @@ namespace webcc {
|
||||
|
||||
class RestClient {
|
||||
public:
|
||||
RestClient(const std::string& host, const std::string& port)
|
||||
: host_(host), port_(port) {
|
||||
}
|
||||
RestClient(const std::string& host, const std::string& port);
|
||||
|
||||
~RestClient() = default;
|
||||
|
||||
DELETE_COPY_AND_ASSIGN(RestClient);
|
||||
|
||||
void set_timeout_seconds(int timeout_seconds) {
|
||||
timeout_seconds_ = timeout_seconds;
|
||||
@@ -31,27 +33,27 @@ class RestClient {
|
||||
return response_->content();
|
||||
}
|
||||
|
||||
Error error() const { return error_; }
|
||||
|
||||
bool timed_out() const { return timed_out_; }
|
||||
|
||||
bool Get(const std::string& url) {
|
||||
Error error() const { return error_; }
|
||||
|
||||
inline bool Get(const std::string& url) {
|
||||
return Request(kHttpGet, url, "");
|
||||
}
|
||||
|
||||
bool Post(const std::string& url, const std::string& content) {
|
||||
inline bool Post(const std::string& url, const std::string& content) {
|
||||
return Request(kHttpPost, url, content);
|
||||
}
|
||||
|
||||
bool Put(const std::string& url, const std::string& content) {
|
||||
inline bool Put(const std::string& url, const std::string& content) {
|
||||
return Request(kHttpPut, url, content);
|
||||
}
|
||||
|
||||
bool Patch(const std::string& url, const std::string& content) {
|
||||
inline bool Patch(const std::string& url, const std::string& content) {
|
||||
return Request(kHttpPatch, url, content);
|
||||
}
|
||||
|
||||
bool Delete(const std::string& url) {
|
||||
inline bool Delete(const std::string& url) {
|
||||
return Request(kHttpDelete, url, "");
|
||||
}
|
||||
|
||||
@@ -64,14 +66,14 @@ class RestClient {
|
||||
std::string port_;
|
||||
|
||||
// Timeout in seconds; only effective when > 0.
|
||||
int timeout_seconds_ = 0;
|
||||
int timeout_seconds_;
|
||||
|
||||
HttpResponsePtr response_;
|
||||
|
||||
Error error_ = kNoError;
|
||||
|
||||
// If the error was caused by timeout or not.
|
||||
bool timed_out_ = false;
|
||||
bool timed_out_;
|
||||
|
||||
Error error_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace webcc {
|
||||
|
||||
class RestServer : public HttpServer {
|
||||
public:
|
||||
RestServer(unsigned short port, std::size_t workers)
|
||||
RestServer(std::uint16_t port, std::size_t workers)
|
||||
: HttpServer(port, workers) {
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,7 @@ class RestListService : public RestService {
|
||||
protected:
|
||||
RestListService() = default;
|
||||
|
||||
virtual bool Get(const UrlQuery& query,
|
||||
std::string* response_content) {
|
||||
virtual bool Get(const UrlQuery& query, std::string* response_content) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@ class SoapClient {
|
||||
bool timed_out() const { return timed_out_; }
|
||||
|
||||
protected:
|
||||
SoapClient() = default;
|
||||
SoapClient() : timeout_seconds_(0), timed_out_(false) {
|
||||
}
|
||||
|
||||
// A generic wrapper to make a call.
|
||||
// NOTE: The parameters should be movable.
|
||||
@@ -27,10 +28,10 @@ class SoapClient {
|
||||
std::string* result);
|
||||
|
||||
// Timeout in seconds; only effective when > 0.
|
||||
int timeout_seconds_ = 0;
|
||||
int timeout_seconds_;
|
||||
|
||||
// If the error was caused by timeout or not.
|
||||
bool timed_out_ = false;
|
||||
bool timed_out_;
|
||||
|
||||
SoapNamespace soapenv_ns_; // SOAP envelope namespace.
|
||||
SoapNamespace service_ns_; // Namespace for your web service.
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace webcc {
|
||||
|
||||
class SoapServer : public HttpServer {
|
||||
public:
|
||||
SoapServer(unsigned short port, std::size_t workers)
|
||||
SoapServer(std::uint16_t port, std::size_t workers)
|
||||
: HttpServer(port, workers) {
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user