Files
beast/test/http/parser_v1.cpp
T
Vinnie Falco 195f974872 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.
2017-02-07 19:59:04 -05:00

161 lines
4.8 KiB
C++

//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/http/parser_v1.hpp>
#include <beast/core/streambuf.hpp>
#include <beast/http/fields.hpp>
#include <beast/http/header_parser_v1.hpp>
#include <beast/http/parse.hpp>
#include <beast/http/string_body.hpp>
#include <beast/test/string_istream.hpp>
#include <beast/test/yield_to.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
namespace http {
class parser_v1_test
: public beast::unit_test::suite
, public test::enable_yield_to
{
public:
void
testParse()
{
using boost::asio::buffer;
{
error_code ec;
parser_v1<true, string_body,
basic_fields<std::allocator<char>>> p;
std::string const s =
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*";
p.write(buffer(s), ec);
BEAST_EXPECT(! ec);
BEAST_EXPECT(p.complete());
auto m = p.release();
BEAST_EXPECT(m.method == "GET");
BEAST_EXPECT(m.url == "/");
BEAST_EXPECT(m.version == 11);
BEAST_EXPECT(m.fields["User-Agent"] == "test");
BEAST_EXPECT(m.body == "*");
}
{
error_code ec;
parser_v1<false, string_body,
basic_fields<std::allocator<char>>> p;
std::string const s =
"HTTP/1.1 200 OK\r\n"
"Server: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*";
p.write(buffer(s), ec);
BEAST_EXPECT(! ec);
BEAST_EXPECT(p.complete());
auto m = p.release();
BEAST_EXPECT(m.status == 200);
BEAST_EXPECT(m.reason == "OK");
BEAST_EXPECT(m.version == 11);
BEAST_EXPECT(m.fields["Server"] == "test");
BEAST_EXPECT(m.body == "*");
}
// skip body
{
error_code ec;
parser_v1<false, string_body, fields> p;
std::string const s =
"HTTP/1.1 200 Connection Established\r\n"
"Proxy-Agent: Zscaler/5.1\r\n"
"\r\n";
p.set_option(skip_body{true});
p.write(buffer(s), ec);
BEAST_EXPECT(! ec);
BEAST_EXPECT(p.complete());
}
}
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();
}
};
BEAST_DEFINE_TESTSUITE(parser_v1,http,beast);
} // http
} // beast