#include #include #include #include #include #include #include struct Header { std::string name; std::string value; }; struct Parser { Parser(); template InputIterator parseHeader(InputIterator begin, InputIterator end) { while(begin != end && !validHeader_) headerParser_(*begin++); auto length = std::find_if(headers_.begin(), headers_.end(), [](Header const& v) { return boost::iequals(v.name, "content-length"); }); if(length != headers_.end()) { try { contentLength_ = boost::lexical_cast(length->value); } catch(boost::bad_lexical_cast&) { validResult_ = false; } } if(validHeader_ && contentLength_ == 0) validResult_ = true; return begin; } template InputIterator parseContent(InputIterator begin, InputIterator end) { if(!validHeader_) throw "ERROR"; if(contentLength_ == 0) return begin; while(begin != end) { contentParser_(*begin++); if(validResult_ || !validResult_) return begin; } return begin; } std::vector
headers_; bool validHeader_; boost::tribool validResult_; std::size_t contentLength_; std::string content_; boost::coroutines::coroutine::push_type headerParser_; boost::coroutines::coroutine::push_type contentParser_; }; Parser::Parser(): headers_{}, validHeader_{false}, validResult_{boost::indeterminate}, contentLength_{0}, content_{}, headerParser_{[&](boost::coroutines::coroutine::pull_type& c) { while(c && c.get() != '\n') { Header hdr{}; // Name while(c.get() != ':') { hdr.name.push_back(c.get()); c(); } if(c.get() != ':') { validResult_ = false; return; } c(); // consume the colon // space while(c.get() == ' ' || c.get() == '\t') c(); // Value while(c.get() != '\n') { hdr.value.push_back(c.get()); c(); } if(c.get() != '\n') { validResult_ = false; return; } c(); // consume the newline headers_.push_back(std::move(hdr)); } if(c && c.get() == '\n') validHeader_ = true; else validResult_ = false; }}, contentParser_{[&](boost::coroutines::coroutine::pull_type& c) { if(c) content_.push_back(c.get()); while(content_.size() < contentLength_) { c(); if(c) content_.push_back(c.get()); } validResult_ = true; }} {} void test1() { std::string input = "Date: Mon, 10 Mar 10:43:00 GMT\n" "Content-Length: 15\n" "\n" "This is a test.\n"; Parser parser; auto pos = parser.parseHeader(input.begin(), input.end()); assert(pos != input.end()); assert(parser.validHeader_); assert(boost::indeterminate(parser.validResult_)); assert(parser.contentLength_ == 15); parser.parseContent(pos, input.end()); assert(parser.validResult_); assert(parser.content_.size() == 15); assert(parser.content_ == "This is a test."); } void test2() { std::string input = "(Date: Mon, 10 Mar 10:43:01 GMT\n" "Content-Length: 0\n" "\n"; Parser parser; auto pos = parser.parseHeader(input.begin(), input.end()); assert(pos == input.end()); assert(parser.validHeader_); assert(parser.validResult_); assert(parser.contentLength_ == 0); // No point in calling parser.parseContent(); } int main() { std::clog << "Running test 1..."; test1(); std::clog << "Test 1 completed.\n" << "Running test 2..."; test2(); std::clog << "Test 2 completed." << std::endl; return 0; }