You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
111 lines
2.3 KiB
C++
111 lines
2.3 KiB
C++
![]()
7 years ago
|
#include "webcc/http_parser.h"
|
||
![]()
8 years ago
|
|
||
|
#include "boost/algorithm/string.hpp"
|
||
|
#include "boost/lexical_cast.hpp"
|
||
|
|
||
![]()
7 years ago
|
#include "webcc/http_message.h"
|
||
![]()
8 years ago
|
|
||
![]()
7 years ago
|
namespace webcc {
|
||
![]()
8 years ago
|
|
||
|
HttpParser::HttpParser(HttpMessage* message)
|
||
![]()
8 years ago
|
: message_(message)
|
||
|
, start_line_parsed_(false)
|
||
|
, header_parsed_(false)
|
||
|
, finished_(false) {
|
||
![]()
8 years ago
|
}
|
||
|
|
||
![]()
8 years ago
|
Error HttpParser::Parse(const char* data, size_t len) {
|
||
![]()
8 years ago
|
if (header_parsed_) {
|
||
|
// Add the data to the content.
|
||
|
message_->AppendContent(data, len);
|
||
|
|
||
|
if (message_->IsContentFull()) {
|
||
|
// All content has been read.
|
||
|
finished_ = true;
|
||
|
}
|
||
|
|
||
|
return kNoError;
|
||
|
}
|
||
|
|
||
|
pending_data_.append(data, len);
|
||
|
size_t off = 0;
|
||
|
|
||
|
while (true) {
|
||
![]()
8 years ago
|
size_t pos = pending_data_.find("\r\n", off);
|
||
![]()
8 years ago
|
if (pos == std::string::npos) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
![]()
8 years ago
|
if (pos == off) { // End of headers.
|
||
|
off = pos + 2; // Skip CRLF.
|
||
![]()
8 years ago
|
header_parsed_ = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
std::string line = pending_data_.substr(off, pos - off);
|
||
|
|
||
|
if (!start_line_parsed_) {
|
||
|
start_line_parsed_ = true;
|
||
![]()
8 years ago
|
Error error = ParseStartLine(line);
|
||
![]()
8 years ago
|
if (error != kNoError) {
|
||
|
return error;
|
||
|
}
|
||
|
} else {
|
||
|
// Currently, only Content-Length is important to us.
|
||
|
// Other fields are ignored.
|
||
![]()
8 years ago
|
if (!message_->IsContentLengthValid()) {
|
||
![]()
8 years ago
|
ParseContentLength(line);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
off = pos + 2; // Skip CRLF.
|
||
|
}
|
||
|
|
||
|
if (header_parsed_) {
|
||
|
// Headers just ended.
|
||
|
|
||
![]()
8 years ago
|
if (!message_->IsContentLengthValid()) {
|
||
![]()
8 years ago
|
// No Content-Length?
|
||
|
return kHttpContentLengthError;
|
||
|
}
|
||
|
|
||
|
message_->AppendContent(pending_data_.substr(off));
|
||
|
|
||
|
if (message_->IsContentFull()) {
|
||
|
// All content has been read.
|
||
|
finished_ = true;
|
||
|
}
|
||
|
} else {
|
||
|
// Save the unparsed piece for next parsing.
|
||
|
pending_data_ = pending_data_.substr(off);
|
||
|
}
|
||
|
|
||
|
return kNoError;
|
||
|
}
|
||
|
|
||
|
void HttpParser::ParseContentLength(const std::string& line) {
|
||
|
size_t pos = line.find(':');
|
||
|
if (pos == std::string::npos) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::string name = line.substr(0, pos);
|
||
|
|
||
![]()
8 years ago
|
if (boost::iequals(name, kContentLength)) {
|
||
![]()
8 years ago
|
++pos; // Skip ':'.
|
||
|
while (line[pos] == ' ') { // Skip spaces.
|
||
|
++pos;
|
||
|
}
|
||
|
|
||
|
std::string value = line.substr(pos);
|
||
|
|
||
|
try {
|
||
![]()
8 years ago
|
message_->SetContentLength(boost::lexical_cast<size_t>(value));
|
||
![]()
8 years ago
|
} catch (boost::bad_lexical_cast&) {
|
||
|
// TODO
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
} // namespace webcc
|