Rework the http header parsing.

master
Adam Gu 7 years ago
parent cbf3efbcba
commit 9b35d0f06c

@ -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<boost::asio::const_buffer> HttpMessage::ToBuffers() const {
assert(!start_line_.empty());

@ -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);

@ -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<std::string> 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::size_t>(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::size_t>(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.

@ -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();

@ -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();

@ -3,6 +3,7 @@
#include <cassert>
#include <string>
#include <utility> // 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_;

@ -151,8 +151,7 @@ std::vector<std::string> 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;

Loading…
Cancel
Save