Code refactoring.

master
Adam Gu 7 years ago
parent 1d64421e33
commit 3b13cc74f7

@ -3,7 +3,6 @@
#include <list> #include <list>
#include <iostream> #include <iostream>
#include "boost/lexical_cast.hpp"
#include "boost/thread/thread.hpp" #include "boost/thread/thread.hpp"
#include "json/json.h" #include "json/json.h"
#include "webcc/logger.h" #include "webcc/logger.h"

@ -36,7 +36,7 @@ int main(int argc, char* argv[]) {
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); 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; int sleep_seconds = 0;
if (argc >= 3) { if (argc >= 3) {
@ -56,7 +56,7 @@ int main(int argc, char* argv[]) {
server.Run(); server.Run();
} catch (std::exception& e) { } catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl; std::cerr << "Exception: " << e.what() << std::endl;
return 1; return 1;
} }

@ -1,6 +1,7 @@
#include "calc_client.h" #include "calc_client.h"
#include <iostream> #include <iostream>
#include "boost/lexical_cast.hpp"
#include "webcc/logger.h" #include "webcc/logger.h"
// Set to 0 to test our own calculator server created with webcc. // 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. // Convert the result from string to double.
try { try {
*result = boost::lexical_cast<double>(result_str); *result = std::stod(result_str);
} catch (boost::bad_lexical_cast&) { } catch (const std::exception&) {
return false; return false;
} }

@ -1,10 +1,11 @@
#include "calc_service.h" #include "calc_service.h"
#include <functional>
#include <string>
// Sleep several seconds for the client to test timeout control. // Sleep several seconds for the client to test timeout control.
#define SLEEP_FOR_TIMEOUT_TEST 0 #define SLEEP_FOR_TIMEOUT_TEST 0
#include "boost/lexical_cast.hpp"
#if SLEEP_FOR_TIMEOUT_TEST #if SLEEP_FOR_TIMEOUT_TEST
#include "boost/thread/thread.hpp" #include "boost/thread/thread.hpp"
#endif #endif
@ -82,10 +83,10 @@ bool CalcService::GetParameters(const webcc::SoapRequest& soap_request,
double* x, double* x,
double* y) { double* y) {
try { try {
*x = boost::lexical_cast<double>(soap_request.GetParameter("x")); *x = std::stod(soap_request.GetParameter("x"));
*y = boost::lexical_cast<double>(soap_request.GetParameter("y")); *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()); LOG_ERRO("Parameter cast error: %s", e.what());
return false; return false;
} }

@ -19,7 +19,7 @@ int main(int argc, char* argv[]) {
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); 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; std::size_t workers = 2;
@ -30,7 +30,7 @@ int main(int argc, char* argv[]) {
server.Run(); server.Run();
} catch (std::exception& e) { } catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl; std::cerr << "Exception: " << e.what() << std::endl;
return 1; return 1;
} }

