BodyReader may construct from a non-const message

fix #619
This commit is contained in:
Vinnie Falco
2017-07-07 14:32:51 -07:00
parent 0324dc371f
commit db59a92011
6 changed files with 132 additions and 12 deletions

View File

@ -2,6 +2,7 @@ Version 76:
* Always go through write_some
* Use Boost.Config
* BodyReader may construct from a non-const message
--------------------------------------------------------------------------------

View File

@ -29,7 +29,7 @@ In this table:
* `a` denotes a value of type `X`.
* `m` denotes a value of type `message const&` where
* `m` denotes a possibly const value of type `message&` where
`std::is_same<decltype(m.body), Body::value_type>:value == true`.
* `ec` is a value of type [link beast.ref.beast__error_code `error_code&`].
@ -51,6 +51,17 @@ In this table:
[
Constructible from `m`. The lifetime of `m` is guaranteed
to end no earlier than after the `X` is destroyed.
The constructor may optionally require that `m` is const, which
has these consequences:
* If `X` requires that `m` is a const reference, then serializers
constructed for messages with this body type will also require a
`const` reference to a message, otherwise:
* If `X` requires that `m` is a non-const reference, then serializers
constructed for messages with this body type will aso require
a non-const reference to a message.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if there was one.
]

View File

@ -52,11 +52,20 @@ do_visit(error_code& ec, Visit& visit)
boost::get<T1>(pv_)));
}
//------------------------------------------------------------------------------
template<bool isRequest, class Body,
class Fields, class ChunkDecorator>
serializer<isRequest, Body, Fields, ChunkDecorator>::
serializer(message<isRequest, Body, Fields> const& m,
ChunkDecorator const& d)
serializer(value_type& m)
: m_(m)
{
}
template<bool isRequest, class Body,
class Fields, class ChunkDecorator>
serializer<isRequest, Body, Fields, ChunkDecorator>::
serializer(value_type& m, ChunkDecorator const& d)
: m_(m)
, d_(d)
{

View File

@ -127,12 +127,34 @@ template<
class ChunkDecorator = no_chunk_decorator>
class serializer
{
public:
static_assert(is_body<Body>::value,
"Body requirements not met");
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
/** The type of the message referenced by this object.
This may be const or non-const depending on the
implementation of the corresponding @b BodyReader.
*/
#if BEAST_DOXYGEN
using value_type = implementation_defined;
#else
using value_type =
typename std::conditional<
std::is_constructible<typename Body::reader,
message<isRequest, Body, Fields>&,
error_code&>::value &&
! std::is_constructible<typename Body::reader,
message<isRequest, Body, Fields> const&,
error_code&>::value,
message<isRequest, Body, Fields>,
message<isRequest, Body, Fields> const>::type;
#endif
private:
enum
{
do_construct = 0,
@ -225,7 +247,7 @@ class serializer
boost::asio::const_buffers_1>>; // crlf
using pcb8_t = buffer_prefix_view<cb8_t const&>;
message<isRequest, Body, Fields> const& m_;
value_type& m_;
boost::optional<typename Fields::reader> frd_;
boost::optional<reader> rd_;
boost::variant<boost::blank,
@ -258,14 +280,34 @@ public:
@ref next. This allows the message to be lazily created.
For example, if the header is filled in before serialization.
@param msg The message to serialize, which must remain valid
for the lifetime of the serializer.
@param msg A reference to the message to serialize, which must
remain valid for the lifetime of the serializer. Depending on
the type of Body used, this may or may not be a `const` reference.
@param decorator An optional decorator to use.
@note This function participates in overload resolution only if
Body::reader is constructible from a `const` message reference.
*/
explicit
serializer(message<isRequest, Body, Fields> const& msg,
ChunkDecorator const& decorator = ChunkDecorator{});
serializer(value_type& msg);
/** Constructor
The implementation guarantees that the message passed on
construction will not be accessed until the first call to
@ref next. This allows the message to be lazily created.
For example, if the header is filled in before serialization.
@param msg A reference to the message to serialize, which must
remain valid for the lifetime of the serializer. Depending on
the type of Body used, this may or may not be a `const` reference.
@param decorator The decorator to use.
@note This function participates in overload resolution only if
Body::reader is constructible from a `const` message reference.
*/
explicit
serializer(value_type& msg, ChunkDecorator const& decorator);
/// Returns the serialized buffer size limit
std::size_t

View File

@ -87,10 +87,10 @@ struct is_body_reader<T, beast::detail::void_t<
is_const_buffer_sequence<
typename T::reader::const_buffers_type>::value &&
std::is_constructible<typename T::reader,
message<true, T, detail::fields_model> const&,
message<true, T, detail::fields_model>&,
error_code&>::value &&
std::is_constructible<typename T::reader,
message<false, T, detail::fields_model> const&,
message<false, T, detail::fields_model>&,
error_code&>::value
> {};
#endif

View File

@ -17,6 +17,63 @@ namespace http {
class serializer_test : public beast::unit_test::suite
{
public:
struct const_body
{
struct value_type{};
struct reader
{
using const_buffers_type =
boost::asio::const_buffers_1;
template<bool isRequest, class Fields>
reader(message<isRequest, const_body, Fields> const&,
error_code&);
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code&);
};
};
struct mutable_body
{
struct value_type{};
struct reader
{
using const_buffers_type =
boost::asio::const_buffers_1;
template<bool isRequest, class Fields>
reader(message<isRequest, mutable_body, Fields>&,
error_code&);
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code&);
};
};
BOOST_STATIC_ASSERT(std::is_const< serializer<
true, const_body>::value_type>::value);
BOOST_STATIC_ASSERT(! std::is_const<serializer<
true, mutable_body>::value_type>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
serializer<true, const_body>,
message <true, const_body>&>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
serializer<true, const_body>,
message <true, const_body> const&>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
serializer<true, mutable_body>,
message <true, mutable_body>&>::value);
BOOST_STATIC_ASSERT(! std::is_constructible<
serializer<true, mutable_body>,
message <true, mutable_body> const&>::value);
struct lambda
{
std::size_t size;