diff --git a/CMakeLists.txt b/CMakeLists.txt index 17e0d48..846d813 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.1.0) project(webcc) -option(WEBCC_ENABLE_LOG "Enable console logger?" ON) +option(WEBCC_ENABLE_LOG "Enable logging?" ON) option(WEBCC_ENABLE_SOAP "Enable SOAP support (need pugixml)?" ON) option(WEBCC_BUILD_UNITTEST "Build unit test?" ON) option(WEBCC_BUILD_EXAMPLE "Build examples?" ON) diff --git a/README.md b/README.md index e1208d5..4abe4fc 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ A lot of C++11 features are used, e.g., `std::move`. But C++14 is not required. The following CMake options determine how you build the projects. They are quite self-explanatory. ```cmake -option(WEBCC_ENABLE_LOG "Enable console logger?" ON) +option(WEBCC_ENABLE_LOG "Enable logging?" ON) option(WEBCC_ENABLE_SOAP "Enable SOAP support (need pugixml)?" ON) option(WEBCC_BUILD_UNITTEST "Build unit test?" ON) option(WEBCC_BUILD_EXAMPLE "Build examples?" ON) diff --git a/example/rest_book_server/book_services.cc b/example/rest_book_server/book_services.cc index a561630..909d385 100644 --- a/example/rest_book_server/book_services.cc +++ b/example/rest_book_server/book_services.cc @@ -12,8 +12,7 @@ // In-memory test data. // There should be some database in a real product. -class Book { -public: +struct Book { std::string id; std::string title; double price; @@ -39,12 +38,10 @@ std::ostream& operator<<(std::ostream& os, const Book& book) { static const Book kNullBook{}; class BookStore { -public: + public: BookStore() = default; - const std::list& books() const { - return books_; - } + const std::list& books() const { return books_; } const Book& GetBook(const std::string& id) const { auto it = FindBook(id); @@ -80,20 +77,17 @@ public: return false; } -private: + private: std::list::const_iterator FindBook(const std::string& id) const { - return std::find_if(books_.begin(), - books_.end(), + return std::find_if(books_.begin(), books_.end(), [&id](const Book& book) { return book.id == id; }); } std::list::iterator FindBook(const std::string& id) { - return std::find_if(books_.begin(), - books_.end(), + return std::find_if(books_.begin(), books_.end(), [&id](Book& book) { return book.id == id; }); } -private: std::list books_; }; diff --git a/webcc/http_connection.h b/webcc/http_connection.h index bc98810..3d8896c 100644 --- a/webcc/http_connection.h +++ b/webcc/http_connection.h @@ -25,9 +25,7 @@ class HttpConnection : public std::enable_shared_from_this { DELETE_COPY_AND_ASSIGN(HttpConnection); - const HttpRequest& request() const { - return request_; - } + const HttpRequest& request() const { return request_; } // Start to read and process the client request. void Start(); diff --git a/webcc/http_response.cc b/webcc/http_response.cc index 64e561f..7ea4912 100644 --- a/webcc/http_response.cc +++ b/webcc/http_response.cc @@ -5,12 +5,12 @@ namespace webcc { namespace status_strings { const std::string OK = "HTTP/1.1 200 OK\r\n"; -const std::string CREATED = "HTTP/1.0 201 Created\r\n"; -const std::string ACCEPTED = "HTTP/1.0 202 Accepted\r\n"; -const std::string NO_CONTENT = "HTTP/1.0 204 No Content\r\n"; -const std::string NOT_MODIFIED = "HTTP/1.0 304 Not Modified\r\n"; +const std::string CREATED = "HTTP/1.1 201 Created\r\n"; +const std::string ACCEPTED = "HTTP/1.1 202 Accepted\r\n"; +const std::string NO_CONTENT = "HTTP/1.1 204 No Content\r\n"; +const std::string NOT_MODIFIED = "HTTP/1.1 304 Not Modified\r\n"; const std::string BAD_REQUEST = "HTTP/1.1 400 Bad Request\r\n"; -const std::string NOT_FOUND = "HTTP/1.0 404 Not Found\r\n"; +const std::string NOT_FOUND = "HTTP/1.1 404 Not Found\r\n"; const std::string INTERNAL_SERVER_ERROR = "HTTP/1.1 500 Internal Server Error\r\n"; const std::string NOT_IMPLEMENTED = "HTTP/1.1 501 Not Implemented\r\n"; diff --git a/webcc/http_response_parser.cc b/webcc/http_response_parser.cc index ff38ee3..1e95ceb 100644 --- a/webcc/http_response_parser.cc +++ b/webcc/http_response_parser.cc @@ -1,5 +1,7 @@ #include "webcc/http_response_parser.h" +#include "boost/algorithm/string.hpp" + #include "webcc/logger.h" #include "webcc/http_response.h" @@ -10,33 +12,20 @@ HttpResponseParser::HttpResponseParser(HttpResponse* response) } bool HttpResponseParser::ParseStartLine(const std::string& line) { - std::size_t off = 0; + std::vector splitted; + boost::split(splitted, line, boost::is_any_of(" "), boost::token_compress_on); - std::size_t pos = line.find(' '); - if (pos == std::string::npos) { + if (splitted.size() < 3) { + LOG_ERRO("Invalid HTTP response status line: %s", line.c_str()); return false; } - // HTTP version - - off = pos + 1; // Skip space. - - pos = line.find(' ', off); - if (pos == std::string::npos) { - return false; - } - - // Status code - std::string status_str = line.substr(off, pos - off); + std::string& status_str = splitted[1]; try { response_->set_status(std::stoi(status_str)); } catch (const std::exception&) { - LOG_ERRO("Invalid HTTP status: %s", status_str.c_str()); - return false; - } - - if (response_->status() != HttpStatus::kOK) { + LOG_ERRO("Invalid HTTP status code: %s", status_str.c_str()); return false; } diff --git a/webcc/rest_request_handler.cc b/webcc/rest_request_handler.cc index f0cafee..ab8b7c5 100644 --- a/webcc/rest_request_handler.cc +++ b/webcc/rest_request_handler.cc @@ -14,7 +14,9 @@ bool RestRequestHandler::Bind(RestServicePtr service, const std::string& url, } void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) { - Url url(connection->request().url(), true); + const HttpRequest& request = connection->request(); + + Url url(request.url(), true); if (!url.IsValid()) { connection->SendResponse(HttpStatus::kBadRequest); @@ -31,14 +33,14 @@ void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) { } UrlQuery query; - Url::SplitQuery(url.query(), &query); + if (request.method() == kHttpGet) { + // Suppose URL query is only available for HTTP GET. + Url::SplitQuery(url.query(), &query); + } std::string content; - bool ok = service->Handle(connection->request().method(), - sub_matches, - query, - connection->request().content(), - &content); + bool ok = service->Handle(request.method(), sub_matches, query, + request.content(), &content); if (!ok) { connection->SendResponse(HttpStatus::kBadRequest); return; @@ -47,7 +49,12 @@ void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) { if (!content.empty()) { connection->SetResponseContent(std::move(content), kAppJsonUtf8); } - connection->SendResponse(HttpStatus::kOK); + + if (request.method() == kHttpPost) { + connection->SendResponse(HttpStatus::kCreated); + } else { + connection->SendResponse(HttpStatus::kOK); + } } } // namespace webcc