diff --git a/example/rest/book_server/book_services.cc b/example/rest/book_server/book_services.cc index a3c4f69..39e916a 100644 --- a/example/rest/book_server/book_services.cc +++ b/example/rest/book_server/book_services.cc @@ -3,7 +3,6 @@ #include #include -#include "boost/lexical_cast.hpp" #include "boost/thread/thread.hpp" #include "json/json.h" #include "webcc/logger.h" diff --git a/example/rest/book_server/main.cc b/example/rest/book_server/main.cc index 6f1f5b0..02c03a0 100644 --- a/example/rest/book_server/main.cc +++ b/example/rest/book_server/main.cc @@ -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::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; } diff --git a/example/soap/calc_client/calc_client.cc b/example/soap/calc_client/calc_client.cc index 39f5ea8..e6e59ca 100644 --- a/example/soap/calc_client/calc_client.cc +++ b/example/soap/calc_client/calc_client.cc @@ -1,6 +1,7 @@ #include "calc_client.h" + #include -#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(result_str); - } catch (boost::bad_lexical_cast&) { + *result = std::stod(result_str); + } catch (const std::exception&) { return false; } diff --git a/example/soap/calc_server/calc_service.cc b/example/soap/calc_server/calc_service.cc index 4561260..0148241 100644 --- a/example/soap/calc_server/calc_service.cc +++ b/example/soap/calc_server/calc_service.cc @@ -1,10 +1,11 @@ #include "calc_service.h" +#include +#include + // 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(soap_request.GetParameter("x")); - *y = boost::lexical_cast(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; } diff --git a/example/soap/calc_server/main.cc b/example/soap/calc_server/main.cc index 3834ba4..a1584d8 100644 --- a/example/soap/calc_server/main.cc +++ b/example/soap/calc_server/main.cc @@ -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::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; } diff --git a/src/webcc/CMakeLists.txt b/src/webcc/CMakeLists.txt index 6969bd0..c8248ef 100644 --- a/src/webcc/CMakeLists.txt +++ b/src/webcc/CMakeLists.txt @@ -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 diff --git a/src/webcc/async_http_client.cc b/src/webcc/async_http_client.cc index 508dfee..f00b31f 100644 --- a/src/webcc/async_http_client.cc +++ b/src/webcc/async_http_client.cc @@ -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 request, @@ -31,6 +31,9 @@ Error AsyncHttpClient::Request(std::shared_ptr 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 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 { diff --git a/src/webcc/async_http_client.h b/src/webcc/async_http_client.h index c3c1d95..311bc01 100644 --- a/src/webcc/async_http_client.h +++ b/src/webcc/async_http_client.h @@ -16,6 +16,7 @@ namespace webcc { +// Request handler/callback. typedef std::function HttpResponseHandler; class AsyncHttpClient : public std::enable_shared_from_this { @@ -57,29 +58,26 @@ class AsyncHttpClient : public std::enable_shared_from_this { void CheckDeadline(); - bool stopped_ = false; - bool timed_out_ = false; - tcp::socket socket_; - - std::shared_ptr request_; - std::unique_ptr resolver_; tcp::resolver::results_type endpoints_; + std::shared_ptr request_; std::vector buffer_; - std::unique_ptr response_parser_; - HttpResponsePtr response_; + std::unique_ptr 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 HttpAsyncClientPtr; diff --git a/src/webcc/async_rest_client.cc b/src/webcc/async_rest_client.cc index d2c26ce..98d8319 100644 --- a/src/webcc/async_rest_client.cc +++ b/src/webcc/async_rest_client.cc @@ -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_); } diff --git a/src/webcc/async_rest_client.h b/src/webcc/async_rest_client.h index bde667c..0ef332b 100644 --- a/src/webcc/async_rest_client.h +++ b/src/webcc/async_rest_client.h @@ -3,16 +3,18 @@ #include -#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 diff --git a/src/webcc/globals.cc b/src/webcc/globals.cc index 85aced5..0bd937e 100644 --- a/src/webcc/globals.cc +++ b/src/webcc/globals.cc @@ -6,27 +6,31 @@ 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"; + +#ifdef WEBCC_ENABLE_SOAP 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 // 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"; +#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 kHttpPost = "POST"; -const std::string kHttpPatch = "PATCH"; -const std::string kHttpPut = "PUT"; +const std::string kHttpHead = "HEAD"; +const std::string kHttpGet = "GET"; +const std::string kHttpPost = "POST"; +const std::string kHttpPatch = "PATCH"; +const std::string kHttpPut = "PUT"; 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) - : 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 diff --git a/src/webcc/globals.h b/src/webcc/globals.h index 4208c12..8098a0a 100644 --- a/src/webcc/globals.h +++ b/src/webcc/globals.h @@ -23,18 +23,25 @@ const std::size_t kBufferSize = 1024; const std::size_t kInvalidLength = static_cast(-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; + +#ifdef WEBCC_ENABLE_SOAP extern const std::string kSoapAction; -extern const std::string kHost; +#endif // WEBCC_ENABLE_SOAP -extern const std::string kTextXmlUtf8; 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_; diff --git a/src/webcc/http_client.cc b/src/webcc/http_client.cc index 40694b6..9020afc 100644 --- a/src/webcc/http_client.cc +++ b/src/webcc/http_client.cc @@ -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* 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(); diff --git a/src/webcc/http_client.h b/src/webcc/http_client.h index cd940db..838d24e 100644 --- a/src/webcc/http_client.h +++ b/src/webcc/http_client.h @@ -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 buffer_; @@ -61,18 +59,18 @@ class HttpClient { HttpResponsePtr response_; std::unique_ptr 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 diff --git a/src/webcc/http_connection.cc b/src/webcc/http_connection.cc index 95f0a23..f8f6120 100644 --- a/src/webcc/http_connection.cc +++ b/src/webcc/http_connection.cc @@ -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; diff --git a/src/webcc/http_connection.h b/src/webcc/http_connection.h index 56981d1..644cbcd 100644 --- a/src/webcc/http_connection.h +++ b/src/webcc/http_connection.h @@ -18,7 +18,7 @@ class HttpRequestHandler; class HttpConnection : public std::enable_shared_from_this { public: - HttpConnection(boost::asio::ip::tcp::socket socket, + HttpConnection(boost::asio::ip::tcp::socket socket, // Will be moved HttpRequestHandler* handler); ~HttpConnection() = default; diff --git a/src/webcc/http_message.h b/src/webcc/http_message.h index 21a3778..d2f78a1 100644 --- a/src/webcc/http_message.h +++ b/src/webcc/http_message.h @@ -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); diff --git a/src/webcc/http_parser.cc b/src/webcc/http_parser.cc index 65c91e1..990d64a 100644 --- a/src/webcc/http_parser.cc +++ b/src/webcc/http_parser.cc @@ -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(value); - LOG_INFO("Content length: %d", content_length_); + content_length_ = static_cast(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. - try { - content_.reserve(content_length_); - } catch (std::exception& e) { - LOG_ERRO("Failed to reserve content memory: %s.", e.what()); - } - } catch (boost::bad_lexical_cast&) { - LOG_ERRO("Invalid content length: %s.", value.c_str()); + 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; } diff --git a/src/webcc/http_parser.h b/src/webcc/http_parser.h index 7fe8830..96fe392 100644 --- a/src/webcc/http_parser.h +++ b/src/webcc/http_parser.h @@ -40,8 +40,6 @@ class HttpParser { // The result HTTP message. HttpMessage* message_; - Error error_; - // Data waiting to be parsed. std::string pending_data_; diff --git a/src/webcc/http_request.cc b/src/webcc/http_request.cc index a2e0e32..b235245 100644 --- a/src/webcc/http_request.cc +++ b/src/webcc/http_request.cc @@ -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 HttpRequest::ToBuffers() const { assert(!start_line_.empty()); diff --git a/src/webcc/http_request.h b/src/webcc/http_request.h index f2bd237..1ed49ed 100644 --- a/src/webcc/http_request.h +++ b/src/webcc/http_request.h @@ -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 diff --git a/src/webcc/http_response.h b/src/webcc/http_response.h index d6a66b5..8f94e44 100644 --- a/src/webcc/http_response.h +++ b/src/webcc/http_response.h @@ -13,16 +13,13 @@ namespace webcc { class HttpResponse : public HttpMessage { public: - HttpResponse() = default; - ~HttpResponse() override = default; - - int status() const { - return status_; + HttpResponse() : status_(HttpStatus::kOK) { } - void set_status(int status) { - status_ = status; - } + ~HttpResponse() override = default; + + 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 HttpResponsePtr; diff --git a/src/webcc/http_response_parser.cc b/src/webcc/http_response_parser.cc index f21993b..f79083a 100644 --- a/src/webcc/http_response_parser.cc +++ b/src/webcc/http_response_parser.cc @@ -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(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; } diff --git a/src/webcc/http_server.cc b/src/webcc/http_server.cc index ec8cedc..146ea05 100644 --- a/src/webcc/http_server.cc +++ b/src/webcc/http_server.cc @@ -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, diff --git a/src/webcc/http_server.h b/src/webcc/http_server.h index 85afec0..17615a0 100644 --- a/src/webcc/http_server.h +++ b/src/webcc/http_server.h @@ -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; diff --git a/src/webcc/logger.cc b/src/webcc/logger.cc index a5889e2..6d31cac 100644 --- a/src/webcc/logger.cc +++ b/src/webcc/logger.cc @@ -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; } diff --git a/src/webcc/logger.h b/src/webcc/logger.h index 0b5a1ea..b8f37e9 100644 --- a/src/webcc/logger.h +++ b/src/webcc/logger.h @@ -8,18 +8,21 @@ #include // for strrchr() #include -#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, ...) diff --git a/src/webcc/rest_client.cc b/src/webcc/rest_client.cc index 0d4f878..466400f 100644 --- a/src/webcc/rest_client.cc +++ b/src/webcc/rest_client.cc @@ -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; diff --git a/src/webcc/rest_client.h b/src/webcc/rest_client.h index 9615281..28a9ede 100644 --- a/src/webcc/rest_client.h +++ b/src/webcc/rest_client.h @@ -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 diff --git a/src/webcc/rest_server.h b/src/webcc/rest_server.h index 82d3560..d1c5bcf 100644 --- a/src/webcc/rest_server.h +++ b/src/webcc/rest_server.h @@ -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) { } diff --git a/src/webcc/rest_service.h b/src/webcc/rest_service.h index 2fb1ec0..375a449 100644 --- a/src/webcc/rest_service.h +++ b/src/webcc/rest_service.h @@ -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; } diff --git a/src/webcc/soap_client.h b/src/webcc/soap_client.h index 522db54..b4d519b 100644 --- a/src/webcc/soap_client.h +++ b/src/webcc/soap_client.h @@ -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. diff --git a/src/webcc/soap_server.h b/src/webcc/soap_server.h index 200e9ad..043371b 100644 --- a/src/webcc/soap_server.h +++ b/src/webcc/soap_server.h @@ -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) { }