Rework the body of request and response

This commit is contained in:
Chunting Gu
2019-07-03 17:37:44 +08:00
parent b9f2ba6a41
commit 98aeeae012
39 changed files with 1122 additions and 677 deletions
+51 -85
View File
@@ -22,12 +22,37 @@ const char CRLF[] = { '\r', '\n' };
// -----------------------------------------------------------------------------
std::ostream& operator<<(std::ostream& os, const Message& message) {
message.Dump(os);
return os;
Message::Message() : body_(new Body{}), content_length_(kInvalidLength) {
}
// -----------------------------------------------------------------------------
void Message::SetBody(BodyPtr body, bool set_length) {
if (body == body_) {
return;
}
if (!body) {
body_.reset(new Body{});
} else {
body_ = body;
}
if (set_length) {
content_length_ = body_->GetSize();
SetHeader(headers::kContentLength, std::to_string(content_length_));
}
}
const std::string& Message::data() const {
static const std::string kEmptyData;
auto string_body = std::dynamic_pointer_cast<StringBody>(body_);
if (string_body) {
return string_body->data();
}
return kEmptyData;
}
bool Message::IsConnectionKeepAlive() const {
using headers::kConnection;
@@ -51,12 +76,15 @@ ContentEncoding Message::GetContentEncoding() const {
using headers::kContentEncoding;
const std::string& encoding = GetHeader(kContentEncoding);
if (encoding == "gzip") {
return ContentEncoding::kGzip;
}
if (encoding == "deflate") {
return ContentEncoding::kDeflate;
}
return ContentEncoding::kUnknown;
}
@@ -66,7 +94,6 @@ bool Message::AcceptEncodingGzip() const {
return GetHeader(kAcceptEncoding).find("gzip") != std::string::npos;
}
// See: https://tools.ietf.org/html/rfc7231#section-3.1.1.1
void Message::SetContentType(const std::string& media_type,
const std::string& charset) {
using headers::kContentType;
@@ -74,108 +101,47 @@ void Message::SetContentType(const std::string& media_type,
if (charset.empty()) {
SetHeader(kContentType, media_type);
} else {
SetHeader(kContentType, media_type + ";charset=" + charset);
SetHeader(kContentType, media_type + "; charset=" + charset);
}
}
void Message::SetContent(std::string&& content, bool set_length) {
content_ = std::move(content);
if (set_length) {
SetContentLength(content_.size());
}
}
void Message::Prepare() {
assert(!start_line_.empty());
Payload Message::GetPayload() const {
using boost::asio::buffer;
payload_.clear();
Payload payload;
payload_.push_back(buffer(start_line_));
payload_.push_back(buffer(misc_strings::CRLF));
payload.push_back(buffer(start_line_));
payload.push_back(buffer(misc_strings::CRLF));
for (const Header& h : headers_.data()) {
payload_.push_back(buffer(h.first));
payload_.push_back(buffer(misc_strings::HEADER_SEPARATOR));
payload_.push_back(buffer(h.second));
payload_.push_back(buffer(misc_strings::CRLF));
payload.push_back(buffer(h.first));
payload.push_back(buffer(misc_strings::HEADER_SEPARATOR));
payload.push_back(buffer(h.second));
payload.push_back(buffer(misc_strings::CRLF));
}
payload_.push_back(buffer(misc_strings::CRLF));
payload.push_back(buffer(misc_strings::CRLF));
if (!content_.empty()) {
payload_.push_back(buffer(content_));
}
return payload;
}
void Message::CopyPayload(std::ostream& os) const {
for (const boost::asio::const_buffer& b : payload_) {
os.write(static_cast<const char*>(b.data()), b.size());
}
}
void Message::Dump(std::ostream& os) const {
const std::string prefix = " > ";
void Message::CopyPayload(std::string* str) const {
std::stringstream ss;
CopyPayload(ss);
*str = ss.str();
}
void Message::Dump(std::ostream& os, std::size_t indent,
const std::string& prefix) const {
std::string indent_str;
if (indent > 0) {
indent_str.append(indent, ' ');
}
indent_str.append(prefix);
os << indent_str << start_line_ << std::endl;
os << prefix << start_line_ << std::endl;
for (const Header& h : headers_.data()) {
os << indent_str << h.first << ": " << h.second << std::endl;
os << prefix << h.first << ": " << h.second << std::endl;
}
os << indent_str << std::endl;
os << prefix << std::endl;
// NOTE:
// - The content will be truncated if it's too large to display.
// - Binary content will not be dumped (TODO).
if (!content_.empty()) {
if (indent == 0) {
if (content_.size() > kMaxDumpSize) {
os.write(content_.c_str(), kMaxDumpSize);
os << "..." << std::endl;
} else {
os << content_ << std::endl;
}
} else {
// Split by EOL to achieve more readability.
std::vector<std::string> lines;
boost::split(lines, content_, boost::is_any_of("\n"));
std::size_t size = 0;
for (const std::string& line : lines) {
os << indent_str;
if (line.size() + size > kMaxDumpSize) {
os.write(line.c_str(), kMaxDumpSize - size);
os << "..." << std::endl;
break;
} else {
os << line << std::endl;
size += line.size();
}
}
}
}
body_->Dump(os, prefix);
}
std::string Message::Dump(std::size_t indent,
const std::string& prefix) const {
std::string Message::Dump() const {
std::stringstream ss;
Dump(ss, indent, prefix);
Dump(ss);
return ss.str();
}