Refine the parsing of start line; return 201 instead of 200 for POST request.
This commit is contained in:
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.1.0)
|
cmake_minimum_required(VERSION 3.1.0)
|
||||||
project(webcc)
|
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_ENABLE_SOAP "Enable SOAP support (need pugixml)?" ON)
|
||||||
option(WEBCC_BUILD_UNITTEST "Build unit test?" ON)
|
option(WEBCC_BUILD_UNITTEST "Build unit test?" ON)
|
||||||
option(WEBCC_BUILD_EXAMPLE "Build examples?" ON)
|
option(WEBCC_BUILD_EXAMPLE "Build examples?" ON)
|
||||||
|
|||||||
@@ -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.
|
The following CMake options determine how you build the projects. They are quite self-explanatory.
|
||||||
|
|
||||||
```cmake
|
```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_ENABLE_SOAP "Enable SOAP support (need pugixml)?" ON)
|
||||||
option(WEBCC_BUILD_UNITTEST "Build unit test?" ON)
|
option(WEBCC_BUILD_UNITTEST "Build unit test?" ON)
|
||||||
option(WEBCC_BUILD_EXAMPLE "Build examples?" ON)
|
option(WEBCC_BUILD_EXAMPLE "Build examples?" ON)
|
||||||
|
|||||||
@@ -12,8 +12,7 @@
|
|||||||
// In-memory test data.
|
// In-memory test data.
|
||||||
// There should be some database in a real product.
|
// There should be some database in a real product.
|
||||||
|
|
||||||
class Book {
|
struct Book {
|
||||||
public:
|
|
||||||
std::string id;
|
std::string id;
|
||||||
std::string title;
|
std::string title;
|
||||||
double price;
|
double price;
|
||||||
@@ -42,9 +41,7 @@ class BookStore {
|
|||||||
public:
|
public:
|
||||||
BookStore() = default;
|
BookStore() = default;
|
||||||
|
|
||||||
const std::list<Book>& books() const {
|
const std::list<Book>& books() const { return books_; }
|
||||||
return books_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Book& GetBook(const std::string& id) const {
|
const Book& GetBook(const std::string& id) const {
|
||||||
auto it = FindBook(id);
|
auto it = FindBook(id);
|
||||||
@@ -82,18 +79,15 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<Book>::const_iterator FindBook(const std::string& id) const {
|
std::list<Book>::const_iterator FindBook(const std::string& id) const {
|
||||||
return std::find_if(books_.begin(),
|
return std::find_if(books_.begin(), books_.end(),
|
||||||
books_.end(),
|
|
||||||
[&id](const Book& book) { return book.id == id; });
|
[&id](const Book& book) { return book.id == id; });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<Book>::iterator FindBook(const std::string& id) {
|
std::list<Book>::iterator FindBook(const std::string& id) {
|
||||||
return std::find_if(books_.begin(),
|
return std::find_if(books_.begin(), books_.end(),
|
||||||
books_.end(),
|
|
||||||
[&id](Book& book) { return book.id == id; });
|
[&id](Book& book) { return book.id == id; });
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
std::list<Book> books_;
|
std::list<Book> books_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ class HttpConnection : public std::enable_shared_from_this<HttpConnection> {
|
|||||||
|
|
||||||
DELETE_COPY_AND_ASSIGN(HttpConnection);
|
DELETE_COPY_AND_ASSIGN(HttpConnection);
|
||||||
|
|
||||||
const HttpRequest& request() const {
|
const HttpRequest& request() const { return request_; }
|
||||||
return request_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start to read and process the client request.
|
// Start to read and process the client request.
|
||||||
void Start();
|
void Start();
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ namespace webcc {
|
|||||||
namespace status_strings {
|
namespace status_strings {
|
||||||
|
|
||||||
const std::string OK = "HTTP/1.1 200 OK\r\n";
|
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 CREATED = "HTTP/1.1 201 Created\r\n";
|
||||||
const std::string ACCEPTED = "HTTP/1.0 202 Accepted\r\n";
|
const std::string ACCEPTED = "HTTP/1.1 202 Accepted\r\n";
|
||||||
const std::string NO_CONTENT = "HTTP/1.0 204 No Content\r\n";
|
const std::string NO_CONTENT = "HTTP/1.1 204 No Content\r\n";
|
||||||
const std::string NOT_MODIFIED = "HTTP/1.0 304 Not Modified\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 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 =
|
const std::string INTERNAL_SERVER_ERROR =
|
||||||
"HTTP/1.1 500 Internal Server Error\r\n";
|
"HTTP/1.1 500 Internal Server Error\r\n";
|
||||||
const std::string NOT_IMPLEMENTED = "HTTP/1.1 501 Not Implemented\r\n";
|
const std::string NOT_IMPLEMENTED = "HTTP/1.1 501 Not Implemented\r\n";
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "webcc/http_response_parser.h"
|
#include "webcc/http_response_parser.h"
|
||||||
|
|
||||||
|
#include "boost/algorithm/string.hpp"
|
||||||
|
|
||||||
#include "webcc/logger.h"
|
#include "webcc/logger.h"
|
||||||
#include "webcc/http_response.h"
|
#include "webcc/http_response.h"
|
||||||
|
|
||||||
@@ -10,33 +12,20 @@ HttpResponseParser::HttpResponseParser(HttpResponse* response)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HttpResponseParser::ParseStartLine(const std::string& line) {
|
bool HttpResponseParser::ParseStartLine(const std::string& line) {
|
||||||
std::size_t off = 0;
|
std::vector<std::string> splitted;
|
||||||
|
boost::split(splitted, line, boost::is_any_of(" "), boost::token_compress_on);
|
||||||
|
|
||||||
std::size_t pos = line.find(' ');
|
if (splitted.size() < 3) {
|
||||||
if (pos == std::string::npos) {
|
LOG_ERRO("Invalid HTTP response status line: %s", line.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP version
|
std::string& status_str = splitted[1];
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response_->set_status(std::stoi(status_str));
|
response_->set_status(std::stoi(status_str));
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
LOG_ERRO("Invalid HTTP status: %s", status_str.c_str());
|
LOG_ERRO("Invalid HTTP status code: %s", status_str.c_str());
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response_->status() != HttpStatus::kOK) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ bool RestRequestHandler::Bind(RestServicePtr service, const std::string& url,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) {
|
void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) {
|
||||||
Url url(connection->request().url(), true);
|
const HttpRequest& request = connection->request();
|
||||||
|
|
||||||
|
Url url(request.url(), true);
|
||||||
|
|
||||||
if (!url.IsValid()) {
|
if (!url.IsValid()) {
|
||||||
connection->SendResponse(HttpStatus::kBadRequest);
|
connection->SendResponse(HttpStatus::kBadRequest);
|
||||||
@@ -31,14 +33,14 @@ void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UrlQuery query;
|
UrlQuery query;
|
||||||
|
if (request.method() == kHttpGet) {
|
||||||
|
// Suppose URL query is only available for HTTP GET.
|
||||||
Url::SplitQuery(url.query(), &query);
|
Url::SplitQuery(url.query(), &query);
|
||||||
|
}
|
||||||
|
|
||||||
std::string content;
|
std::string content;
|
||||||
bool ok = service->Handle(connection->request().method(),
|
bool ok = service->Handle(request.method(), sub_matches, query,
|
||||||
sub_matches,
|
request.content(), &content);
|
||||||
query,
|
|
||||||
connection->request().content(),
|
|
||||||
&content);
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
connection->SendResponse(HttpStatus::kBadRequest);
|
connection->SendResponse(HttpStatus::kBadRequest);
|
||||||
return;
|
return;
|
||||||
@@ -47,7 +49,12 @@ void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) {
|
|||||||
if (!content.empty()) {
|
if (!content.empty()) {
|
||||||
connection->SetResponseContent(std::move(content), kAppJsonUtf8);
|
connection->SetResponseContent(std::move(content), kAppJsonUtf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.method() == kHttpPost) {
|
||||||
|
connection->SendResponse(HttpStatus::kCreated);
|
||||||
|
} else {
|
||||||
connection->SendResponse(HttpStatus::kOK);
|
connection->SendResponse(HttpStatus::kOK);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webcc
|
} // namespace webcc
|
||||||
|
|||||||
Reference in New Issue
Block a user