Remove header_parser (API Change)

This commit is contained in:
Vinnie Falco
2017-06-05 07:20:58 -07:00
parent fa28cba515
commit 9f7abcbe2d
13 changed files with 58 additions and 492 deletions

View File

@@ -2,6 +2,10 @@ Version 50
* parser is constructible from other body types * parser is constructible from other body types
API Changes:
* Remove header_parser
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Version 49 Version 49

View File

@@ -63,7 +63,6 @@
[def __fields__ [link beast.ref.http__fields `fields`]] [def __fields__ [link beast.ref.http__fields `fields`]]
[def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]] [def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]]
[def __header__ [link beast.ref.http__header `header`]] [def __header__ [link beast.ref.http__header `header`]]
[def __header_parser__ [link beast.ref.http__header_parser `header_parser`]]
[def __message__ [link beast.ref.http__message `message`]] [def __message__ [link beast.ref.http__message `message`]]
[def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]] [def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]]
[def __parser__ [link beast.ref.http__parser `parser`]] [def __parser__ [link beast.ref.http__parser `parser`]]

View File

@@ -38,18 +38,6 @@ defined types deriving from the basic parser are possible:
: public basic_parser<...>; : public basic_parser<...>;
``` ```
]] ]]
[[
__header_parser__
][
```
/// An HTTP/1 parser for producing a header.
template<
bool isRequest, // `true` to parse an HTTP request
class Fields> // The type of container representing the fields
class header_parser
: public basic_parser<...>;
```
]]
[[ [[
[link beast.ref.http__request_parser `request_parser`] [link beast.ref.http__request_parser `request_parser`]
][ ][

View File

@@ -7,11 +7,11 @@
[section:parser_buffers Buffer-Oriented Parsing] [section:parser_buffers Buffer-Oriented Parsing]
In extreme cases, users may wish to create an instance of __parser__, In some cases, users may wish to create an instance of __parser__, or a
__header_parser__, or a user-defined type derived from __basic_parser__ and user-defined type derived from __basic_parser__ and invoke its methods
invoke its methods directly instead of using the provided stream algorithms. directly instead of using the provided stream algorithms. This could be
This could be useful for implementing algorithms on streams whose interface useful for implementing algorithms on streams whose interface does not
does not conform to any __Stream__. For example, a conform to any __Stream__. For example, a
[@http://zeromq.org/ *ZeroMQ* socket]. [@http://zeromq.org/ *ZeroMQ* socket].
The basic parser interface is interactive; the caller invokes the function The basic parser interface is interactive; the caller invokes the function
[link beast.ref.http__basic_parser.put `basic_parser::put`] [link beast.ref.http__basic_parser.put `basic_parser::put`]

View File

@@ -37,7 +37,6 @@
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member> <member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
<member><link linkend="beast.ref.http__fields">fields</link></member> <member><link linkend="beast.ref.http__fields">fields</link></member>
<member><link linkend="beast.ref.http__header">header</link></member> <member><link linkend="beast.ref.http__header">header</link></member>
<member><link linkend="beast.ref.http__header_parser">header_parser</link></member>
<member><link linkend="beast.ref.http__message">message</link></member> <member><link linkend="beast.ref.http__message">message</link></member>
<member><link linkend="beast.ref.http__parser">parser</link></member> <member><link linkend="beast.ref.http__parser">parser</link></member>
<member><link linkend="beast.ref.http__no_chunk_decorator">no_chunk_decorator</link></member> <member><link linkend="beast.ref.http__no_chunk_decorator">no_chunk_decorator</link></member>

View File

@@ -19,6 +19,9 @@ struct header;
template<bool, class, class> template<bool, class, class>
struct message; struct message;
template<bool isRequest,class Body, class Fields>
class parser;
namespace detail { namespace detail {
template<class T> template<class T>
@@ -35,6 +38,12 @@ public:
template<class T> template<class T>
using is_header = typename is_header_impl<T>::type; using is_header = typename is_header_impl<T>::type;
template<class T>
struct is_parser : std::false_type {};
template<bool isRequest, class Body, class Fields>
struct is_parser<parser<isRequest, Body, Fields>> : std::true_type {};
struct fields_model struct fields_model
{ {
string_view method() const; string_view method() const;

View File

@@ -14,15 +14,6 @@
namespace beast { namespace beast {
namespace http { namespace http {
template<bool isRequest, class Fields>
template<class Arg0, class... ArgN, class>
header_parser<isRequest, Fields>::
header_parser(Arg0&& arg0, ArgN&&... argn)
: h_(std::forward<Arg0>(arg0),
std::forward<ArgN>(argn)...)
{
}
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Fields>
template<class Arg1, class... ArgN, class> template<class Arg1, class... ArgN, class>
parser<isRequest, Body, Fields>:: parser<isRequest, Body, Fields>::
@@ -33,7 +24,7 @@ parser(Arg1&& arg1, ArgN&&... argn)
} }
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Fields>
template<class OtherBody, class... Args> template<class OtherBody, class... Args, class>
parser<isRequest, Body, Fields>:: parser<isRequest, Body, Fields>::
parser(parser<isRequest, OtherBody, Fields>&& parser, parser(parser<isRequest, OtherBody, Fields>&& parser,
Args&&... args) Args&&... args)
@@ -46,17 +37,6 @@ parser(parser<isRequest, OtherBody, Fields>&& parser,
"moved-from parser has a body"}); "moved-from parser has a body"});
} }
template<bool isRequest, class Body, class Fields>
template<class... Args>
parser<isRequest, Body, Fields>::
parser(header_parser<
isRequest, Fields>&& parser, Args&&... args)
: base_type(std::move(static_cast<basic_parser<
isRequest, header_parser<isRequest, Fields>>&>(parser)))
, m_(parser.release(), std::forward<Args>(args)...)
{
}
} // http } // http
} // beast } // beast

View File

@@ -20,199 +20,6 @@
namespace beast { namespace beast {
namespace http { namespace http {
/** An HTTP/1 parser for producing a header.
This class uses the basic HTTP/1 wire format parser to convert
a series of octets into a @ref header.
@note A new instance of the parser is required for each message.
@tparam isRequest Indicates whether a request or response
will be parsed.
@tparam Fields The type of container used to represent the fields.
*/
template<bool isRequest, class Fields>
class header_parser
: public basic_parser<isRequest,
header_parser<isRequest, Fields>>
{
header<isRequest, Fields> h_;
string_view body_;
public:
/// The type of @ref header this object produces.
using value_type = header<isRequest, Fields>;
/// Default constructor.
header_parser() = default;
/// Copy constructor.
header_parser(header_parser const&) = default;
/// Copy assignment.
header_parser& operator=(header_parser const&) = default;
/** Move constructor.
After the move, the only valid operation
on the moved-from object is destruction.
*/
header_parser(header_parser&&) = default;
/** Move assignment
After the move, the only valid operation
on the moved-from object is destruction.
*/
header_parser& operator=(header_parser&&) = default;
/** Constructor
@param args Optional arguments forwarded
forwarded to the @ref http::header constructor.
*/
#if BEAST_DOXYGEN
template<class... Args>
explicit
header_parser(Args&&... args);
#else
template<class Arg0, class... ArgN,
class = typename std::enable_if<
! std::is_convertible<typename
std::decay<Arg0>::type,
header_parser>::value>>
explicit
header_parser(Arg0&& arg0, ArgN&&... argn);
#endif
/** Returns parsed body octets.
This function will return the most recent buffer
of octets corresponding to the parsed body. This
buffer will become invalidated on any subsequent
call to @ref put or @ref put_eof
*/
string_view
body() const
{
return body_;
}
/** Returns the parsed header
@note The return value is undefined unless
@ref is_header_done would return `true`.
*/
value_type const&
get() const
{
return h_;
}
/** Returns the parsed header.
@note The return value is undefined unless
@ref is_header_done would return `true`.
*/
value_type&
get()
{
return h_;
}
/** Returns ownership of the parsed header.
Ownership is transferred to the caller.
@note The return value is undefined unless
@ref is_header_done would return `true`.
Requires:
@ref value_type is @b MoveConstructible
*/
value_type
release()
{
static_assert(
std::is_move_constructible<decltype(h_)>::value,
"MoveConstructible requirements not met");
return std::move(h_);
}
private:
friend class basic_parser<isRequest, header_parser>;
void
on_request(string_view method,
string_view path, int version, error_code&)
{
h_.target(path);
h_.method(method);
h_.version = version;
}
void
on_response(int code, string_view reason,
int version, error_code&)
{
h_.result(code);
h_.version = version;
h_.reason(reason);
}
void
on_field(string_view name,
string_view value, error_code&)
{
h_.fields.insert(name, value);
}
void
on_header(error_code&)
{
}
void
on_body(boost::optional<std::
uint64_t> const&, error_code&)
{
}
void
on_data(string_view s, error_code&)
{
body_ = s;
}
void
on_chunk(std::uint64_t,
string_view, error_code&)
{
body_ = {};
}
void
on_complete(error_code&)
{
body_ = {};
}
};
template<
bool isRequest,class Body, class Fields = fields>
class parser;
namespace detail {
template<class T>
struct is_parser : std::false_type {};
template<bool isRequest, class Body, class Fields>
struct is_parser<parser<isRequest, Body, Fields>> : std::true_type {};
} // detail
/** An HTTP/1 parser for producing a message. /** An HTTP/1 parser for producing a message.
This class uses the basic HTTP/1 wire format parser to convert This class uses the basic HTTP/1 wire format parser to convert
@@ -227,7 +34,10 @@ struct is_parser<parser<isRequest, Body, Fields>> : std::true_type {};
@note A new instance of the parser is required for each message. @note A new instance of the parser is required for each message.
*/ */
template<bool isRequest, class Body, class Fields> template<
bool isRequest,
class Body,
class Fields = fields>
class parser class parser
: public basic_parser<isRequest, : public basic_parser<isRequest,
parser<isRequest, Body, Fields>> parser<isRequest, Body, Fields>>
@@ -265,7 +75,7 @@ public:
After the move, the only valid operation After the move, the only valid operation
on the moved-from object is destruction. on the moved-from object is destruction.
*/ */
parser(parser&& other); parser(parser&& other) = default;
/** Constructor /** Constructor
@@ -320,22 +130,14 @@ public:
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
template<class OtherBody, class... Args> template<class OtherBody, class... Args>
#else #else
template<class OtherBody, class... Args> template<class OtherBody, class... Args,
class = typename std::enable_if<
! std::is_same<Body, OtherBody>::value>::type>
#endif #endif
explicit explicit
parser(parser<isRequest, OtherBody, Fields>&& parser, parser(parser<isRequest, OtherBody, Fields>&& parser,
Args&&... args); Args&&... args);
/** Construct a parser from a @ref header_parser.
@param parser The header parser to construct from.
@param args Optional arguments forwarded to the message
constructor.
*/
template<class... Args>
explicit
parser(header_parser<
isRequest, Fields>&& parser, Args&&... args);
/** Returns the parsed message. /** Returns the parsed message.
Depending on the progress of the parser, portions Depending on the progress of the parser, portions

View File

@@ -173,19 +173,15 @@ class stream<NextLayer>::accept_op
{ {
struct data struct data
{ {
bool cont;
stream<NextLayer>& ws; stream<NextLayer>& ws;
Decorator decorator; Decorator decorator;
http::header_parser<true, http::fields> p; http::request_parser<http::empty_body> p;
int state = 0;
data(Handler& handler, stream<NextLayer>& ws_, data(Handler& handler, stream<NextLayer>& ws_,
Decorator const& decorator_) Decorator const& decorator_)
: ws(ws_) : ws(ws_)
, decorator(decorator_) , decorator(decorator_)
{ {
using boost::asio::asio_handler_is_continuation;
cont = asio_handler_is_continuation(std::addressof(handler));
} }
template<class Buffers> template<class Buffers>
@@ -195,8 +191,6 @@ class stream<NextLayer>::accept_op
: ws(ws_) : ws(ws_)
, decorator(decorator_) , decorator(decorator_)
{ {
using boost::asio::asio_handler_is_continuation;
cont = asio_handler_is_continuation(std::addressof(handler));
using boost::asio::buffer_copy; using boost::asio::buffer_copy;
using boost::asio::buffer_size; using boost::asio::buffer_size;
// VFALCO What about catch(std::length_error const&)? // VFALCO What about catch(std::length_error const&)?
@@ -218,11 +212,11 @@ public:
: d_(std::forward<DeducedHandler>(h), : d_(std::forward<DeducedHandler>(h),
ws, std::forward<Args>(args)...) ws, std::forward<Args>(args)...)
{ {
(*this)(error_code{}, 0, false);
} }
void operator()(error_code ec, void operator()();
std::size_t bytes_used, bool again = true);
void operator()(error_code ec);
friend friend
void* asio_handler_allocate( void* asio_handler_allocate(
@@ -245,7 +239,9 @@ public:
friend friend
bool asio_handler_is_continuation(accept_op* op) bool asio_handler_is_continuation(accept_op* op)
{ {
return op->d_->cont; using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
} }
template<class Function> template<class Function>
@@ -262,27 +258,24 @@ template<class NextLayer>
template<class Decorator, class Handler> template<class Decorator, class Handler>
void void
stream<NextLayer>::accept_op<Decorator, Handler>:: stream<NextLayer>::accept_op<Decorator, Handler>::
operator()(error_code ec, operator()()
std::size_t bytes_used, bool again)
{ {
auto& d = *d_; auto& d = *d_;
d.cont = d.cont || again; http::async_read_header(d.ws.next_layer(),
if(ec) d.ws.stream_.buffer(), d.p,
goto upcall; std::move(*this));
switch(d.state) }
{
case 0:
// read message
d.state = 1;
http::async_read_some(d.ws.next_layer(),
d.ws.stream_.buffer(), d.p,
std::move(*this));
return;
case 1: template<class NextLayer>
template<class Decorator, class Handler>
void
stream<NextLayer>::accept_op<Decorator, Handler>::
operator()(error_code ec)
{
auto& d = *d_;
if(! ec)
{ {
BOOST_ASSERT(d.p.is_header_done()); BOOST_ASSERT(d.p.is_header_done());
d.ws.stream_.buffer().consume(bytes_used);
// Arguments from our state must be // Arguments from our state must be
// moved to the stack before releasing // moved to the stack before releasing
// the handler. // the handler.
@@ -302,8 +295,6 @@ operator()(error_code ec,
#endif #endif
return; return;
} }
}
upcall:
d_.invoke(ec); d_.invoke(ec);
} }
@@ -619,7 +610,7 @@ async_accept(AcceptHandler&& handler)
reset(); reset();
accept_op<decltype(&default_decorate_res), accept_op<decltype(&default_decorate_res),
handler_type<AcceptHandler, void(error_code)>>{ handler_type<AcceptHandler, void(error_code)>>{
init.completion_handler, *this, &default_decorate_res}; init.completion_handler, *this, &default_decorate_res}();
return init.result.get(); return init.result.get();
} }
@@ -641,7 +632,7 @@ async_accept_ex(ResponseDecorator const& decorator,
reset(); reset();
accept_op<ResponseDecorator, handler_type< accept_op<ResponseDecorator, handler_type<
AcceptHandler, void(error_code)>>{ AcceptHandler, void(error_code)>>{
init.completion_handler, *this, decorator}; init.completion_handler, *this, decorator}();
return init.result.get(); return init.result.get();
} }
@@ -664,7 +655,8 @@ async_accept(ConstBufferSequence const& buffers,
reset(); reset();
accept_op<decltype(&default_decorate_res), accept_op<decltype(&default_decorate_res),
handler_type<AcceptHandler, void(error_code)>>{ handler_type<AcceptHandler, void(error_code)>>{
init.completion_handler, *this, buffers, &default_decorate_res}; init.completion_handler, *this, buffers,
&default_decorate_res}();
return init.result.get(); return init.result.get();
} }
@@ -692,7 +684,8 @@ async_accept_ex(ConstBufferSequence const& buffers,
reset(); reset();
accept_op<ResponseDecorator, handler_type< accept_op<ResponseDecorator, handler_type<
AcceptHandler, void(error_code)>>{ AcceptHandler, void(error_code)>>{
init.completion_handler, *this, buffers, decorator}; init.completion_handler, *this, buffers,
decorator}();
return init.result.get(); return init.result.get();
} }

View File

@@ -91,13 +91,11 @@ stream<NextLayer>::
do_accept( do_accept(
Decorator const& decorator, error_code& ec) Decorator const& decorator, error_code& ec)
{ {
http::header_parser<true, http::fields> p; http::request_parser<http::empty_body> p;
auto const bytes_used = http::read_some( http::read_header(next_layer(),
next_layer(), stream_.buffer(), p, ec); stream_.buffer(), p, ec);
if(ec) if(ec)
return; return;
BOOST_ASSERT(p.is_header_done());
stream_.buffer().consume(bytes_used);
do_accept(p.get(), decorator, ec); do_accept(p.get(), decorator, ec);
} }

View File

@@ -30,12 +30,10 @@ namespace beast {
namespace websocket { namespace websocket {
/// The type of object holding HTTP Upgrade requests /// The type of object holding HTTP Upgrade requests
using request_type = using request_type = http::request<http::empty_body>;
http::message<true, http::empty_body, http::fields>;
/// The type of object holding HTTP Upgrade responses /// The type of object holding HTTP Upgrade responses
using response_type = using response_type = http::response<http::string_body>;
http::message<false, http::string_body, http::fields>;
/** Information about a WebSocket frame. /** Information about a WebSocket frame.

View File

@@ -256,134 +256,6 @@ public:
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
#if 0
// VFALCO This is broken
/*
Efficiently relay a message from one stream to another
*/
template<
bool isRequest,
class SyncWriteStream,
class DynamicBuffer,
class SyncReadStream>
void
relay(
SyncWriteStream& out,
DynamicBuffer& b,
SyncReadStream& in)
{
flat_buffer buffer{4096}; // 4K limit
header_parser<isRequest, fields> parser;
serializer<isRequest, buffer_body<
typename flat_buffer::const_buffers_type>,
fields> ws{parser.get()};
error_code ec;
do
{
auto const state0 = parser.state();
auto const bytes_used =
read_some(in, buffer, parser, ec);
BEAST_EXPECTS(! ec, ec.message());
switch(state0)
{
case parse_state::header:
{
BEAST_EXPECT(parser.is_header_done());
for(;;)
{
ws.write_some(out, ec);
if(ec == http::error::need_more)
{
ec = {};
break;
}
if(ec)
BOOST_THROW_EXCEPTION(system_error{ec});
}
break;
}
case parse_state::chunk_header:
{
// inspect parser.chunk_extension() here
if(parser.is_done())
boost::asio::write(out,
chunk_encode_final());
break;
}
case parse_state::body:
case parse_state::body_to_eof:
case parse_state::chunk_body:
{
if(! parser.is_done())
{
auto const body = parser.body();
boost::asio::write(out, chunk_encode(
false, boost::asio::buffer(
body.data(), body.size())));
}
break;
}
case parse_state::complete:
break;
}
buffer.consume(bytes_used);
}
while(! parser.is_done());
}
void
testRelay()
{
// Content-Length
{
test::string_istream is{ios_,
"GET / HTTP/1.1\r\n"
"Content-Length: 5\r\n"
"\r\n" // 37 byte header
"*****",
3 // max_read
};
test::string_ostream os{ios_};
flat_buffer b{16};
relay<true>(os, b, is);
}
// end of file
{
test::string_istream is{ios_,
"HTTP/1.1 200 OK\r\n"
"\r\n" // 19 byte header
"*****",
3 // max_read
};
test::string_ostream os{ios_};
flat_buffer b{16};
relay<false>(os, b, is);
}
// chunked
{
test::string_istream is{ios_,
"GET / HTTP/1.1\r\n"
"Transfer-Encoding: chunked\r\n"
"\r\n"
"5;x;y=1;z=\"-\"\r\n*****\r\n"
"3\r\n---\r\n"
"1\r\n+\r\n"
"0\r\n\r\n",
2 // max_read
};
test::string_ostream os{ios_};
flat_buffer b{16};
relay<true>(os, b, is);
}
}
#endif
//--------------------------------------------------------------------------
void void
run() run()
@@ -395,7 +267,6 @@ public:
doWriteStdStream(); doWriteStdStream();
doCustomParser(); doCustomParser();
doHEAD(); doHEAD();
doDeferredBody(); doDeferredBody();
} }
}; };

View File

@@ -25,57 +25,6 @@
namespace beast { namespace beast {
namespace http { namespace http {
class header_parser_test
: public beast::unit_test::suite
, public test::enable_yield_to
{
public:
static
boost::asio::const_buffers_1
buf(string_view s)
{
return {s.data(), s.size()};
}
void
testParse()
{
{
test::string_istream is{ios_,
"GET / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"\r\n"
};
flat_buffer db{1024};
header_parser<true, fields> p;
read_some(is, db, p);
BEAST_EXPECT(p.is_header_done());
}
{
test::string_istream is{ios_,
"POST / HTTP/1.1\r\n"
"User-Agent: test\r\n"
"Content-Length: 1\r\n"
"\r\n"
"*"
};
flat_buffer db{1024};
header_parser<true, fields> p;
read_some(is, db, p);
BEAST_EXPECT(p.is_header_done());
BEAST_EXPECT(! p.is_done());
}
}
void
run() override
{
testParse();
}
};
BEAST_DEFINE_TESTSUITE(header_parser,http,beast);
class parser_test class parser_test
: public beast::unit_test::suite : public beast::unit_test::suite
, public beast::test::enable_yield_to , public beast::test::enable_yield_to
@@ -335,30 +284,6 @@ public:
} }
} }
void
testExpect100Continue()
{
test::string_istream ss{ios_,
"POST / HTTP/1.1\r\n"
"Expect: 100-continue\r\n"
"Content-Length: 5\r\n"
"\r\n"
"*****"};
multi_buffer b;
error_code ec;
header_parser<true, fields> p0;
auto const bytes_used =
read_some(ss, b, p0, ec);
b.consume(bytes_used);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p0.is_header_done());
BEAST_EXPECT(! p0.is_done());
request_parser<string_body> p1{std::move(p0)};
read(ss, b, p1, ec);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p1.get().body == "*****");
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
template<class DynamicBuffer> template<class DynamicBuffer>