Refine the parsing of response status line; add UT for utility.

This commit is contained in:
Chunting Gu
2019-05-31 13:43:44 +08:00
parent 78743e6a55
commit 2035c1f552
10 changed files with 81 additions and 21 deletions
+2 -2
View File
@@ -98,7 +98,7 @@ std::vector<Header>::iterator Headers::Find(const std::string& key) {
static bool ParseValue(const std::string& str, const std::string& expected_key,
std::string* value) {
std::string key;
if (!Split2(str, '=', &key, value)) {
if (!SplitKV(str, '=', &key, value)) {
return false;
}
@@ -182,7 +182,7 @@ bool ContentDisposition::Init(const std::string& str) {
std::string key;
std::string value;
for (std::size_t i = 1; i < parts.size(); ++i) {
if (!Split2(parts[i], '=', &key, &value)) {
if (!SplitKV(parts[i], '=', &key, &value)) {
return false;
}
+1 -1
View File
@@ -138,7 +138,7 @@ bool Parser::GetNextLine(std::size_t off, std::string* line, bool erase) {
bool Parser::ParseHeaderLine(const std::string& line) {
Header header;
if (!Split2(line, ':', &header.first, &header.second)) {
if (!SplitKV(line, ':', &header.first, &header.second)) {
LOG_ERRO("Invalid header: %s", line.c_str());
return false;
}
+1 -1
View File
@@ -167,7 +167,7 @@ bool RequestParser::ParsePartHeaders(bool* need_more_data) {
}
Header header;
if (!Split2(line, ':', &header.first, &header.second)) {
if (!SplitKV(line, ':', &header.first, &header.second)) {
LOG_ERRO("Invalid part header line: %s", line.c_str());
return false;
}
+10 -2
View File
@@ -27,11 +27,19 @@ public:
status_ = status;
}
// Set start line according to status code.
const std::string& reason() const {
return reason_;
}
void set_reason(const std::string& reason) {
reason_ = reason;
}
void Prepare() override;
private:
int status_;
int status_; // Status code
std::string reason_; // Reason phrase
};
} // namespace webcc
+40 -9
View File
@@ -16,25 +16,56 @@ void ResponseParser::Init(Response* response) {
response_ = response;
}
// TODO: Keep the original message.
namespace {
void SplitStartLine(const std::string& line, std::vector<std::string>* parts) {
const char SPACE = ' ';
std::size_t off = 0;
std::size_t pos = 0;
for (std::size_t i = 0; i < 2; ++i) {
pos = line.find(SPACE, off);
if (pos == std::string::npos) {
break;
}
parts->push_back(line.substr(off, pos - off));
off = pos + 1;
for (; off < line.size() && line[off] == SPACE; ++off) {}
}
if (off < line.size()) {
parts->push_back(line.substr(off));
}
}
} // namespace
bool ResponseParser::ParseStartLine(const std::string& line) {
std::vector<std::string> parts;
boost::split(parts, line, boost::is_any_of(" "), boost::token_compress_on);
SplitStartLine(line, &parts);
if (parts.size() < 3) {
if (parts.size() != 3) {
LOG_ERRO("Invalid HTTP response status line: %s", line.c_str());
return false;
}
std::string& status_str = parts[1];
try {
response_->set_status(std::stoi(status_str));
} catch (const std::exception&) {
LOG_ERRO("Invalid HTTP status code: %s", status_str.c_str());
if (!boost::starts_with(parts[0], "HTTP/1.")) {
LOG_ERRO("Invalid HTTP version: %s", parts[0].c_str());
return false;
}
try {
response_->set_status(std::stoi(parts[1]));
} catch (const std::exception&) {
LOG_ERRO("Invalid HTTP status code: %s", parts[1].c_str());
return false;
}
response_->set_reason(parts[2]);
return true;
}
+3 -3
View File
@@ -15,9 +15,9 @@ std::string RandomUuid() {
return ss.str();
}
bool Split2(const std::string& str, char token, std::string* part1,
std::string* part2) {
std::size_t pos = str.find(token);
bool SplitKV(const std::string& str, char delimiter,
std::string* part1, std::string* part2) {
std::size_t pos = str.find(delimiter);
if (pos == std::string::npos) {
return false;
}
+4 -3
View File
@@ -7,9 +7,10 @@ namespace webcc {
std::string RandomUuid();
// Split a string to two parts by the given token.
bool Split2(const std::string& str, char token, std::string* part1,
std::string* part2);
// Split a key-value string.
// E.g., split "Connection: Keep-Alive".
bool SplitKV(const std::string& str, char delimiter,
std::string* key, std::string* value);
} // namespace webcc