@ -1,6 +1,10 @@
# Don't use any deprecated definitions (e.g., io_service). # Don't use any deprecated definitions (e.g., io_service).
add_definitions(-DBOOST_ASIO_NO_DEPRECATED) add_definitions(-DBOOST_ASIO_NO_DEPRECATED)
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
set(SRCS set(SRCS
async_http_client.cc async_http_client.cc
async_http_client.h async_http_client.h

@ -18,12 +18,12 @@ extern void AdjustBufferSize(std::size_t content_length,
AsyncHttpClient::AsyncHttpClient(boost::asio::io_context& io_context) AsyncHttpClient::AsyncHttpClient(boost::asio::io_context& io_context)
: socket_(io_context), : socket_(io_context),
resolver_(new tcp::resolver(io_context)),
buffer_(kBufferSize), buffer_(kBufferSize),
deadline_(io_context),
timeout_seconds_(kMaxReceiveSeconds), timeout_seconds_(kMaxReceiveSeconds),
deadline_(io_context) { stopped_(false),
resolver_.reset(new tcp::resolver(io_context)); timed_out_(false) {
response_.reset(new HttpResponse());
response_parser_.reset(new HttpResponseParser(response_.get()));
} }
Error AsyncHttpClient::Request(std::shared_ptr<HttpRequest> request, Error AsyncHttpClient::Request(std::shared_ptr<HttpRequest> request,
@ -31,6 +31,9 @@ Error AsyncHttpClient::Request(std::shared_ptr<HttpRequest> request,
assert(request); assert(request);
assert(response_handler); 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()); LOG_VERB("HTTP request:\n%s", request->Dump(4, "> ").c_str());
request_ = request; request_ = request;
@ -53,8 +56,10 @@ Error AsyncHttpClient::Request(std::shared_ptr<HttpRequest> request,
void AsyncHttpClient::Stop() { void AsyncHttpClient::Stop() {
stopped_ = true; stopped_ = true;
boost::system::error_code ignored_ec; boost::system::error_code ignored_ec;
socket_.close(ignored_ec); socket_.close(ignored_ec);
deadline_.cancel(); 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 // Start the deadline actor. You will note that we're not setting any
// particular deadline here. Instead, the connect and input actors will // particular deadline here. Instead, the connect and input actors will
// update the deadline prior to each asynchronous operation. // 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 // of the asynchronous operation. If the socket is closed at this time then
// the timeout handler must have run first. // the timeout handler must have run first.
LOG_WARN("Connect timed out."); LOG_WARN("Connect timed out.");
// Try the next available endpoint. // Try the next available endpoint.
AsyncConnect(++endpoint_iter); AsyncConnect(++endpoint_iter);
} else if (ec) { } 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 // We need to close the socket used in the previous connection attempt
// before starting a new one. // before starting a new one.
socket_.close(); socket_.close();
// Try the next available endpoint. // Try the next available endpoint.
AsyncConnect(++endpoint_iter); AsyncConnect(++endpoint_iter);
} else { } else {

@ -16,6 +16,7 @@
namespace webcc { namespace webcc {
// Request handler/callback.
typedef std::function<void(HttpResponsePtr, Error, bool)> HttpResponseHandler; typedef std::function<void(HttpResponsePtr, Error, bool)> HttpResponseHandler;
class AsyncHttpClient : public std::enable_shared_from_this<AsyncHttpClient> { class AsyncHttpClient : public std::enable_shared_from_this<AsyncHttpClient> {
@ -57,29 +58,26 @@ class AsyncHttpClient : public std::enable_shared_from_this<AsyncHttpClient> {
void CheckDeadline(); void CheckDeadline();
bool stopped_ = false;
bool timed_out_ = false;
tcp::socket socket_; tcp::socket socket_;
std::shared_ptr<HttpRequest> request_;
std::unique_ptr<tcp::resolver> resolver_; std::unique_ptr<tcp::resolver> resolver_;
tcp::resolver::results_type endpoints_; tcp::resolver::results_type endpoints_;
std::shared_ptr<HttpRequest> request_;
std::vector<char> buffer_; std::vector<char> buffer_;
std::unique_ptr<HttpResponseParser> response_parser_;
HttpResponsePtr response_; HttpResponsePtr response_;
std::unique_ptr<HttpResponseParser> response_parser_;
HttpResponseHandler response_handler_; HttpResponseHandler response_handler_;
// Timer for the timeout control.
boost::asio::deadline_timer deadline_;
// Maximum seconds to wait before the client cancels the operation. // Maximum seconds to wait before the client cancels the operation.
// Only for receiving response from server. // Only for receiving response from server.
int timeout_seconds_; int timeout_seconds_;
// Timer for the timeout control. bool stopped_;
boost::asio::deadline_timer deadline_; bool timed_out_;
}; };
typedef std::shared_ptr<AsyncHttpClient> HttpAsyncClientPtr; typedef std::shared_ptr<AsyncHttpClient> HttpAsyncClientPtr;

@ -2,6 +2,12 @@
namespace webcc { 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, void AsyncRestClient::Request(const std::string& method,
const std::string& url, const std::string& url,
const std::string& content, const std::string& content,
@ -21,6 +27,11 @@ void AsyncRestClient::Request(const std::string& method,
request->Build(); request->Build();
HttpAsyncClientPtr http_client(new AsyncHttpClient(io_context_)); HttpAsyncClientPtr http_client(new AsyncHttpClient(io_context_));
if (timeout_seconds_ > 0) {
http_client->set_timeout_seconds(timeout_seconds_);
}
http_client->Request(request, response_handler_); http_client->Request(request, response_handler_);
} }

@ -3,16 +3,18 @@
#include <string> #include <string>
#include "webcc/globals.h"
#include "webcc/async_http_client.h" #include "webcc/async_http_client.h"
namespace webcc { namespace webcc {
class AsyncRestClient { class AsyncRestClient {
public: public:
AsyncRestClient(boost::asio::io_context& io_context, AsyncRestClient(boost::asio::io_context& io_context, // NOLINT
const std::string& host, const std::string& port) const std::string& host,
: io_context_(io_context), host_(host), port_(port) { const std::string& port);
void set_timeout_seconds(int timeout_seconds) {
timeout_seconds_ = timeout_seconds;
} }
void Get(const std::string& url, void Get(const std::string& url,
@ -50,9 +52,14 @@ class AsyncRestClient {
HttpResponseHandler response_handler); HttpResponseHandler response_handler);
boost::asio::io_context& io_context_; boost::asio::io_context& io_context_;
std::string host_; std::string host_;
std::string port_; std::string port_;
HttpResponseHandler response_handler_; HttpResponseHandler response_handler_;
// Timeout in seconds; only effective when > 0.
int timeout_seconds_;
}; };
} // namespace webcc } // namespace webcc

@ -6,27 +6,31 @@ namespace webcc {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// NOTE: // NOTE: Field names are case-insensitive.
// Field names are case-insensitive. // See https://stackoverflow.com/a/5259004 for more details.
// See: https://stackoverflow.com/a/5259004 const std::string kHost = "Host";
const std::string kContentType = "Content-Type"; const std::string kContentType = "Content-Type";
const std::string kContentLength = "Content-Length"; const std::string kContentLength = "Content-Length";
#ifdef WEBCC_ENABLE_SOAP
const std::string kSoapAction = "SOAPAction"; const std::string kSoapAction = "SOAPAction";
const std::string kHost = "Host"; #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 // 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]. // Content-type header must be chosen as "application/soap+xml" [RFC 3902].
// But in practice, many web servers cannot understand it. // But in practice, many web servers cannot understand it.
// See: https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L26854 // See: https://www.w3.org/TR/2007/REC-soap12-part0-20070427/#L26854
const std::string kTextXmlUtf8 = "text/xml; charset=utf-8"; const std::string kTextXmlUtf8 = "text/xml; charset=utf-8";
#endif // WEBCC_ENABLE_SOAP
const std::string kTextJsonUtf8 = "text/json; charset=utf-8"; const std::string kHttpHead = "HEAD";
const std::string kHttpGet = "GET";
const std::string kHttpHead = "HEAD"; const std::string kHttpPost = "POST";
const std::string kHttpGet = "GET"; const std::string kHttpPatch = "PATCH";
const std::string kHttpPost = "POST"; const std::string kHttpPut = "PUT";
const std::string kHttpPatch = "PATCH";
const std::string kHttpPut = "PUT";
const std::string kHttpDelete = "DELETE"; const std::string kHttpDelete = "DELETE";
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -65,35 +69,27 @@ Parameter::Parameter(const std::string& key, std::string&& value)
} }
Parameter::Parameter(const std::string& key, int value) Parameter::Parameter(const std::string& key, int value)
: key_(key) { : key_(key), value_(std::to_string(value)) {
value_ = std::to_string(value);
} }
Parameter::Parameter(const std::string& key, double value) Parameter::Parameter(const std::string& key, double value)
: key_(key) { : key_(key), value_(std::to_string(value)) {
value_ = std::to_string(value);
} }
Parameter::Parameter(const std::string& key, bool value) Parameter::Parameter(const std::string& key, bool value)
: key_(key) { : key_(key), value_(value ? "true" : "false") {
value_ = value ? "true" : "false";
} }
Parameter::Parameter(Parameter&& rhs) Parameter::Parameter(Parameter&& rhs)
: key_(std::move(rhs.key_)), : key_(std::move(rhs.key_)), value_(std::move(rhs.value_)) {
value_(std::move(rhs.value_)) {
} }
Parameter& Parameter::operator=(Parameter&& rhs) { Parameter& Parameter::operator=(Parameter&& rhs) {
if (this != &rhs) { if (&rhs != this) {
key_ = std::move(rhs.key_); key_ = std::move(rhs.key_);
value_ = std::move(rhs.value_); value_ = std::move(rhs.value_);
} }
return *this; return *this;
} }
std::string Parameter::ToString() const {
return key_ + "=" + value_;
}
} // namespace webcc } // namespace webcc

@ -23,18 +23,25 @@ const std::size_t kBufferSize = 1024;
const std::size_t kInvalidLength = static_cast<std::size_t>(-1); const std::size_t kInvalidLength = static_cast<std::size_t>(-1);
// Timeout seconds. // Timeout seconds.
// TODO
const int kMaxConnectSeconds = 10; const int kMaxConnectSeconds = 10;
const int kMaxSendSeconds = 10; const int kMaxSendSeconds = 30;
const int kMaxReceiveSeconds = 30; const int kMaxReceiveSeconds = 30;
extern const std::string kHost;
extern const std::string kContentType; extern const std::string kContentType;
extern const std::string kContentLength; extern const std::string kContentLength;
#ifdef WEBCC_ENABLE_SOAP
extern const std::string kSoapAction; extern const std::string kSoapAction;
extern const std::string kHost; #endif // WEBCC_ENABLE_SOAP
extern const std::string kTextXmlUtf8;
extern const std::string kTextJsonUtf8; 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.). // HTTP methods (verbs) in string ("HEAD", "GET", etc.).
// NOTE: Don't use enum to avoid converting back and forth. // NOTE: Don't use enum to avoid converting back and forth.
extern const std::string kHttpHead; extern const std::string kHttpHead;
@ -99,25 +106,16 @@ class Parameter {
// Use "= default" if drop the support of VS 2013. // Use "= default" if drop the support of VS 2013.
Parameter& operator=(Parameter&& rhs); Parameter& operator=(Parameter&& rhs);
const std::string& key() const { const std::string& key() const { return key_; }
return key_; const std::string& value() const { return value_; }
}
const std::string& value() const { const char* c_key() const { return key_.c_str(); }
return value_; const char* c_value() const { return value_.c_str(); }
}
const char* c_key() const { std::string ToString() const {
return key_.c_str(); return key_ + "=" + value_;
} }
const char* c_value() const {
return value_.c_str();
}
// Return "key=value" string.
std::string ToString() const;
private: private:
std::string key_; std::string key_;
std::string value_; std::string value_;

@ -10,8 +10,6 @@
#include "boost/lambda/lambda.hpp" #include "boost/lambda/lambda.hpp"
#include "webcc/logger.h" #include "webcc/logger.h"
#include "webcc/http_request.h"
#include "webcc/http_response.h"
// NOTE: // NOTE:
// The timeout control is inspired by the following Asio example: // 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; std::size_t min_buffer_size = content_length / kMaxTimes;
if (min_buffer_size > buffer->size()) { if (min_buffer_size > buffer->size()) {
buffer->resize(std::min(min_buffer_size, kMaxBufferSize)); 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 { } else {
LOG_INFO("Keep the current buffer size (%d).", buffer->size()); LOG_INFO("Keep the current buffer size: %u.", buffer->size());
} }
} }
HttpClient::HttpClient() HttpClient::HttpClient()
: socket_(io_context_), : socket_(io_context_),
buffer_(kBufferSize), buffer_(kBufferSize),
deadline_(io_context_),
timeout_seconds_(kMaxReceiveSeconds), timeout_seconds_(kMaxReceiveSeconds),
deadline_(io_context_) { stopped_(false),
timed_out_(false),
error_(kNoError) {
} }
bool HttpClient::Request(const HttpRequest& request) { bool HttpClient::Request(const HttpRequest& request) {
@ -189,7 +190,7 @@ void HttpClient::DoReadResponse(Error* error) {
return; return;
} }
LOG_INFO("Read data, length: %d.", length); LOG_INFO("Read data, length: %u.", length);
bool content_length_parsed = response_parser_->content_length_parsed(); bool content_length_parsed = response_parser_->content_length_parsed();

@ -19,7 +19,6 @@ namespace webcc {
class HttpClient { class HttpClient {
public: public:
HttpClient(); HttpClient();
~HttpClient() = default; ~HttpClient() = default;
DELETE_COPY_AND_ASSIGN(HttpClient); DELETE_COPY_AND_ASSIGN(HttpClient);
@ -31,10 +30,10 @@ class HttpClient {
HttpResponsePtr response() const { return response_; } HttpResponsePtr response() const { return response_; }
Error error() const { return error_; }
bool timed_out() const { return timed_out_; } bool timed_out() const { return timed_out_; }
Error error() const { return error_; }
// Connect to server, send request, wait until response is received. // Connect to server, send request, wait until response is received.
bool Request(const HttpRequest& request); bool Request(const HttpRequest& request);
@ -53,7 +52,6 @@ class HttpClient {
void CheckDeadline(); void CheckDeadline();
boost::asio::io_context io_context_; boost::asio::io_context io_context_;
boost::asio::ip::tcp::socket socket_; boost::asio::ip::tcp::socket socket_;
std::vector<char> buffer_; std::vector<char> buffer_;
@ -61,18 +59,18 @@ class HttpClient {
HttpResponsePtr response_; HttpResponsePtr response_;
std::unique_ptr<HttpResponseParser> response_parser_; std::unique_ptr<HttpResponseParser> response_parser_;
Error error_ = kNoError; boost::asio::deadline_timer deadline_;
bool stopped_ = false;
// If the error was caused by timeout or not.
bool timed_out_ = false;
// Maximum seconds to wait before the client cancels the operation. // Maximum seconds to wait before the client cancels the operation.
// Only for receiving response from server. // Only for receiving response from server.
int timeout_seconds_; 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 } // namespace webcc

@ -91,7 +91,7 @@ void HttpConnection::AsyncWrite() {
void HttpConnection::WriteHandler(boost::system::error_code ec, void HttpConnection::WriteHandler(boost::system::error_code ec,
std::size_t length) { std::size_t length) {
if (!ec) { if (!ec) {
LOG_INFO("Response has been sent back."); LOG_INFO("Response has been sent back, length: %u.", length);
// Initiate graceful connection closure. // Initiate graceful connection closure.
boost::system::error_code ec; boost::system::error_code ec;

@ -18,7 +18,7 @@ class HttpRequestHandler;
class HttpConnection : public std::enable_shared_from_this<HttpConnection> { class HttpConnection : public std::enable_shared_from_this<HttpConnection> {
public: public:
HttpConnection(boost::asio::ip::tcp::socket socket, HttpConnection(boost::asio::ip::tcp::socket socket, // Will be moved
HttpRequestHandler* handler); HttpRequestHandler* handler);
~HttpConnection() = default; ~HttpConnection() = default;

@ -10,8 +10,7 @@
namespace webcc { namespace webcc {
class HttpHeader { struct HttpHeader {
public:
std::string name; std::string name;
std::string value; std::string value;
}; };
@ -21,20 +20,15 @@ class HttpMessage {
public: public:
virtual ~HttpMessage() = default; virtual ~HttpMessage() = default;
const std::string& start_line() const { const std::string& start_line() const { return start_line_; }
return start_line_;
}
void set_start_line(const std::string& start_line) { void set_start_line(const std::string& start_line) {
start_line_ = start_line; start_line_ = start_line;
} }
std::size_t content_length() const { std::size_t content_length() const { return content_length_; }
return content_length_;
}
const std::string& content() const { const std::string& content() const { return content_; }
return content_;
}
void SetHeader(const std::string& name, const std::string& value); void SetHeader(const std::string& name, const std::string& value);

@ -1,7 +1,6 @@
#include "webcc/http_parser.h" #include "webcc/http_parser.h"
#include "boost/algorithm/string.hpp" #include "boost/algorithm/string.hpp"
#include "boost/lexical_cast.hpp"
#include "webcc/http_message.h" #include "webcc/http_message.h"
#include "webcc/logger.h" #include "webcc/logger.h"
@ -111,23 +110,24 @@ void HttpParser::ParseContentLength(const std::string& line) {
std::string value = line.substr(pos); std::string value = line.substr(pos);
try { try {
content_length_ = boost::lexical_cast<std::size_t>(value); content_length_ = static_cast<std::size_t>(std::stoul(value));
LOG_INFO("Content length: %d", content_length_); } 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. // Reserve memory to avoid frequent reallocation when append.
try { content_.reserve(content_length_);
content_.reserve(content_length_); } catch (const std::exception& e) {
} catch (std::exception& e) { LOG_ERRO("Failed to reserve content memory: %s.", e.what());
LOG_ERRO("Failed to reserve content memory: %s.", e.what());
}
} catch (boost::bad_lexical_cast&) {
LOG_ERRO("Invalid content length: %s.", value.c_str());
} }
} }
} }
void HttpParser::Finish() { void HttpParser::Finish() {
// Move temp content to message. // Move content to message.
message_->SetContent(std::move(content_)); message_->SetContent(std::move(content_));
finished_ = true; finished_ = true;
} }

@ -40,8 +40,6 @@ class HttpParser {
// The result HTTP message. // The result HTTP message.
HttpMessage* message_; HttpMessage* message_;
Error error_;
// Data waiting to be parsed. // Data waiting to be parsed.
std::string pending_data_; std::string pending_data_;

@ -2,6 +2,17 @@
namespace webcc { 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) { void HttpRequest::SetHost(const std::string& host, const std::string& port) {
host_ = host; host_ = host;
port_ = port; 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! // ATTENTION: The buffers don't hold the memory!
std::vector<boost::asio::const_buffer> HttpRequest::ToBuffers() const { std::vector<boost::asio::const_buffer> HttpRequest::ToBuffers() const {
assert(!start_line_.empty()); assert(!start_line_.empty());

@ -19,29 +19,14 @@ class HttpRequest : public HttpMessage {
virtual ~HttpRequest() = default; virtual ~HttpRequest() = default;
const std::string& method() const { const std::string& method() const { return method_; }
return method_; void set_method(const std::string& method) { method_ = method; }
}
void set_method(const std::string& method) { const std::string& url() const { return url_; }
method_ = method; void set_url(const std::string& url) { url_ = url; }
}
const std::string& url() const { const std::string& host() const { return host_; }
return url_; const std::string& port() const { return port_; }
}
void set_url(const std::string& url) {
url_ = url;
}
const std::string& host() const {
return host_;
}
const std::string& port() const {
return port_;
}
// Set host name and port number. // Set host name and port number.
// The |host| is a descriptive name or a numeric IP address. The |port| is // The |host| is a descriptive name or a numeric IP address. The |port| is

@ -13,16 +13,13 @@ namespace webcc {
class HttpResponse : public HttpMessage { class HttpResponse : public HttpMessage {
public: public:
HttpResponse() = default; HttpResponse() : status_(HttpStatus::kOK) {
~HttpResponse() override = default;
int status() const {
return status_;
} }
void set_status(int status) { ~HttpResponse() override = default;
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 // Convert the response into a vector of buffers. The buffers do not own the
// underlying memory blocks, therefore the response object must remain valid // underlying memory blocks, therefore the response object must remain valid
@ -33,7 +30,7 @@ class HttpResponse : public HttpMessage {
static HttpResponse Fault(HttpStatus::Enum status); static HttpResponse Fault(HttpStatus::Enum status);
private: private:
int status_ = HttpStatus::kOK; int status_;
}; };
typedef std::shared_ptr<HttpResponse> HttpResponsePtr; typedef std::shared_ptr<HttpResponse> HttpResponsePtr;

@ -1,7 +1,5 @@
#include "webcc/http_response_parser.h" #include "webcc/http_response_parser.h"
#include "boost/lexical_cast.hpp"
#include "webcc/logger.h" #include "webcc/logger.h"
#include "webcc/http_response.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); std::string status_str = line.substr(off, pos - off);
try { try {
response_->set_status(boost::lexical_cast<int>(status_str)); response_->set_status(std::stoi(status_str));
} catch (boost::bad_lexical_cast&) { } catch (const std::exception&) {
LOG_ERRO("Invalid HTTP status: %s", status_str.c_str()); LOG_ERRO("Invalid HTTP status: %s", status_str.c_str());
return false; return false;
} }

@ -12,7 +12,7 @@ using tcp = boost::asio::ip::tcp;
namespace webcc { 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) { : signals_(io_context_) , workers_(workers) {
// Register to handle the signals that indicate when the server should exit. // 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, // It is safe to register for the same signal multiple times in a program,

@ -21,7 +21,7 @@ class HttpRequestHandler;
// NOTE: Only support IPv4. // NOTE: Only support IPv4.
class HttpServer { class HttpServer {
public: public:
HttpServer(unsigned short port, std::size_t workers); HttpServer(std::uint16_t port, std::size_t workers);
virtual ~HttpServer() = default; virtual ~HttpServer() = default;

@ -56,7 +56,7 @@ namespace bfs = boost::filesystem;
static bfs::path InitLogPath(const std::string& dir) { static bfs::path InitLogPath(const std::string& dir) {
if (dir.empty()) { if (dir.empty()) {
return bfs::current_path() / WEBCC_LOG_FILE; return bfs::current_path() / WEBCC_LOG_FILE_NAME;
} }
bfs::path path = bfs::path(dir); 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; return path;
} }

@ -8,18 +8,21 @@
#include <cstring> // for strrchr() #include <cstring> // for strrchr()
#include <string> #include <string>
#define WEBCC_VERB 0 // Log levels.
#define WEBCC_VERB 0 // Similar to DEBUG in other projects.
#define WEBCC_INFO 1 #define WEBCC_INFO 1
#define WEBCC_WARN 2 #define WEBCC_WARN 2
#define WEBCC_ERRO 3 #define WEBCC_ERRO 3
#define WEBCC_FATA 4 #define WEBCC_FATA 4
// Default log level. // 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 #ifndef WEBCC_LOG_LEVEL
#define WEBCC_LOG_LEVEL WEBCC_WARN #define WEBCC_LOG_LEVEL WEBCC_WARN
#endif #endif
#define WEBCC_LOG_FILE "webcc.log" #define WEBCC_LOG_FILE_NAME "webcc.log"
namespace webcc { namespace webcc {
@ -129,7 +132,7 @@ void LogWrite(int level, const char* file, int line, const char* format, ...);
#else // WEBCC_ENABLE_LOG == 0 #else // WEBCC_ENABLE_LOG == 0
#define WEBCC_LOG_INIT(modes) #define WEBCC_LOG_INIT(dir, modes)
#if (defined(WIN32) || defined(_WIN64)) #if (defined(WIN32) || defined(_WIN64))
#define LOG_VERB(format, ...) #define LOG_VERB(format, ...)

@ -5,10 +5,19 @@
namespace webcc { 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, bool RestClient::Request(const std::string& method,
const std::string& url, const std::string& url,
const std::string& content) { const std::string& content) {
response_.reset(); response_.reset();
error_ = kNoError; error_ = kNoError;
timed_out_ = false; timed_out_ = false;

@ -11,9 +11,11 @@ namespace webcc {
class RestClient { class RestClient {
public: public:
RestClient(const std::string& host, const std::string& port) RestClient(const std::string& host, const std::string& port);
: host_(host), port_(port) {
} ~RestClient() = default;
DELETE_COPY_AND_ASSIGN(RestClient);
void set_timeout_seconds(int timeout_seconds) { void set_timeout_seconds(int timeout_seconds) {
timeout_seconds_ = timeout_seconds; timeout_seconds_ = timeout_seconds;
@ -31,27 +33,27 @@ class RestClient {
return response_->content(); return response_->content();
} }
Error error() const { return error_; }
bool timed_out() const { return timed_out_; } 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, ""); 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); 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); 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); return Request(kHttpPatch, url, content);
} }
bool Delete(const std::string& url) { inline bool Delete(const std::string& url) {
return Request(kHttpDelete, url, ""); return Request(kHttpDelete, url, "");
} }
@ -64,14 +66,14 @@ class RestClient {
std::string port_; std::string port_;
// Timeout in seconds; only effective when > 0. // Timeout in seconds; only effective when > 0.
int timeout_seconds_ = 0; int timeout_seconds_;
HttpResponsePtr response_; HttpResponsePtr response_;
Error error_ = kNoError;
// If the error was caused by timeout or not. // If the error was caused by timeout or not.
bool timed_out_ = false; bool timed_out_;
Error error_;
}; };
} // namespace webcc } // namespace webcc

@ -13,7 +13,7 @@ namespace webcc {
class RestServer : public HttpServer { class RestServer : public HttpServer {
public: public:
RestServer(unsigned short port, std::size_t workers) RestServer(std::uint16_t port, std::size_t workers)
: HttpServer(port, workers) { : HttpServer(port, workers) {
} }

@ -53,8 +53,7 @@ class RestListService : public RestService {
protected: protected:
RestListService() = default; RestListService() = default;
virtual bool Get(const UrlQuery& query, virtual bool Get(const UrlQuery& query, std::string* response_content) {
std::string* response_content) {
return false; return false;
} }

@ -18,7 +18,8 @@ class SoapClient {
bool timed_out() const { return timed_out_; } bool timed_out() const { return timed_out_; }
protected: protected:
SoapClient() = default; SoapClient() : timeout_seconds_(0), timed_out_(false) {
}
// A generic wrapper to make a call. // A generic wrapper to make a call.
// NOTE: The parameters should be movable. // NOTE: The parameters should be movable.
@ -27,10 +28,10 @@ class SoapClient {
std::string* result); std::string* result);
// Timeout in seconds; only effective when > 0. // Timeout in seconds; only effective when > 0.
int timeout_seconds_ = 0; int timeout_seconds_;
// If the error was caused by timeout or not. // If the error was caused by timeout or not.
bool timed_out_ = false; bool timed_out_;
SoapNamespace soapenv_ns_; // SOAP envelope namespace. SoapNamespace soapenv_ns_; // SOAP envelope namespace.
SoapNamespace service_ns_; // Namespace for your web service. SoapNamespace service_ns_; // Namespace for your web service.

@ -12,7 +12,7 @@ namespace webcc {
class SoapServer : public HttpServer { class SoapServer : public HttpServer {
public: public:
SoapServer(unsigned short port, std::size_t workers) SoapServer(std::uint16_t port, std::size_t workers)
: HttpServer(port, workers) { : HttpServer(port, workers) {
} }

Loading…
Cancel
Save