diff --git a/webcc/http_message.cc b/webcc/http_message.cc index f7cf252..17c39e1 100644 --- a/webcc/http_message.cc +++ b/webcc/http_message.cc @@ -19,15 +19,24 @@ const char CRLF[] = { '\r', '\n' }; void HttpMessage::SetHeader(const std::string& name, const std::string& value) { for (HttpHeader& h : headers_) { - if (h.name == name) { + if (boost::iequals(h.name, name)) { h.value = value; return; } } - headers_.push_back({ name, value }); } +void HttpMessage::SetHeader(std::string&& name, std::string&& value) { + for (HttpHeader& h : headers_) { + if (boost::iequals(h.name, name)) { + h.value = std::move(value); + return; + } + } + headers_.push_back({ std::move(name), std::move(value) }); +} + // ATTENTION: The buffers don't hold the memory! std::vector HttpMessage::ToBuffers() const { assert(!start_line_.empty()); diff --git a/webcc/http_message.h b/webcc/http_message.h index c2ae305..3afcf73 100644 --- a/webcc/http_message.h +++ b/webcc/http_message.h @@ -36,6 +36,8 @@ class HttpMessage { void SetHeader(const std::string& name, const std::string& value); + void SetHeader(std::string&& name, std::string&& value); + // E.g., "text/xml; charset=utf-8" void SetContentType(const std::string& content_type) { SetHeader(kContentType, content_type); diff --git a/webcc/http_parser.cc b/webcc/http_parser.cc index 12bbdac..1124740 100644 --- a/webcc/http_parser.cc +++ b/webcc/http_parser.cc @@ -18,7 +18,7 @@ HttpParser::HttpParser(HttpMessage* message) bool HttpParser::Parse(const char* data, std::size_t length) { if (header_parsed_) { - // Add the data to the content. + // Append the data to the content. AppendContent(data, length); if (IsContentFull()) { @@ -29,6 +29,8 @@ bool HttpParser::Parse(const char* data, std::size_t length) { return true; } + // Continue to parse headers. + pending_data_.append(data, length); std::size_t off = 0; @@ -53,11 +55,7 @@ bool HttpParser::Parse(const char* data, std::size_t length) { return false; } } else { - // Currently, only Content-Length is important to us. - // Other header fields are ignored. - if (!content_length_parsed_) { - ParseContentLength(line); - } + ParseHeader(line); } off = pos + 2; // Skip CRLF. @@ -92,28 +90,28 @@ bool HttpParser::Parse(const char* data, std::size_t length) { return true; } -void HttpParser::ParseContentLength(const std::string& line) { - std::size_t pos = line.find(':'); - if (pos == std::string::npos) { - return; +bool HttpParser::ParseHeader(const std::string& line) { + std::vector splitted; + boost::split(splitted, line, boost::is_any_of(":")); + + if (splitted.size() != 2) { + return false; } - std::string name = line.substr(0, pos); + std::string& name = splitted[0]; + std::string& value = splitted[1]; - if (boost::iequals(name, kContentLength)) { - content_length_parsed_ = true; - - ++pos; // Skip ':'. - while (line[pos] == ' ') { // Skip spaces. - ++pos; - } + boost::trim(name); + boost::trim(value); - std::string value = line.substr(pos); + if (!content_length_parsed_ && boost::iequals(name, kContentLength)) { + content_length_parsed_ = true; try { content_length_ = static_cast(std::stoul(value)); } catch (const std::exception&) { LOG_ERRO("Invalid content length: %s.", value.c_str()); + return false; } LOG_INFO("Content length: %u.", content_length_); @@ -123,9 +121,49 @@ void HttpParser::ParseContentLength(const std::string& line) { content_.reserve(content_length_); } catch (const std::exception& e) { LOG_ERRO("Failed to reserve content memory: %s.", e.what()); + return false; } + } else { + message_->SetHeader(std::move(name), std::move(value)); } + + return true; } +// +//void HttpParser::ParseContentLength(const std::string& line) { +// std::size_t pos = line.find(':'); +// if (pos == std::string::npos) { +// return; +// } +// +// std::string name = line.substr(0, pos); +// +// if (boost::iequals(name, kContentLength)) { +// content_length_parsed_ = true; +// +// ++pos; // Skip ':'. +// while (line[pos] == ' ') { // Skip spaces. +// ++pos; +// } +// +// std::string value = line.substr(pos); +// +// try { +// content_length_ = static_cast(std::stoul(value)); +// } catch (const std::exception&) { +// 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 content to message. diff --git a/webcc/http_parser.h b/webcc/http_parser.h index 96fe392..ad75875 100644 --- a/webcc/http_parser.h +++ b/webcc/http_parser.h @@ -28,7 +28,9 @@ class HttpParser { protected: virtual bool ParseStartLine(const std::string& line) = 0; - void ParseContentLength(const std::string& line); + bool ParseHeader(const std::string& line); + + //void ParseContentLength(const std::string& line); void Finish(); diff --git a/webcc/rest_client.cc b/webcc/rest_client.cc index aa96ec8..545f0bc 100644 --- a/webcc/rest_client.cc +++ b/webcc/rest_client.cc @@ -13,9 +13,8 @@ RestClient::RestClient(const std::string& host, const std::string& port) error_(kNoError) { } -bool RestClient::Request(const std::string& method, - const std::string& url, - const std::string& content) { +bool RestClient::Request(const std::string& method, const std::string& url, + std::string&& content) { response_.reset(); error_ = kNoError; @@ -28,7 +27,8 @@ bool RestClient::Request(const std::string& method, request.SetHost(host_, port_); if (!content.empty()) { - request.SetContent(content); + request.SetContent(std::move(content)); + request.SetContentType(kTextJsonUtf8); } request.UpdateStartLine(); diff --git a/webcc/rest_client.h b/webcc/rest_client.h index 28a9ede..db1aa8c 100644 --- a/webcc/rest_client.h +++ b/webcc/rest_client.h @@ -3,6 +3,7 @@ #include #include +#include // for move() #include "webcc/globals.h" #include "webcc/http_response.h" @@ -41,16 +42,16 @@ class RestClient { return Request(kHttpGet, url, ""); } - inline bool Post(const std::string& url, const std::string& content) { - return Request(kHttpPost, url, content); + inline bool Post(const std::string& url, std::string&& content) { + return Request(kHttpPost, url, std::move(content)); } - inline bool Put(const std::string& url, const std::string& content) { - return Request(kHttpPut, url, content); + inline bool Put(const std::string& url, std::string&& content) { + return Request(kHttpPut, url, std::move(content)); } - inline bool Patch(const std::string& url, const std::string& content) { - return Request(kHttpPatch, url, content); + inline bool Patch(const std::string& url, std::string&& content) { + return Request(kHttpPatch, url, std::move(content)); } inline bool Delete(const std::string& url) { @@ -58,9 +59,8 @@ class RestClient { } private: - bool Request(const std::string& method, - const std::string& url, - const std::string& content); + bool Request(const std::string& method, const std::string& url, + std::string&& content); std::string host_; std::string port_; diff --git a/webcc/url.cc b/webcc/url.cc index b5bda58..b8c6a89 100644 --- a/webcc/url.cc +++ b/webcc/url.cc @@ -151,8 +151,7 @@ std::vector Url::SplitPath(const std::string& path) { } static bool SplitKeyValue(const std::string& kv, - std::string* key, - std::string* value) { + std::string* key, std::string* value) { std::size_t i = kv.find_first_of('='); if (i == std::string::npos || i == 0) { return false;