forked from boostorg/beast
Refactor HTTP serialization and parsing (API Change):
fix #404 Parsing and serialization interfaces have been fine tuned and unified. For parsing these stream operations are defined: * read * read_header * read_some * async_read * async_read_header * async_read_some For serialization these stream operations are defined: * write * write_header * write_some * async_write * async_write_header * async_write_some
This commit is contained in:
1 parent
50cba32565
commit
fe75a7ca2a
44 files changed
+3655
-3250
No files matched your search
@@ -8,6 +8,7 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <beast/core/bind_handler.hpp>
|
||||
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <functional>
|
||||
|
||||
@@ -16,6 +17,21 @@ namespace beast {
|
||||
class bind_handler_test : public unit_test::suite
|
||||
{
|
||||
public:
|
||||
struct handler
|
||||
{
|
||||
void
|
||||
operator()() const;
|
||||
};
|
||||
|
||||
#if 0
|
||||
// This function should fail to compile
|
||||
void
|
||||
failStdBind()
|
||||
{
|
||||
std::bind(bind_handler(handler{}));
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
callback(int v)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ add_executable (http-bench
|
||||
${BEAST_INCLUDES}
|
||||
${EXTRAS_INCLUDES}
|
||||
nodejs_parser.hpp
|
||||
message_fuzz.hpp
|
||||
../../extras/beast/unit_test/main.cpp
|
||||
nodejs_parser.cpp
|
||||
parser_bench.cpp
|
||||
|
||||
+39
-35
@@ -148,19 +148,18 @@ public:
|
||||
return {s, N-1};
|
||||
}
|
||||
|
||||
template<
|
||||
bool isRequest, bool isDirect, class Derived>
|
||||
template<bool isRequest, class Derived>
|
||||
static
|
||||
std::size_t
|
||||
feed(boost::asio::const_buffer buffer,
|
||||
basic_parser<isRequest, isDirect, Derived>& parser,
|
||||
basic_parser<isRequest, Derived>& parser,
|
||||
error_code& ec)
|
||||
{
|
||||
using boost::asio::const_buffers_1;
|
||||
std::size_t used = 0;
|
||||
for(;;)
|
||||
{
|
||||
auto const n = parser.write(
|
||||
auto const n = parser.put(
|
||||
const_buffers_1{buffer}, ec);
|
||||
if(ec)
|
||||
return 0;
|
||||
@@ -168,7 +167,7 @@ public:
|
||||
break;
|
||||
buffer = buffer + n;
|
||||
used += n;
|
||||
if(parser.is_complete())
|
||||
if(parser.is_done())
|
||||
break;
|
||||
if(buffer_size(buffer) == 0)
|
||||
break;
|
||||
@@ -177,11 +176,11 @@ public:
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence,
|
||||
bool isRequest, bool isDirect, class Derived>
|
||||
bool isRequest, class Derived>
|
||||
static
|
||||
std::size_t
|
||||
feed(ConstBufferSequence const& buffers,
|
||||
basic_parser<isRequest, isDirect, Derived>& parser,
|
||||
basic_parser<isRequest, Derived>& parser,
|
||||
error_code& ec)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
@@ -191,14 +190,14 @@ public:
|
||||
for(;;)
|
||||
{
|
||||
auto const n =
|
||||
parser.write(cb, ec);
|
||||
parser.put(cb, ec);
|
||||
if(ec)
|
||||
return 0;
|
||||
if(n == 0)
|
||||
break;
|
||||
cb.consume(n);
|
||||
used += n;
|
||||
if(parser.is_complete())
|
||||
if(parser.is_done())
|
||||
break;
|
||||
if(buffer_size(cb) == 0)
|
||||
break;
|
||||
@@ -206,12 +205,11 @@ public:
|
||||
return used;
|
||||
}
|
||||
|
||||
template<
|
||||
bool isRequest, bool isDirect, class Derived>
|
||||
template<bool isRequest, class Derived>
|
||||
static
|
||||
std::size_t
|
||||
feed(boost::asio::const_buffers_1 buffers,
|
||||
basic_parser<isRequest, isDirect, Derived>& parser,
|
||||
basic_parser<isRequest, Derived>& parser,
|
||||
error_code& ec)
|
||||
{
|
||||
return feed(*buffers.begin(), parser, ec);
|
||||
@@ -225,7 +223,7 @@ public:
|
||||
using boost::asio::buffer;
|
||||
test_parser<isRequest> p;
|
||||
if(skipBody)
|
||||
p.skip_body();
|
||||
p.skip(true);
|
||||
error_code ec;
|
||||
auto const n = feed(buffer(
|
||||
s.data(), s.size()), p, ec);
|
||||
@@ -233,8 +231,8 @@ public:
|
||||
return;
|
||||
if(! BEAST_EXPECT(n == s.size()))
|
||||
return;
|
||||
if(p.state() == parse_state::body_to_eof)
|
||||
p.write_eof(ec);
|
||||
if(p.need_eof())
|
||||
p.put_eof(ec);
|
||||
if(BEAST_EXPECTS(! ec, ec.message()))
|
||||
pred(p);
|
||||
}
|
||||
@@ -257,18 +255,19 @@ public:
|
||||
using boost::asio::buffer;
|
||||
test_parser<isRequest> p;
|
||||
if(skipBody)
|
||||
p.skip_body();
|
||||
p.skip(true);
|
||||
error_code ec;
|
||||
feed(buffer(
|
||||
s.data(), s.size()), p, ec);
|
||||
if(! ec && ev)
|
||||
p.write_eof(ec);
|
||||
p.put_eof(ec);
|
||||
BEAST_EXPECTS(ec == ev, ec.message());
|
||||
}
|
||||
|
||||
void
|
||||
testFlatten()
|
||||
{
|
||||
#if 0
|
||||
using boost::asio::buffer;
|
||||
{
|
||||
std::string const s =
|
||||
@@ -289,7 +288,7 @@ public:
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
feed(buffer_cat(b1, b2), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -310,9 +309,10 @@ public:
|
||||
ec = {};
|
||||
feed(buffer_cat(b1, b2), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
p.write_eof(ec);
|
||||
p.put_eof(ec);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check that all callbacks are invoked
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
"*";
|
||||
feed(buffer(s), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
BEAST_EXPECT(p.got_on_begin);
|
||||
BEAST_EXPECT(p.got_on_field);
|
||||
BEAST_EXPECT(p.got_on_header);
|
||||
@@ -350,7 +350,7 @@ public:
|
||||
"*";
|
||||
feed(buffer(s), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
BEAST_EXPECT(p.got_on_begin);
|
||||
BEAST_EXPECT(p.got_on_field);
|
||||
BEAST_EXPECT(p.got_on_header);
|
||||
@@ -747,6 +747,7 @@ public:
|
||||
|
||||
void testBody()
|
||||
{
|
||||
#if 0
|
||||
using boost::asio::buffer;
|
||||
good<true>(
|
||||
"GET / HTTP/1.1\r\n"
|
||||
@@ -774,7 +775,7 @@ public:
|
||||
buf("67890")),
|
||||
p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
|
||||
// request without Content-Length or
|
||||
@@ -787,7 +788,7 @@ public:
|
||||
"\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
{
|
||||
error_code ec;
|
||||
@@ -797,7 +798,7 @@ public:
|
||||
"\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
|
||||
// response without Content-Length or
|
||||
@@ -810,17 +811,17 @@ public:
|
||||
"\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(! p.is_complete());
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
BEAST_EXPECT(p.state() == parse_state::body_to_eof);
|
||||
feed(buf(
|
||||
"hello"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(! p.is_complete());
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
BEAST_EXPECT(p.state() == parse_state::body_to_eof);
|
||||
p.write_eof(ec);
|
||||
p.put_eof(ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
|
||||
// 304 "Not Modified" response does not require eof
|
||||
@@ -832,7 +833,7 @@ public:
|
||||
"\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
|
||||
// Chunked response does not require eof
|
||||
@@ -845,12 +846,12 @@ public:
|
||||
"\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(! p.is_complete());
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
feed(buf(
|
||||
"0\r\n\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
|
||||
// restart: 1.0 assumes Connection: close
|
||||
@@ -862,7 +863,7 @@ public:
|
||||
"\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
|
||||
// restart: 1.1 assumes Connection: keep-alive
|
||||
@@ -874,7 +875,7 @@ public:
|
||||
"\r\n"
|
||||
), p, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
|
||||
bad<true>(
|
||||
@@ -882,8 +883,10 @@ public:
|
||||
"Content-Length: 1\r\n"
|
||||
"\r\n",
|
||||
error::partial_message);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<bool isRequest>
|
||||
void
|
||||
check_header(
|
||||
@@ -898,6 +901,7 @@ public:
|
||||
BEAST_EXPECT(! p.got_on_complete);
|
||||
BEAST_EXPECT(p.state() != parse_state::header);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
testSplit()
|
||||
@@ -921,7 +925,7 @@ public:
|
||||
BEAST_EXPECT(! p.got_on_chunk);
|
||||
BEAST_EXPECT(! p.got_on_complete);
|
||||
BEAST_EXPECT(p.state() != parse_state::header);
|
||||
BEAST_EXPECT(! p.is_complete());
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
BEAST_EXPECT(p.body.empty());
|
||||
b.consume(n);
|
||||
p.resume();
|
||||
@@ -933,7 +937,7 @@ public:
|
||||
BEAST_EXPECT(p.got_on_body);
|
||||
BEAST_EXPECT(! p.got_on_chunk);
|
||||
BEAST_EXPECT(p.got_on_complete);
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
BEAST_EXPECT(p.body == "*****");
|
||||
#endif
|
||||
}
|
||||
|
||||
+463
-504
File diff suppressed because it is too large.
Load diff
@@ -22,6 +22,13 @@ class header_parser_test
|
||||
, public test::enable_yield_to
|
||||
{
|
||||
public:
|
||||
static
|
||||
boost::asio::const_buffers_1
|
||||
buf(string_view s)
|
||||
{
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
void
|
||||
testParse()
|
||||
{
|
||||
@@ -34,7 +41,7 @@ public:
|
||||
flat_buffer db{1024};
|
||||
header_parser<true, fields> p;
|
||||
read_some(is, db, p);
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_header_done());
|
||||
}
|
||||
{
|
||||
test::string_istream is{ios_,
|
||||
@@ -47,8 +54,8 @@ public:
|
||||
flat_buffer db{1024};
|
||||
header_parser<true, fields> p;
|
||||
read_some(is, db, p);
|
||||
BEAST_EXPECT(! p.is_complete());
|
||||
BEAST_EXPECT(p.state() == parse_state::body);
|
||||
BEAST_EXPECT(p.is_header_done());
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+220
-94
@@ -14,10 +14,10 @@
|
||||
#include <beast/test/string_istream.hpp>
|
||||
#include <beast/test/string_ostream.hpp>
|
||||
#include <beast/test/yield_to.hpp>
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/flat_buffer.hpp>
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/http/header_parser.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/core/ostream.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
@@ -30,41 +30,117 @@ class message_parser_test
|
||||
, public beast::test::enable_yield_to
|
||||
{
|
||||
public:
|
||||
template<bool isRequest, class Pred>
|
||||
void
|
||||
testMatrix(std::string const& s, Pred const& pred)
|
||||
template<bool isRequest>
|
||||
using parser_type =
|
||||
message_parser<isRequest, string_body, fields>;
|
||||
|
||||
static
|
||||
boost::asio::const_buffers_1
|
||||
buf(string_view s)
|
||||
{
|
||||
beast::test::string_istream ss{get_io_service(), s};
|
||||
error_code ec;
|
||||
#if 0
|
||||
multi_buffer buffer;
|
||||
#else
|
||||
flat_buffer buffer{1024};
|
||||
#endif
|
||||
message<isRequest, string_body, fields> m;
|
||||
read(ss, buffer, m, ec);
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
return;
|
||||
pred(m);
|
||||
return {s.data(), s.size()};
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence,
|
||||
bool isRequest, class Derived>
|
||||
static
|
||||
void
|
||||
put(ConstBufferSequence const& buffers,
|
||||
basic_parser<isRequest, Derived>& p,
|
||||
error_code& ec)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
consuming_buffers<ConstBufferSequence> cb{buffers};
|
||||
for(;;)
|
||||
{
|
||||
auto const used = p.put(cb, ec);
|
||||
cb.consume(used);
|
||||
if(ec)
|
||||
return;
|
||||
if(p.need_eof() &&
|
||||
buffer_size(cb) == 0)
|
||||
{
|
||||
p.put_eof(ec);
|
||||
if(ec)
|
||||
return;
|
||||
}
|
||||
if(p.is_done())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<bool isRequest, class F>
|
||||
void
|
||||
doMatrix(string_view s0, F const& f)
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
// parse a single buffer
|
||||
{
|
||||
auto s = s0;
|
||||
error_code ec;
|
||||
parser_type<isRequest> p;
|
||||
put(buffer(s.data(), s.size()), p, ec);
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
return;
|
||||
f(p);
|
||||
}
|
||||
// parse two buffers
|
||||
for(auto n = s0.size() - 1; n >= 1; --n)
|
||||
{
|
||||
auto s = s0;
|
||||
error_code ec;
|
||||
parser_type<isRequest> p;
|
||||
p.eager(true);
|
||||
auto used =
|
||||
p.put(buffer(s.data(), n), ec);
|
||||
s.remove_prefix(used);
|
||||
if(ec == error::need_more)
|
||||
ec = {};
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
continue;
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
used = p.put(
|
||||
buffer(s.data(), s.size()), ec);
|
||||
s.remove_prefix(used);
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
continue;
|
||||
BEAST_EXPECT(s.empty());
|
||||
if(p.need_eof())
|
||||
{
|
||||
p.put_eof(ec);
|
||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||
continue;
|
||||
}
|
||||
if(BEAST_EXPECT(p.is_done()))
|
||||
f(p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testRead()
|
||||
testParse()
|
||||
{
|
||||
testMatrix<false>(
|
||||
doMatrix<false>(
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Server: test\r\n"
|
||||
"\r\n"
|
||||
"*******",
|
||||
[&](message<false, string_body, fields> const& m)
|
||||
"Hello, world!",
|
||||
[&](parser_type<false> const& p)
|
||||
{
|
||||
BEAST_EXPECTS(m.body == "*******",
|
||||
"body='" + m.body + "'");
|
||||
auto const& m = p.get();
|
||||
BEAST_EXPECT(! p.is_chunked());
|
||||
BEAST_EXPECT(p.need_eof());
|
||||
BEAST_EXPECT(p.content_length() == boost::none);
|
||||
BEAST_EXPECT(m.version == 10);
|
||||
BEAST_EXPECT(m.status == 200);
|
||||
BEAST_EXPECT(m.reason() == "OK");
|
||||
BEAST_EXPECT(m.fields["Server"] == "test");
|
||||
BEAST_EXPECT(m.body == "Hello, world!");
|
||||
}
|
||||
);
|
||||
testMatrix<false>(
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
doMatrix<false>(
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Server: test\r\n"
|
||||
"Expect: Expires, MD5-Fingerprint\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"5\r\n"
|
||||
@@ -75,132 +151,137 @@ public:
|
||||
"Expires: never\r\n"
|
||||
"MD5-Fingerprint: -\r\n"
|
||||
"\r\n",
|
||||
[&](message<false, string_body, fields> const& m)
|
||||
[&](parser_type<false> const& p)
|
||||
{
|
||||
auto const& m = p.get();
|
||||
BEAST_EXPECT(! p.need_eof());
|
||||
BEAST_EXPECT(p.is_chunked());
|
||||
BEAST_EXPECT(p.content_length() == boost::none);
|
||||
BEAST_EXPECT(m.version == 11);
|
||||
BEAST_EXPECT(m.status == 200);
|
||||
BEAST_EXPECT(m.reason() == "OK");
|
||||
BEAST_EXPECT(m.fields["Server"] == "test");
|
||||
BEAST_EXPECT(m.fields["Transfer-Encoding"] == "chunked");
|
||||
BEAST_EXPECT(m.fields["Expires"] == "never");
|
||||
BEAST_EXPECT(m.fields["MD5-Fingerprint"] == "-");
|
||||
BEAST_EXPECT(m.body == "*****--");
|
||||
}
|
||||
);
|
||||
testMatrix<false>(
|
||||
doMatrix<false>(
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"Server: test\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"\r\n"
|
||||
"*****",
|
||||
[&](message<false, string_body, fields> const& m)
|
||||
[&](parser_type<false> const& p)
|
||||
{
|
||||
auto const& m = p.get();
|
||||
BEAST_EXPECT(m.body == "*****");
|
||||
}
|
||||
);
|
||||
testMatrix<true>(
|
||||
doMatrix<true>(
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"\r\n",
|
||||
[&](message<true, string_body, fields> const& m)
|
||||
[&](parser_type<true> const& p)
|
||||
{
|
||||
auto const& m = p.get();
|
||||
BEAST_EXPECT(m.method() == "GET");
|
||||
BEAST_EXPECT(m.target() == "/");
|
||||
BEAST_EXPECT(m.version == 11);
|
||||
BEAST_EXPECT(! p.need_eof());
|
||||
BEAST_EXPECT(! p.is_chunked());
|
||||
BEAST_EXPECT(p.content_length() == boost::none);
|
||||
}
|
||||
);
|
||||
testMatrix<true>(
|
||||
doMatrix<true>(
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"X: \t x \t \r\n"
|
||||
"\r\n",
|
||||
[&](message<true, string_body, fields> const& m)
|
||||
[&](parser_type<true> const& p)
|
||||
{
|
||||
auto const& m = p.get();
|
||||
BEAST_EXPECT(m.fields["X"] == "x");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
testParse()
|
||||
{
|
||||
using boost::asio::buffer;
|
||||
// test eager(true)
|
||||
{
|
||||
error_code ec;
|
||||
beast::test::string_istream is{
|
||||
get_io_service(),
|
||||
parser_type<true> p;
|
||||
p.eager(true);
|
||||
p.put(buf(
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Content-Length: 1\r\n"
|
||||
"\r\n"
|
||||
"*"};
|
||||
flat_buffer b{1024};
|
||||
message_parser<true, string_body, fields> p;
|
||||
read(is, b, p, ec);
|
||||
"*")
|
||||
, ec);
|
||||
auto const& m = p.get();
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(! ec);
|
||||
BEAST_EXPECT(p.is_done());
|
||||
BEAST_EXPECT(p.is_header_done());
|
||||
BEAST_EXPECT(! p.need_eof());
|
||||
BEAST_EXPECT(m.method() == "GET");
|
||||
BEAST_EXPECT(m.target() == "/");
|
||||
BEAST_EXPECT(m.version == 11);
|
||||
BEAST_EXPECT(m.fields["User-Agent"] == "test");
|
||||
BEAST_EXPECT(m.body == "*");
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
// test partial parsing of final chunk
|
||||
// parse through the chunk body
|
||||
beast::test::string_istream is{
|
||||
get_io_service(), ""};
|
||||
multi_buffer b;
|
||||
b <<
|
||||
error_code ec;
|
||||
flat_buffer b;
|
||||
parser_type<true> p;
|
||||
p.eager(true);
|
||||
ostream(b) <<
|
||||
"PUT / HTTP/1.1\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"1\r\n"
|
||||
"*";
|
||||
error_code ec;
|
||||
message_parser<true, string_body, fields> p;
|
||||
read(is, b, p, ec);
|
||||
BEAST_EXPECT(b.size() == 0);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(!p.is_complete());
|
||||
auto used = p.put(b.data(), ec);
|
||||
b.consume(used);
|
||||
BEAST_EXPECT(! ec);
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
BEAST_EXPECT(p.get().body == "*");
|
||||
b << "\r\n0;d;e=3;f=\"4\"\r\n"
|
||||
ostream(b) <<
|
||||
"\r\n"
|
||||
"0;d;e=3;f=\"4\"\r\n"
|
||||
"Expires: never\r\n"
|
||||
"MD5-Fingerprint: -\r\n";
|
||||
// incomplete parse, missing the final crlf
|
||||
BEAST_EXPECT(p.write(b.data(), ec) == 0);
|
||||
used = p.put(b.data(), ec);
|
||||
b.consume(used);
|
||||
BEAST_EXPECT(ec == error::need_more);
|
||||
ec = {};
|
||||
BEAST_EXPECT(! p.is_done());
|
||||
ostream(b) <<
|
||||
"\r\n"; // final crlf to end message
|
||||
used = p.put(b.data(), ec);
|
||||
b.consume(used);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(!p.is_complete());
|
||||
b << "\r\n"; // final crlf to end message
|
||||
BEAST_EXPECT(p.write(b.data(), ec) == b.size());
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
}
|
||||
{
|
||||
error_code ec;
|
||||
message_parser<false, string_body, fields> 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);
|
||||
auto const& m = p.get();
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
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 == "*");
|
||||
BEAST_EXPECT(p.is_done());
|
||||
}
|
||||
// skip body
|
||||
{
|
||||
error_code ec;
|
||||
message_parser<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.skip_body();
|
||||
p.write(buffer(s), ec);
|
||||
p.skip(true);
|
||||
p.put(buf(
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Length: 5\r\n"
|
||||
"\r\n"
|
||||
"*****")
|
||||
, ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p.is_complete());
|
||||
BEAST_EXPECT(p.is_done());
|
||||
BEAST_EXPECT(p.is_header_done());
|
||||
BEAST_EXPECT(p.content_length() &&
|
||||
*p.content_length() == 5);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -219,8 +300,8 @@ public:
|
||||
read_some(ss, b, p0, ec);
|
||||
b.consume(bytes_used);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
BEAST_EXPECT(p0.state() != parse_state::header);
|
||||
BEAST_EXPECT(! p0.is_complete());
|
||||
BEAST_EXPECT(p0.is_header_done());
|
||||
BEAST_EXPECT(! p0.is_done());
|
||||
message_parser<true,
|
||||
string_body, fields> p1{std::move(p0)};
|
||||
read(ss, b, p1, ec);
|
||||
@@ -228,12 +309,57 @@ public:
|
||||
BEAST_EXPECT(p1.get().body == "*****");
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template<class DynamicBuffer>
|
||||
void
|
||||
testNeedMore()
|
||||
{
|
||||
error_code ec;
|
||||
std::size_t used;
|
||||
{
|
||||
DynamicBuffer b;
|
||||
parser_type<true> p;
|
||||
ostream(b) <<
|
||||
"GET / HTTP/1.1\r\n";
|
||||
used = p.put(b.data(), ec);
|
||||
BEAST_EXPECTS(ec == error::need_more, ec.message());
|
||||
b.consume(used);
|
||||
ec = {};
|
||||
ostream(b) <<
|
||||
"User-Agent: test\r\n"
|
||||
"\r\n";
|
||||
used = p.put(b.data(), ec);
|
||||
BEAST_EXPECTS(! ec, ec.message());
|
||||
b.consume(used);
|
||||
BEAST_EXPECT(p.is_done());
|
||||
BEAST_EXPECT(p.is_header_done());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testGotSome()
|
||||
{
|
||||
error_code ec;
|
||||
parser_type<true> p;
|
||||
auto used = p.put(buf(""), ec);
|
||||
BEAST_EXPECT(ec == error::need_more);
|
||||
BEAST_EXPECT(! p.got_some());
|
||||
BEAST_EXPECT(used == 0);
|
||||
ec = {};
|
||||
used = p.put(buf("G"), ec);
|
||||
BEAST_EXPECT(ec == error::need_more);
|
||||
BEAST_EXPECT(p.got_some());
|
||||
BEAST_EXPECT(used == 0);
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testRead();
|
||||
testParse();
|
||||
testExpect100Continue();
|
||||
testNeedMore<flat_buffer>();
|
||||
testNeedMore<multi_buffer>();
|
||||
testGotSome();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+28
-39
@@ -11,6 +11,7 @@
|
||||
#include <beast/http.hpp>
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/ostream.hpp>
|
||||
#include <beast/core/flat_buffer.hpp>
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
@@ -26,7 +27,8 @@ class parser_bench_test : public beast::unit_test::suite
|
||||
public:
|
||||
static std::size_t constexpr N = 2000;
|
||||
|
||||
using corpus = std::vector<multi_buffer>;
|
||||
//using corpus = std::vector<multi_buffer>;
|
||||
using corpus = std::vector<flat_buffer>;
|
||||
|
||||
corpus creq_;
|
||||
corpus cres_;
|
||||
@@ -41,22 +43,17 @@ public:
|
||||
std::string>(buffers(bs));
|
||||
}
|
||||
|
||||
parser_bench_test()
|
||||
{
|
||||
creq_ = build_corpus(N/2, std::true_type{});
|
||||
cres_ = build_corpus(N/2, std::false_type{});
|
||||
}
|
||||
|
||||
corpus
|
||||
build_corpus(std::size_t n, std::true_type)
|
||||
{
|
||||
corpus v;
|
||||
v.resize(N);
|
||||
v.resize(n);
|
||||
message_fuzz mg;
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
{
|
||||
mg.request(v[i]);
|
||||
size_ += v[i].size();
|
||||
BEAST_EXPECT(v[i].size() > 0);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
@@ -65,22 +62,23 @@ public:
|
||||
build_corpus(std::size_t n, std::false_type)
|
||||
{
|
||||
corpus v;
|
||||
v.resize(N);
|
||||
v.resize(n);
|
||||
message_fuzz mg;
|
||||
for(std::size_t i = 0; i < n; ++i)
|
||||
{
|
||||
mg.response(v[i]);
|
||||
size_ += v[i].size();
|
||||
BEAST_EXPECT(v[i].size() > 0);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
template<class ConstBufferSequence,
|
||||
bool isRequest, bool isDirect, class Derived>
|
||||
bool isRequest, class Derived>
|
||||
static
|
||||
std::size_t
|
||||
feed(ConstBufferSequence const& buffers,
|
||||
basic_parser<isRequest, isDirect, Derived>& parser,
|
||||
basic_parser<isRequest, Derived>& parser,
|
||||
error_code& ec)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
@@ -90,14 +88,14 @@ public:
|
||||
for(;;)
|
||||
{
|
||||
auto const n =
|
||||
parser.write(cb, ec);
|
||||
parser.put(cb, ec);
|
||||
if(ec)
|
||||
return 0;
|
||||
if(n == 0)
|
||||
break;
|
||||
cb.consume(n);
|
||||
used += n;
|
||||
if(parser.is_complete())
|
||||
if(parser.is_done())
|
||||
break;
|
||||
if(buffer_size(cb) == 0)
|
||||
break;
|
||||
@@ -155,14 +153,13 @@ public:
|
||||
|
||||
template<bool isRequest>
|
||||
struct null_parser :
|
||||
basic_parser<isRequest, true,
|
||||
null_parser<isRequest>>
|
||||
basic_parser<isRequest, null_parser<isRequest>>
|
||||
{
|
||||
};
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
struct bench_parser : basic_parser<
|
||||
isRequest, false, bench_parser<isRequest, Body, Fields>>
|
||||
isRequest, bench_parser<isRequest, Body, Fields>>
|
||||
{
|
||||
using mutable_buffers_type =
|
||||
boost::asio::mutable_buffers_1;
|
||||
@@ -194,13 +191,8 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
on_body(error_code& ec)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_body(std::uint64_t content_length,
|
||||
error_code& ec)
|
||||
on_body(boost::optional<std::uint64_t> const&,
|
||||
error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -217,12 +209,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_body(string_view const&,
|
||||
error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_complete(error_code&)
|
||||
{
|
||||
@@ -235,6 +221,9 @@ public:
|
||||
static std::size_t constexpr Trials = 3;
|
||||
static std::size_t constexpr Repeat = 500;
|
||||
|
||||
creq_ = build_corpus(N/2, std::true_type{});
|
||||
cres_ = build_corpus(N/2, std::false_type{});
|
||||
|
||||
log << "sizeof(request parser) == " <<
|
||||
sizeof(null_parser<true>) << '\n';
|
||||
|
||||
@@ -245,16 +234,6 @@ public:
|
||||
((Repeat * size_ + 512) / 1024) << "KB in " <<
|
||||
(Repeat * (creq_.size() + cres_.size())) << " messages";
|
||||
|
||||
timedTest(Trials, "nodejs_parser",
|
||||
[&]
|
||||
{
|
||||
testParser1<nodejs_parser<
|
||||
true, dynamic_body, fields>>(
|
||||
Repeat, creq_);
|
||||
testParser1<nodejs_parser<
|
||||
false, dynamic_body, fields>>(
|
||||
Repeat, cres_);
|
||||
});
|
||||
timedTest(Trials, "http::basic_parser",
|
||||
[&]
|
||||
{
|
||||
@@ -265,6 +244,16 @@ public:
|
||||
false, dynamic_body, fields>>(
|
||||
Repeat, cres_);
|
||||
});
|
||||
timedTest(Trials, "nodejs_parser",
|
||||
[&]
|
||||
{
|
||||
testParser1<nodejs_parser<
|
||||
true, dynamic_body, fields>>(
|
||||
Repeat, creq_);
|
||||
testParser1<nodejs_parser<
|
||||
false, dynamic_body, fields>>(
|
||||
Repeat, cres_);
|
||||
});
|
||||
pass();
|
||||
}
|
||||
|
||||
|
||||
+51
-1
@@ -10,11 +10,14 @@
|
||||
|
||||
#include "test_parser.hpp"
|
||||
|
||||
#include <beast/core/ostream.hpp>
|
||||
#include <beast/core/static_buffer.hpp>
|
||||
#include <beast/http/fields.hpp>
|
||||
#include <beast/http/dynamic_body.hpp>
|
||||
#include <beast/http/header_parser.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/test/fail_stream.hpp>
|
||||
#include <beast/test/pipe_stream.hpp>
|
||||
#include <beast/test/string_istream.hpp>
|
||||
#include <beast/test/yield_to.hpp>
|
||||
#include <beast/unit_test/suite.hpp>
|
||||
@@ -108,7 +111,7 @@ public:
|
||||
{
|
||||
multi_buffer b;
|
||||
test::string_istream ss(ios_, "GET / X");
|
||||
message_parser<true, dynamic_body, fields> p;
|
||||
request_parser<dynamic_body> p;
|
||||
read(ss, b, p);
|
||||
fail();
|
||||
}
|
||||
@@ -118,6 +121,52 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testBufferOverflow()
|
||||
{
|
||||
{
|
||||
test::pipe p{ios_};
|
||||
ostream(p.server.buffer) <<
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"10\r\n"
|
||||
"****************\r\n"
|
||||
"0\r\n\r\n";
|
||||
static_buffer_n<1024> b;
|
||||
request<string_body> req;
|
||||
try
|
||||
{
|
||||
read(p.server, b, req);
|
||||
pass();
|
||||
}
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
fail(e.what(), __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
{
|
||||
test::pipe p{ios_};
|
||||
ostream(p.server.buffer) <<
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: localhost\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
"Transfer-Encoding: chunked\r\n"
|
||||
"\r\n"
|
||||
"10\r\n"
|
||||
"****************\r\n"
|
||||
"0\r\n\r\n";
|
||||
error_code ec;
|
||||
static_buffer_n<10> b;
|
||||
request<string_body> req;
|
||||
read(p.server, b, req, ec);
|
||||
BEAST_EXPECTS(ec == error::buffer_overflow,
|
||||
ec.message());
|
||||
}
|
||||
}
|
||||
|
||||
void testFailures(yield_context do_yield)
|
||||
{
|
||||
char const* req[] = {
|
||||
@@ -318,6 +367,7 @@ public:
|
||||
run() override
|
||||
{
|
||||
testThrow();
|
||||
testBufferOverflow();
|
||||
|
||||
yield_to([&](yield_context yield){
|
||||
testFailures(yield); });
|
||||
|
||||
+12
-21
@@ -16,8 +16,7 @@ namespace http {
|
||||
|
||||
template<bool isRequest>
|
||||
class test_parser
|
||||
: public basic_parser<isRequest, false,
|
||||
test_parser<isRequest>>
|
||||
: public basic_parser<isRequest, test_parser<isRequest>>
|
||||
{
|
||||
test::fail_counter* fc_ = nullptr;
|
||||
|
||||
@@ -36,8 +35,6 @@ public:
|
||||
bool got_on_header = false;
|
||||
bool got_on_body = false;
|
||||
bool got_content_length = false;
|
||||
bool got_on_prepare = false;
|
||||
bool got_on_commit = false;
|
||||
bool got_on_chunk = false;
|
||||
bool got_on_complete = false;
|
||||
|
||||
@@ -50,10 +47,9 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
on_request(
|
||||
string_view const& method_,
|
||||
string_view const& path_,
|
||||
int version_, error_code& ec)
|
||||
on_request(string_view const& method_,
|
||||
string_view const& path_,
|
||||
int version_, error_code& ec)
|
||||
{
|
||||
method = std::string(
|
||||
method_.data(), method_.size());
|
||||
@@ -98,19 +94,13 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
on_body(error_code& ec)
|
||||
on_body(boost::optional<
|
||||
std::uint64_t> const& content_length_,
|
||||
error_code& ec)
|
||||
{
|
||||
got_on_body = true;
|
||||
if(fc_)
|
||||
fc_->fail(ec);
|
||||
}
|
||||
|
||||
void
|
||||
on_body(std::uint64_t content_length,
|
||||
error_code& ec)
|
||||
{
|
||||
got_on_body = true;
|
||||
got_content_length = true;
|
||||
got_content_length =
|
||||
static_cast<bool>(content_length_);
|
||||
if(fc_)
|
||||
fc_->fail(ec);
|
||||
}
|
||||
@@ -120,12 +110,13 @@ public:
|
||||
error_code& ec)
|
||||
{
|
||||
body.append(s.data(), s.size());
|
||||
if(fc_)
|
||||
fc_->fail(ec);
|
||||
}
|
||||
|
||||
void
|
||||
on_chunk(std::uint64_t,
|
||||
string_view const&,
|
||||
error_code& ec)
|
||||
string_view const&, error_code& ec)
|
||||
{
|
||||
got_on_chunk = true;
|
||||
if(fc_)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <beast/http/type_traits.hpp>
|
||||
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
@@ -17,5 +18,7 @@ BOOST_STATIC_ASSERT(! is_body_reader<int>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(is_body_reader<empty_body>::value);
|
||||
|
||||
BOOST_STATIC_ASSERT(! is_body_writer<std::string>::value);
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
+4
-92
@@ -382,7 +382,7 @@ public:
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
write(fs, m, ec);
|
||||
if(ec == boost::asio::error::eof)
|
||||
if(ec == error::end_of_stream)
|
||||
{
|
||||
BEAST_EXPECT(fs.next_layer().str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
@@ -415,7 +415,7 @@ public:
|
||||
m.body = "*****";
|
||||
error_code ec;
|
||||
async_write(fs, m, do_yield[ec]);
|
||||
if(ec == boost::asio::error::eof)
|
||||
if(ec == error::end_of_stream)
|
||||
{
|
||||
BEAST_EXPECT(fs.next_layer().str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
@@ -559,7 +559,7 @@ public:
|
||||
test::string_ostream ss(ios_);
|
||||
error_code ec;
|
||||
write(ss, m, ec);
|
||||
BEAST_EXPECT(ec == boost::asio::error::eof);
|
||||
BEAST_EXPECT(ec == error::end_of_stream);
|
||||
BEAST_EXPECT(ss.str ==
|
||||
"GET / HTTP/1.0\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
@@ -596,7 +596,7 @@ public:
|
||||
test::string_ostream ss(ios_);
|
||||
error_code ec;
|
||||
write(ss, m, ec);
|
||||
BEAST_EXPECT(ec == boost::asio::error::eof);
|
||||
BEAST_EXPECT(ec == error::end_of_stream);
|
||||
BEAST_EXPECT(ss.str ==
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"User-Agent: test\r\n"
|
||||
@@ -949,93 +949,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/** Execute a child process and return the output as an HTTP response.
|
||||
|
||||
@param input A stream to read the child process output from.
|
||||
|
||||
@param output A stream to write the HTTP response to.
|
||||
*/
|
||||
template<class SyncReadStream, class SyncWriteStream>
|
||||
void
|
||||
cgi_process(SyncReadStream& input, SyncWriteStream& output, error_code& ec)
|
||||
{
|
||||
multi_buffer b;
|
||||
message<false, buffer_body<true,
|
||||
typename multi_buffer::const_buffers_type>, fields> m;
|
||||
m.status = 200;
|
||||
m.version = 11;
|
||||
m.fields.insert("Server", "cgi-process");
|
||||
m.fields.insert("Transfer-Encoding", "chunked");
|
||||
m.body.first = boost::none;
|
||||
m.body.second = true;
|
||||
|
||||
auto sr = make_serializer(m);
|
||||
|
||||
// send the header first, so the
|
||||
// other end gets it right away
|
||||
for(;;)
|
||||
{
|
||||
write_some(output, sr, ec);
|
||||
if(ec == error::need_more)
|
||||
{
|
||||
ec = {};
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return;
|
||||
}
|
||||
|
||||
// send the body
|
||||
for(;;)
|
||||
{
|
||||
// read from input
|
||||
auto bytes_transferred =
|
||||
input.read_some(b.prepare(1024), ec);
|
||||
if(ec == boost::asio::error::eof)
|
||||
{
|
||||
BOOST_ASSERT(bytes_transferred == 0);
|
||||
ec = {};
|
||||
m.body = {boost::none, false};
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ec)
|
||||
return;
|
||||
b.commit(bytes_transferred);
|
||||
m.body = {b.data(), true};
|
||||
}
|
||||
|
||||
// write to output
|
||||
for(;;)
|
||||
{
|
||||
write_some(output, sr, ec);
|
||||
if(ec == error::need_more)
|
||||
{
|
||||
ec = {};
|
||||
break;
|
||||
}
|
||||
if(ec)
|
||||
return;
|
||||
if(sr.is_done())
|
||||
goto is_done;
|
||||
}
|
||||
b.consume(b.size());
|
||||
}
|
||||
is_done:
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
testCgiRelay()
|
||||
{
|
||||
error_code ec;
|
||||
std::string const body = "Hello, world!\n";
|
||||
test::string_ostream so{get_io_service(), 3};
|
||||
test::string_istream si{get_io_service(), body, 6};
|
||||
cgi_process(si, so, ec);
|
||||
BEAST_EXPECT(equal_body<false>(so.str, body));
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
yield_to([&](yield_context yield){
|
||||
@@ -1046,7 +959,6 @@ public:
|
||||
test_std_ostream();
|
||||
testOstream();
|
||||
testIoService();
|
||||
testCgiRelay();
|
||||
yield_to(
|
||||
[&](yield_context yield)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user