parser requires basic_fields (API Change):

* `parser` is now templated on Allocator

* `parser` only produces messages using `basic_fields<Allocator>`
  as the Fields type.

* message-oriented read and async_read only work on messages
  using basic_fields as the Fields type.

Actions Required:

* Callers using `parser` with Fields types other than basic_fields
  will need to create their own subclass of basic_parser to work
  with their custom fields type.
This commit is contained in:
Vinnie Falco
2017-06-19 11:54:53 -07:00
parent 72ce21927c
commit 50902c3938
7 changed files with 68 additions and 52 deletions

View File

@@ -8,6 +8,16 @@ Version 62:
* Clear the error faster * Clear the error faster
* Avoid explicit operator bool for error * Avoid explicit operator bool for error
API Changes:
* parser requires basic_fields
Actions Required:
* Callers using `parser` with Fields types other than basic_fields
will need to create their own subclass of basic_parser to work
with their custom fields type.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Version 61: Version 61:

View File

@@ -464,7 +464,6 @@ do_head_request(
*/ */
template< template<
bool isRequest, bool isRequest,
class Fields = fields,
class SyncWriteStream, class SyncWriteStream,
class SyncReadStream, class SyncReadStream,
class DynamicBuffer, class DynamicBuffer,
@@ -487,10 +486,10 @@ relay(
char buf[2048]; char buf[2048];
// Create a parser with a buffer body to read from the input. // Create a parser with a buffer body to read from the input.
parser<isRequest, buffer_body, Fields> p; parser<isRequest, buffer_body> p;
// Create a serializer from the message contained in the parser. // Create a serializer from the message contained in the parser.
serializer<isRequest, buffer_body, Fields> sr{p.get()}; serializer<isRequest, buffer_body, fields> sr{p.get()};
// Read just the header from the input // Read just the header from the input
read_header(input, buffer, p, ec); read_header(input, buffer, p, ec);
@@ -684,13 +683,12 @@ write_ostream(
template< template<
class Allocator, class Allocator,
bool isRequest, bool isRequest,
class Body, class Body>
class Fields>
void void
read_istream( read_istream(
std::istream& is, std::istream& is,
basic_flat_buffer<Allocator>& buffer, basic_flat_buffer<Allocator>& buffer,
message<isRequest, Body, Fields>& msg, message<isRequest, Body, fields>& msg,
error_code& ec) error_code& ec)
{ {
// Create the message parser // Create the message parser
@@ -700,7 +698,7 @@ read_istream(
// a move construction in case the caller has constructed // a move construction in case the caller has constructed
// their message in a non-default way. // their message in a non-default way.
// //
parser<isRequest, Body, Fields> p{std::move(msg)}; parser<isRequest, Body> p{std::move(msg)};
do do
{ {

View File

@@ -14,19 +14,19 @@
namespace beast { namespace beast {
namespace http { namespace http {
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Allocator>
template<class Arg1, class... ArgN, class> template<class Arg1, class... ArgN, class>
parser<isRequest, Body, Fields>:: parser<isRequest, Body, Allocator>::
parser(Arg1&& arg1, ArgN&&... argn) parser(Arg1&& arg1, ArgN&&... argn)
: m_(std::forward<Arg1>(arg1), : m_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...) std::forward<ArgN>(argn)...)
{ {
} }
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Allocator>
template<class OtherBody, class... Args, class> template<class OtherBody, class... Args, class>
parser<isRequest, Body, Fields>:: parser<isRequest, Body, Allocator>::
parser(parser<isRequest, OtherBody, Fields>&& p, parser(parser<isRequest, OtherBody, Allocator>&& p,
Args&&... args) Args&&... args)
: base_type(std::move(p)) : base_type(std::move(p))
, m_(p.release(), std::forward<Args>(args)...) , m_(p.release(), std::forward<Args>(args)...)

View File

@@ -300,15 +300,15 @@ upcall:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<class Stream, class DynamicBuffer, template<class Stream, class DynamicBuffer,
bool isRequest, class Body, class Fields, bool isRequest, class Body, class Allocator,
class Handler> class Handler>
class read_msg_op class read_msg_op
{ {
using parser_type = using parser_type =
parser<isRequest, Body, Fields>; parser<isRequest, Body, Allocator>;
using message_type = using message_type =
message<isRequest, Body, Fields>; typename parser_type::value_type;
struct data struct data
{ {
@@ -383,11 +383,11 @@ public:
}; };
template<class Stream, class DynamicBuffer, template<class Stream, class DynamicBuffer,
bool isRequest, class Body, class Fields, bool isRequest, class Body, class Allocator,
class Handler> class Handler>
void void
read_msg_op<Stream, DynamicBuffer, read_msg_op<Stream, DynamicBuffer,
isRequest, Body, Fields, Handler>:: isRequest, Body, Allocator, Handler>::
operator()(error_code ec) operator()(error_code ec)
{ {
auto& d = *d_; auto& d = *d_;
@@ -693,12 +693,12 @@ async_read(
template< template<
class SyncReadStream, class SyncReadStream,
class DynamicBuffer, class DynamicBuffer,
bool isRequest, class Body, class Fields> bool isRequest, class Body, class Allocator>
void void
read( read(
SyncReadStream& stream, SyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg) message<isRequest, Body, basic_fields<Allocator>>& msg)
{ {
static_assert(is_sync_read_stream<SyncReadStream>::value, static_assert(is_sync_read_stream<SyncReadStream>::value,
"SyncReadStream requirements not met"); "SyncReadStream requirements not met");
@@ -717,12 +717,12 @@ read(
template< template<
class SyncReadStream, class SyncReadStream,
class DynamicBuffer, class DynamicBuffer,
bool isRequest, class Body, class Fields> bool isRequest, class Body, class Allocator>
void void
read( read(
SyncReadStream& stream, SyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg, message<isRequest, Body, basic_fields<Allocator>>& msg,
error_code& ec) error_code& ec)
{ {
static_assert(is_sync_read_stream<SyncReadStream>::value, static_assert(is_sync_read_stream<SyncReadStream>::value,
@@ -733,7 +733,7 @@ read(
"Body requirements not met"); "Body requirements not met");
static_assert(is_body_writer<Body>::value, static_assert(is_body_writer<Body>::value,
"BodyWriter requirements not met"); "BodyWriter requirements not met");
parser<isRequest, Body, Fields> p{std::move(msg)}; parser<isRequest, Body, Allocator> p{std::move(msg)};
p.eager(true); p.eager(true);
read(stream, buffer, p.base(), ec); read(stream, buffer, p.base(), ec);
if(ec) if(ec)
@@ -744,13 +744,13 @@ read(
template< template<
class AsyncReadStream, class AsyncReadStream,
class DynamicBuffer, class DynamicBuffer,
bool isRequest, class Body, class Fields, bool isRequest, class Body, class Allocator,
class ReadHandler> class ReadHandler>
async_return_type<ReadHandler, void(error_code)> async_return_type<ReadHandler, void(error_code)>
async_read( async_read(
AsyncReadStream& stream, AsyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg, message<isRequest, Body, basic_fields<Allocator>>& msg,
ReadHandler&& handler) ReadHandler&& handler)
{ {
static_assert(is_async_read_stream<AsyncReadStream>::value, static_assert(is_async_read_stream<AsyncReadStream>::value,
@@ -764,7 +764,7 @@ async_read(
async_completion<ReadHandler, async_completion<ReadHandler,
void(error_code)> init{handler}; void(error_code)> init{handler};
detail::read_msg_op<AsyncReadStream, DynamicBuffer, detail::read_msg_op<AsyncReadStream, DynamicBuffer,
isRequest, Body, Fields, handler_type< isRequest, Body, Allocator, handler_type<
ReadHandler, void(error_code)>>{ ReadHandler, void(error_code)>>{
init.completion_handler, stream, buffer, msg}( init.completion_handler, stream, buffer, msg}(
error_code{}); error_code{});

View File

@@ -14,6 +14,7 @@
#include <beast/http/type_traits.hpp> #include <beast/http/type_traits.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <memory>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -23,24 +24,27 @@ namespace http {
/** 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
a series of octets into a @ref message. a series of octets into a @ref message using the @ref basic_fields
container to represent the fields.
@tparam isRequest Indicates whether a request or response @tparam isRequest Indicates whether a request or response
will be parsed. will be parsed.
@tparam Body The type used to represent the body. @tparam Body The type used to represent the body. This must
meet the requirements of @b Body.
@tparam Fields The type of container used to represent the fields. @tparam Allocator The type of allocator used with the
@ref basic_fields container.
@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< template<
bool isRequest, bool isRequest,
class Body, class Body,
class Fields = fields> class Allocator = std::allocator<char>>
class parser class parser
: public basic_parser<isRequest, : public basic_parser<isRequest,
parser<isRequest, Body, Fields>> parser<isRequest, Body, Allocator>>
{ {
static_assert(is_body<Body>::value, static_assert(is_body<Body>::value,
"Body requirements not met"); "Body requirements not met");
@@ -52,14 +56,15 @@ class parser
friend class parser; friend class parser;
using base_type = basic_parser<isRequest, using base_type = basic_parser<isRequest,
parser<isRequest, Body, Fields>>; parser<isRequest, Body, Allocator>>;
message<isRequest, Body, Fields> m_; message<isRequest, Body, basic_fields<Allocator>> m_;
boost::optional<typename Body::writer> wr_; boost::optional<typename Body::writer> wr_;
public: public:
/// The type of message returned by the parser /// The type of message returned by the parser
using value_type = message<isRequest, Body, Fields>; using value_type =
message<isRequest, Body, basic_fields<Allocator>>;
/// Constructor (default) /// Constructor (default)
parser() = default; parser() = default;
@@ -126,6 +131,9 @@ public:
@throws std::invalid_argument Thrown when the constructed-from @throws std::invalid_argument Thrown when the constructed-from
parser has already initialized a body writer. parser has already initialized a body writer.
@note This function participates in overload resolution only
if the other parser uses a different body type.
*/ */
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
template<class OtherBody, class... Args> template<class OtherBody, class... Args>
@@ -135,13 +143,13 @@ public:
! std::is_same<Body, OtherBody>::value>::type> ! std::is_same<Body, OtherBody>::value>::type>
#endif #endif
explicit explicit
parser(parser<isRequest, OtherBody, Fields>&& parser, parser(parser<isRequest, OtherBody,
Args&&... args); Allocator>&& parser, Args&&... args);
/** Returns the parsed message. /** Returns the parsed message.
Depending on the progress of the parser, portions Depending on the parser's progress,
of this object may be incomplete. parts of this object may be incomplete.
*/ */
value_type const& value_type const&
get() const get() const
@@ -151,8 +159,8 @@ public:
/** Returns the parsed message. /** Returns the parsed message.
Depending on the progress of the parser, portions Depending on the parser's progress,
of this object may be incomplete. parts of this object may be incomplete.
*/ */
value_type& value_type&
get() get()
@@ -163,8 +171,8 @@ public:
/** Returns ownership of the parsed message. /** Returns ownership of the parsed message.
Ownership is transferred to the caller. Ownership is transferred to the caller.
Depending on the progress of the parser, portions Depending on the parser's progress,
of this object may be incomplete. parts of this object may be incomplete.
@par Requires @par Requires
@@ -253,12 +261,12 @@ private:
}; };
/// An HTTP/1 parser for producing a request message. /// An HTTP/1 parser for producing a request message.
template<class Body, class Fields = fields> template<class Body, class Allocator = std::allocator<char>>
using request_parser = parser<true, Body, Fields>; using request_parser = parser<true, Body, Allocator>;
/// An HTTP/1 parser for producing a response message. /// An HTTP/1 parser for producing a response message.
template<class Body, class Fields = fields> template<class Body, class Allocator = std::allocator<char>>
using response_parser = parser<false, Body, Fields>; using response_parser = parser<false, Body, Allocator>;
} // http } // http
} // beast } // beast

View File

@@ -614,12 +614,12 @@ async_read(
template< template<
class SyncReadStream, class SyncReadStream,
class DynamicBuffer, class DynamicBuffer,
bool isRequest, class Body, class Fields> bool isRequest, class Body, class Allocator>
void void
read( read(
SyncReadStream& stream, SyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg); message<isRequest, Body, basic_fields<Allocator>>& msg);
/** Read a complete message from a stream. /** Read a complete message from a stream.
@@ -666,12 +666,12 @@ read(
template< template<
class SyncReadStream, class SyncReadStream,
class DynamicBuffer, class DynamicBuffer,
bool isRequest, class Body, class Fields> bool isRequest, class Body, class Allocator>
void void
read( read(
SyncReadStream& stream, SyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg, message<isRequest, Body, basic_fields<Allocator>>& msg,
error_code& ec); error_code& ec);
/** Read a complete message from a stream asynchronously. /** Read a complete message from a stream asynchronously.
@@ -735,7 +735,7 @@ read(
template< template<
class AsyncReadStream, class AsyncReadStream,
class DynamicBuffer, class DynamicBuffer,
bool isRequest, class Body, class Fields, bool isRequest, class Body, class Allocator,
class ReadHandler> class ReadHandler>
#if BEAST_DOXYGEN #if BEAST_DOXYGEN
void_or_deduced void_or_deduced
@@ -746,7 +746,7 @@ async_return_type<
async_read( async_read(
AsyncReadStream& stream, AsyncReadStream& stream,
DynamicBuffer& buffer, DynamicBuffer& buffer,
message<isRequest, Body, Fields>& msg, message<isRequest, Body, basic_fields<Allocator>>& msg,
ReadHandler&& handler); ReadHandler&& handler);
} // http } // http

View File

@@ -32,7 +32,7 @@ class parser_test
public: public:
template<bool isRequest> template<bool isRequest>
using parser_type = using parser_type =
parser<isRequest, string_body, fields>; parser<isRequest, string_body>;
static static
boost::asio::const_buffers_1 boost::asio::const_buffers_1