Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
enhancing response incremental parser
  • Loading branch information
leecoder committed Jun 26, 2014
commit 80826f0c14d91edc6c369fcd23c9a2b858e24091
47 changes: 33 additions & 14 deletions boost/network/protocol/http/parser/incremental.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,26 +168,35 @@ namespace boost { namespace network { namespace http {
} else if (*current == ' ') {
state_ = http_status_done;
++current;
} else if (*current == '\r' || *current == '\n') {
state_ = http_status_done;
} else {
parsed_ok = false;
}
break;
case http_status_done:
if (algorithm::is_alnum()(*current)) {
state_ = http_status_message_char;
if (*current == ' ') {
++current;
} else if (*current == '\r') {
state_ = http_status_message_cr;
++current;
} else if (*current == '\n') {
state_ = http_status_message_done;
++current;
} else {
parsed_ok = false;
state_ = http_status_message_char;
++current;
}
break;
case http_status_message_char:
if (algorithm::is_alnum()(*current) || algorithm::is_punct()(*current) || (*current == ' ')) {
++current;
} else if (*current == '\r') {
if (*current == '\r') {
state_ = http_status_message_cr;
++current;
} else if (*current == '\n') {
state_ = http_status_message_done;
++current;
} else {
parsed_ok = false;
++current;
}
break;
case http_status_message_cr:
Expand All @@ -200,12 +209,17 @@ namespace boost { namespace network { namespace http {
break;
case http_status_message_done:
case http_header_line_done:
if (algorithm::is_alnum()(*current)) {
if (*current == ' ') {
++current;
} else if (algorithm::is_alnum()(*current) || algorithm::is_punct()(*current)) {
state_ = http_header_name_char;
++current;
} else if (*current == '\r') {
state_ = http_headers_end_cr;
++current;
} else if (*current == '\n') {
state_ = http_headers_done;
++current;
} else {
parsed_ok = false;
}
Expand All @@ -221,21 +235,26 @@ namespace boost { namespace network { namespace http {
}
break;
case http_header_colon:
if (algorithm::is_space()(*current)) {
if (*current == '\r') {
state_ = http_header_line_cr;
++current;
} else if (algorithm::is_alnum()(*current) || algorithm::is_punct()(*current)) {
state_ = http_header_value_char;
} else if (*current == '\n') {
state_ = http_header_line_done;
++current;
} else if (algorithm::is_space()(*current)) {
++current;
} else {
parsed_ok = false;
state_ = http_header_value_char;
++current;
}
break;
case http_header_value_char:
if (*current == '\r') {
state_ = http_header_line_cr;
++current;
} else if (algorithm::is_cntrl()(*current)) {
parsed_ok = false;
} else if (*current == '\n') {
state_ = http_header_line_done;
++current;
} else {
++current;
}
Expand Down
1 change: 1 addition & 0 deletions libs/network/test/http/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ endif()

if (Boost_FOUND)
set ( TESTS
response_incremental_parser_test
request_incremental_parser_test
request_linearize_test
)
Expand Down
151 changes: 144 additions & 7 deletions libs/network/test/http/response_incremental_parser_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ namespace logic = boost::logic;
namespace fusion = boost::fusion;
using namespace boost::network::http;

struct crlf {
static const std::string literal;
};
const std::string crlf::literal = "\r\n";
struct lf {
static const std::string literal;
};
const std::string lf::literal = "\n";
typedef boost::mpl::vector<crlf, lf> eol_types;


BOOST_AUTO_TEST_CASE(incremental_parser_constructor) {
response_parser<tags::default_string> p; // default constructible
}
Expand Down Expand Up @@ -114,7 +125,7 @@ BOOST_AUTO_TEST_CASE(incremental_parser_parse_http_version) {
* the parser doesn't do any conversions from string to integer
* and outsource that part to the user of the parser.
*/
BOOST_AUTO_TEST_CASE(incremental_parser_parse_status) {
BOOST_AUTO_TEST_CASE_TEMPLATE(incremental_parser_parse_status, eol, eol_types) {
typedef response_parser<tags::default_string> response_parser_type;
typedef boost::iterator_range<std::string::const_iterator> range_type;
// We want to create a parser that has been initialized to a specific
Expand All @@ -140,17 +151,25 @@ BOOST_AUTO_TEST_CASE(incremental_parser_parse_status) {
BOOST_CHECK_EQUAL(parsed_ok, false);
parsed = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl;

valid_status = "200" + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_status_done,
valid_status);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl;
}

/** In this test then we get the rest of the first line of the HTTP
* Response, and treat it as the status message.
*/
BOOST_AUTO_TEST_CASE(incremental_parser_parse_status_message) {
BOOST_AUTO_TEST_CASE_TEMPLATE(incremental_parser_parse_status_message, eol, eol_types) {
typedef response_parser<tags::default_string> response_parser_type;
typedef boost::iterator_range<std::string::const_iterator> range_type;
response_parser_type p(response_parser_type::http_status_done);

std::string valid_status_message = "OK\r\nServer: Foo";
std::string valid_status_message = "OK" + eol::literal + "Server: Foo";
logic::tribool parsed_ok;
range_type result_range;
fusion::tie(parsed_ok, result_range) = p.parse_until(
Expand All @@ -161,7 +180,25 @@ BOOST_AUTO_TEST_CASE(incremental_parser_parse_status_message) {
std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl;

p.reset(response_parser_type::http_status_done);
valid_status_message = "OK\r\n";
valid_status_message = "OK" + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_status_message_done,
valid_status_message);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl;

p.reset(response_parser_type::http_status_done);
valid_status_message = "Internal Server Error" + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_status_message_done,
valid_status_message);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl;

p.reset(response_parser_type::http_status_done);
valid_status_message = eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_status_message_done,
valid_status_message);
Expand All @@ -170,7 +207,7 @@ BOOST_AUTO_TEST_CASE(incremental_parser_parse_status_message) {
std::cout << "PARSED: " << parsed << " state=" << p.state() << std::endl;

p.reset(response_parser_type::http_status_done);
valid_status_message = "Internal Server Error\r\n";
valid_status_message = "한글메시지" + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_status_message_done,
valid_status_message);
Expand All @@ -181,12 +218,12 @@ BOOST_AUTO_TEST_CASE(incremental_parser_parse_status_message) {

/** This test specifices how one-line-per-header parsing happens incrementally.
*/
BOOST_AUTO_TEST_CASE(incremental_parser_parse_header_lines) {
BOOST_AUTO_TEST_CASE_TEMPLATE(incremental_parser_parse_header_lines, eol, eol_types) {
typedef response_parser<tags::default_string> response_parser_type;
typedef boost::iterator_range<std::string::const_iterator> range_type;
response_parser_type p(response_parser_type::http_status_message_done);

std::string valid_headers = "Server: Foo\r\nContent-Type: application/json\r\n\r\n";
std::string valid_headers = "Server: Foo" + eol::literal + "Content-Type: application/json" + eol::literal + eol::literal;
logic::tribool parsed_ok;
range_type result_range;
fusion::tie(parsed_ok, result_range) = p.parse_until(
Expand All @@ -211,5 +248,105 @@ BOOST_AUTO_TEST_CASE(incremental_parser_parse_header_lines) {
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
BOOST_CHECK(parsed1 != parsed2);

p.reset(response_parser_type::http_status_message_done);
valid_headers = " Server: Foo" + eol::literal + " Content-Type: application/json" + eol::literal + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed1 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl;
p.reset(response_parser_type::http_status_message_done);
end = valid_headers.end();
valid_headers.assign(boost::end(result_range), end);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed2 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl;
valid_headers.assign(boost::end(result_range), end);
p.reset(response_parser_type::http_status_message_done);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_headers_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
BOOST_CHECK(parsed1 != parsed2);

p.reset(response_parser_type::http_status_message_done);
valid_headers = "_Server: Foo" + eol::literal + "_Content-Type: application/json" + eol::literal + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed1 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl;
p.reset(response_parser_type::http_status_message_done);
end = valid_headers.end();
valid_headers.assign(boost::end(result_range), end);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed2 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl;
valid_headers.assign(boost::end(result_range), end);
p.reset(response_parser_type::http_status_message_done);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_headers_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
BOOST_CHECK(parsed1 != parsed2);

p.reset(response_parser_type::http_status_message_done);
valid_headers = "Server: " + eol::literal + "Content-Type: application/json" + eol::literal + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed1 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl;
p.reset(response_parser_type::http_status_message_done);
end = valid_headers.end();
valid_headers.assign(boost::end(result_range), end);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed2 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl;
valid_headers.assign(boost::end(result_range), end);
p.reset(response_parser_type::http_status_message_done);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_headers_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
BOOST_CHECK(parsed1 != parsed2);

p.reset(response_parser_type::http_status_message_done);
valid_headers = "Server: 서버" + eol::literal + "Content-Type: application/json" + eol::literal + eol::literal;
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed1 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed1 << " state=" << p.state() << std::endl;
p.reset(response_parser_type::http_status_message_done);
end = valid_headers.end();
valid_headers.assign(boost::end(result_range), end);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_header_line_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
parsed2 = std::string(boost::begin(result_range), boost::end(result_range));
std::cout << "PARSED: " << parsed2 << " state=" << p.state() << std::endl;
valid_headers.assign(boost::end(result_range), end);
p.reset(response_parser_type::http_status_message_done);
fusion::tie(parsed_ok, result_range) = p.parse_until(
response_parser_type::http_headers_done,
valid_headers);
BOOST_CHECK_EQUAL(parsed_ok, true);
BOOST_CHECK(parsed1 != parsed2);
}