Fix HTTP split parse edge case:

fix #257

This fixes a problem when doing split parsing (header then body).
The problem arises when the first buffer passed to the header
parser contains exactly the full header and nothing more. The
symptom is that when parsing the body, the parse will erroneously
be considered complete.
This commit is contained in:
Vinnie Falco
2017-07-20 08:12:15 -07:00
parent dbfb7718fc
commit 2b799b6371
4 changed files with 79 additions and 64 deletions
+69 -59
View File
@@ -25,64 +25,8 @@ class parser_v1_test
, public test::enable_yield_to
{
public:
void testRegressions()
{
using boost::asio::buffer;
// consecutive empty header values
{
error_code ec;
parser_v1<true, string_body, fields> p;
std::string const s =
"GET / HTTP/1.1\r\n"
"X1:\r\n"
"X2:\r\n"
"X3:x\r\n"
"\r\n";
p.write(buffer(s), ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
BEAST_EXPECT(p.complete());
auto const msg = p.release();
BEAST_EXPECT(msg.fields.exists("X1"));
BEAST_EXPECT(msg.fields["X1"] == "");
BEAST_EXPECT(msg.fields.exists("X2"));
BEAST_EXPECT(msg.fields["X2"] == "");
BEAST_EXPECT(msg.fields.exists("X3"));
BEAST_EXPECT(msg.fields["X3"] == "x");
}
}
void testWithBody()
{
test::string_istream ss{ios_,
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*"};
streambuf rb;
header_parser_v1<true, fields> p0;
parse(ss, rb, p0);
request_header const& reqh = p0.get();
BEAST_EXPECT(reqh.method == "GET");
BEAST_EXPECT(reqh.url == "/");
BEAST_EXPECT(reqh.version == 11);
BEAST_EXPECT(reqh.fields["User-Agent"] == "test");
BEAST_EXPECT(reqh.fields["Content-Length"] == "1");
parser_v1<true, string_body, fields> p =
with_body<string_body>(p0);
BEAST_EXPECT(p.get().method == "GET");
BEAST_EXPECT(p.get().url == "/");
BEAST_EXPECT(p.get().version == 11);
BEAST_EXPECT(p.get().fields["User-Agent"] == "test");
BEAST_EXPECT(p.get().fields["Content-Length"] == "1");
parse(ss, rb, p);
request<string_body, fields> req = p.release();
BEAST_EXPECT(req.body == "*");
}
void run() override
void
testParse()
{
using boost::asio::buffer;
{
@@ -138,9 +82,75 @@ public:
BEAST_EXPECT(! ec);
BEAST_EXPECT(p.complete());
}
}
testRegressions();
void
testWithBody()
{
std::string const raw =
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*";
test::string_istream ss{
ios_, raw, raw.size() - 1};
streambuf rb;
header_parser_v1<true, fields> p0;
parse(ss, rb, p0);
request_header const& reqh = p0.get();
BEAST_EXPECT(reqh.method == "GET");
BEAST_EXPECT(reqh.url == "/");
BEAST_EXPECT(reqh.version == 11);
BEAST_EXPECT(reqh.fields["User-Agent"] == "test");
BEAST_EXPECT(reqh.fields["Content-Length"] == "1");
parser_v1<true, string_body, fields> p =
with_body<string_body>(p0);
BEAST_EXPECT(p.get().method == "GET");
BEAST_EXPECT(p.get().url == "/");
BEAST_EXPECT(p.get().version == 11);
BEAST_EXPECT(p.get().fields["User-Agent"] == "test");
BEAST_EXPECT(p.get().fields["Content-Length"] == "1");
parse(ss, rb, p);
request<string_body, fields> req = p.release();
BEAST_EXPECT(req.body == "*");
}
void
testRegressions()
{
using boost::asio::buffer;
// consecutive empty header values
{
error_code ec;
parser_v1<true, string_body, fields> p;
std::string const s =
"GET / HTTP/1.1\r\n"
"X1:\r\n"
"X2:\r\n"
"X3:x\r\n"
"\r\n";
p.write(buffer(s), ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
BEAST_EXPECT(p.complete());
auto const msg = p.release();
BEAST_EXPECT(msg.fields.exists("X1"));
BEAST_EXPECT(msg.fields["X1"] == "");
BEAST_EXPECT(msg.fields.exists("X2"));
BEAST_EXPECT(msg.fields["X2"] == "");
BEAST_EXPECT(msg.fields.exists("X3"));
BEAST_EXPECT(msg.fields["X3"] == "x");
}
}
void run() override
{
testParse();
testWithBody();
testRegressions();
}
};