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++

#include "csoap/http_parser.h"
#include "boost/algorithm/string.hpp"
#include "boost/lexical_cast.hpp"
#include "csoap/http_message.h"
namespace csoap {
HttpParser::HttpParser(HttpMessage* message)
: message_(message)
, start_line_parsed_(false)
, header_parsed_(false)
, finished_(false) {
}
Error HttpParser::Parse(const char* data, size_t len) {
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) {
size_t pos = pending_data_.find("\r\n", off);
if (pos == std::string::npos) {
break;
}
if (pos == off) { // End of headers.
off = pos + 2; // Skip CRLF.
header_parsed_ = true;
break;
}
std::string line = pending_data_.substr(off, pos - off);
if (!start_line_parsed_) {
start_line_parsed_ = true;
Error error = ParseStartLine(line);
if (error != kNoError) {
return error;
}
} else {
// Currently, only Content-Length is important to us.
// Other fields are ignored.
if (!message_->IsContentLengthValid()) {
ParseContentLength(line);
}
}
off = pos + 2; // Skip CRLF.
}
if (header_parsed_) {
// Headers just ended.
if (!message_->IsContentLengthValid()) {
// 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);
if (boost::iequals(name, kContentLength)) {
++pos; // Skip ':'.
while (line[pos] == ' ') { // Skip spaces.
++pos;
}
std::string value = line.substr(pos);
try {
message_->SetContentLength(boost::lexical_cast<size_t>(value));
} catch (boost::bad_lexical_cast&) {
// TODO
}
}
}
} // namespace csoap