forked from boostorg/beast
New HTTP interfaces (API Change):
fix #123 fix #154 fix #265 This completely replaces the HTTP parser used to read and parse incoming messages. The new version is faster than the old one, and written in fewer lines. A summary of changes: * parse and async_parse renamed to read and async_read * basic_parser is optimized for linear buffers, use flat_streambuf for the best performance with these functions: - http::read - http::read_some - http::async_read - http::async_read_some * The overloads of read() and async_read() which take just a header have been removed, since they would throw away important parse metadata. * The derived class callbacks for basic_parser have been streamlined. All strings passed to callbacks are presented in their entirety, instead of being provided in pieces. These changes allow use-cases that were previously difficult or impossible, such as: - Efficient relaying - Late body type commitment - Expect: 100-continue handling
This commit is contained in:
+128
-11
@@ -9,6 +9,7 @@
|
||||
#include "message_fuzz.hpp"
|
||||
|
||||
#include <beast/http.hpp>
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/streambuf.hpp>
|
||||
#include <beast/core/to_string.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
@@ -64,9 +65,39 @@ public:
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence,
|
||||
bool isRequest, bool isDirect, class Derived>
|
||||
static
|
||||
std::size_t
|
||||
feed(ConstBufferSequence const& buffers,
|
||||
basic_parser<isRequest, isDirect, Derived>& parser,
|
||||
error_code& ec)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
beast::consuming_buffers<
|
||||
ConstBufferSequence> cb{buffers};
|
||||
std::size_t used = 0;
|
||||
for(;;)
|
||||
{
|
||||
auto const n =
|
||||
parser.write(cb, ec);
|
||||
if(ec)
|
||||
return 0;
|
||||
if(n == 0)
|
||||
break;
|
||||
cb.consume(n);
|
||||
used += n;
|
||||
if(parser.is_complete())
|
||||
break;
|
||||
if(buffer_size(cb) == 0)
|
||||
break;
|
||||
}
|
||||
return used;
|
||||
}
|
||||
|
||||
template<class Parser>
|
||||
void
|
||||
testParser(std::size_t repeat, corpus const& v)
|
||||
testParser1(std::size_t repeat, corpus const& v)
|
||||
{
|
||||
while(repeat--)
|
||||
for(auto const& sb : v)
|
||||
@@ -79,6 +110,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template<class Parser>
|
||||
void
|
||||
testParser2(std::size_t repeat, corpus const& v)
|
||||
{
|
||||
while(repeat--)
|
||||
for(auto const& sb : v)
|
||||
{
|
||||
Parser p;
|
||||
error_code ec;
|
||||
feed(sb.data(), p, ec);
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
log << to_string(sb.data()) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Function>
|
||||
void
|
||||
timedTest(std::size_t repeat, std::string const& name, Function&& f)
|
||||
@@ -98,21 +144,92 @@ public:
|
||||
}
|
||||
|
||||
template<bool isRequest>
|
||||
struct null_parser : basic_parser_v1<isRequest, null_parser<isRequest>>
|
||||
struct null_parser :
|
||||
basic_parser<isRequest, true,
|
||||
null_parser<isRequest>>
|
||||
{
|
||||
};
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
struct bench_parser : basic_parser<
|
||||
isRequest, false, bench_parser<isRequest, Body, Fields>>
|
||||
{
|
||||
using mutable_buffers_type =
|
||||
boost::asio::mutable_buffers_1;
|
||||
|
||||
void
|
||||
on_request(boost::string_ref const&,
|
||||
boost::string_ref const&,
|
||||
int, error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_response(int,
|
||||
boost::string_ref const&,
|
||||
int, error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_field(boost::string_ref const&,
|
||||
boost::string_ref const&,
|
||||
error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_header(error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_body(error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_body(std::uint64_t content_length,
|
||||
error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_data(boost::string_ref const&,
|
||||
error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_chunk(std::uint64_t,
|
||||
boost::string_ref const&,
|
||||
error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_body(boost::string_ref const&,
|
||||
error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_complete(error_code&)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testSpeed()
|
||||
{
|
||||
static std::size_t constexpr Trials = 3;
|
||||
static std::size_t constexpr Repeat = 50;
|
||||
static std::size_t constexpr Repeat = 500;
|
||||
|
||||
log << "sizeof(request parser) == " <<
|
||||
sizeof(basic_parser_v1<true, null_parser<true>>) << '\n';
|
||||
sizeof(null_parser<true>) << '\n';
|
||||
|
||||
log << "sizeof(response parser) == " <<
|
||||
sizeof(basic_parser_v1<false, null_parser<true>>)<< '\n';
|
||||
sizeof(null_parser<false>)<< '\n';
|
||||
|
||||
testcase << "Parser speed test, " <<
|
||||
((Repeat * size_ + 512) / 1024) << "KB in " <<
|
||||
@@ -121,20 +238,20 @@ public:
|
||||
timedTest(Trials, "nodejs_parser",
|
||||
[&]
|
||||
{
|
||||
testParser<nodejs_parser<
|
||||
testParser1<nodejs_parser<
|
||||
true, streambuf_body, fields>>(
|
||||
Repeat, creq_);
|
||||
testParser<nodejs_parser<
|
||||
testParser1<nodejs_parser<
|
||||
false, streambuf_body, fields>>(
|
||||
Repeat, cres_);
|
||||
});
|
||||
timedTest(Trials, "http::basic_parser_v1",
|
||||
timedTest(Trials, "http::basic_parser",
|
||||
[&]
|
||||
{
|
||||
testParser<parser_v1<
|
||||
true, streambuf_body, fields>>(
|
||||
testParser2<bench_parser<
|
||||
true, streambuf_body, fields> >(
|
||||
Repeat, creq_);
|
||||
testParser<parser_v1<
|
||||
testParser2<bench_parser<
|
||||
false, streambuf_body, fields>>(
|
||||
Repeat, cres_);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user