New BodyReader and BodyWriter constructors (API Change):

fix #884

* BodyReader and BodyWriter constructors now require the header and
  body elements to be passed as distinct header and value_type objects.

This enables the composition of body types, for example:

    http::response<compressed_body<http::string_body>> res;

* The previous single-argument constructors are deprecated and will be
  removed in a subsequent version.

Actions Required:

* Change user-defined instances of BodyReader or BodyWriter constructor
  signatures to the two-argument form.

OR

* Define the macro BOOST_BEAST_ALLOW_DEPRECATED in the project (which
  will accept both the new and the deprecated signatures).
This commit is contained in:
Damian Jarek
2017-11-13 23:34:14 +01:00
committed by Vinnie Falco
parent d796319476
commit b76ab4450a
24 changed files with 358 additions and 107 deletions

View File

@@ -41,27 +41,25 @@ In this table:
`std::is_same<R, B::reader>::value == true`. `std::is_same<R, B::reader>::value == true`.
* `a` denotes a value of type `R`. * `a` denotes a value of type `R`.
* `b` is an object whose type meets the requirements of __ConstBufferSequence__ * `b` is an object whose type meets the requirements of __ConstBufferSequence__
* `m` denotes a value of type `message&` where * `h` denotes a value of type `header<isRequest, Fields>&`.
`std::is_same<decltype(m.body), Body::value_type>::value == true`. * `v` denotes a value of type `Body::value_type&`.
* `n` is a value of type `boost::optional<std::uint64_t>`. * `n` is a value of type `boost::optional<std::uint64_t>`.
* `ec` is a value of type [link beast.ref.boost__beast__error_code `error_code&`]. * `ec` is a value of type [link beast.ref.boost__beast__error_code `error_code&`].
[table Valid expressions [table Valid expressions
[[Expression] [Type] [Semantics, Pre/Post-conditions]] [[Expression] [Type] [Semantics, Pre/Post-conditions]]
[ [
[`R{m};`] [`R{h,v};`]
[] []
[ [
Constructible from `m`. The lifetime of `m` is guaranteed to Constructible from `h` and `v`. The lifetime of `h` and `v`
end no earlier than after the `R` is destroyed. The constructor is guaranteed to end no earlier than after the `R` is destroyed.
will be called after a complete header is stored in `m`, and The constructor will be called after a complete header is stored
before parsing body octets for messages indicating that a body in `h`, and before parsing body octets for messages indicating
is present The reader shall not access the contents of `m` before that a body is present.
The reader shall not access the contents of `h` or `v` before
the first call to `init`, permitting lazy construction of the the first call to `init`, permitting lazy construction of the
message. 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.
] ]
][ ][
[`a.init(n, ec)`] [`a.init(n, ec)`]

View File

@@ -42,8 +42,8 @@ In this table:
* `B` denotes a __Body__ where * `B` denotes a __Body__ where
`std::is_same<W, B::writer>::value == true`. `std::is_same<W, B::writer>::value == true`.
* `a` denotes a value of type `W`. * `a` denotes a value of type `W`.
* `m` denotes a possibly const value of type `message&` where * `h` denotes a const value of type `header<isRequest, Fields> const&`.
`std::is_same<decltype(m.body), Body::value_type>:value == true`. * `v` denotes a possibly const value of type `Body::value_type&`.
* `ec` is a value of type [link beast.ref.boost__beast__error_code `error_code&`]. * `ec` is a value of type [link beast.ref.boost__beast__error_code `error_code&`].
* `W<T>` is the type `boost::optional<std::pair<T, bool>>`. * `W<T>` is the type `boost::optional<std::pair<T, bool>>`.
@@ -57,23 +57,23 @@ In this table:
This is the type of buffer returned by `W::get`. This is the type of buffer returned by `W::get`.
] ]
][ ][
[`W{m};`] [`W{h,v};`]
[] []
[ [
Constructible from `m`. The lifetime of `m` is guaranteed Constructible from `h` and `v`. The lifetime of `h` and `v`
to end no earlier than after the `W` is destroyed. is guaranteed to end no earlier than after the `W` is destroyed.
The writer shall not access the contents of `m` before the The writer shall not access the contents of `h` or `v` before
first call to `init`, permitting lazy construction of the the first call to `init`, permitting lazy construction of the
message. message.
The constructor may optionally require that `m` is const, which The constructor may optionally require that `v` is const, which
has these consequences: has these consequences:
* If `W` requires that `m` is a const reference, then serializers * If `W` requires that `v` is a const reference, then serializers
constructed for messages with this body type will also require a constructed for messages with this body type will also require a
const reference to a message, otherwise: const reference to a message, otherwise:
* If `W` requires that `m` is a non-const reference, then serializers * If `W` requires that `v` is a non-const reference, then serializers
constructed for messages with this body type will aso require constructed for messages with this body type will aso require
a non-const reference to a message. a non-const reference to a message.
] ]

View File

@@ -70,9 +70,8 @@ struct basic_dynamic_body
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, reader(header<isRequest, Fields>&, value_type& b)
basic_dynamic_body, Fields>& msg) : body_(b)
: body_(msg.body())
{ {
} }
@@ -140,9 +139,8 @@ struct basic_dynamic_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
basic_dynamic_body, Fields> const& m) : body_(b)
: body_(m.body())
{ {
} }

View File

@@ -239,8 +239,8 @@ public:
// Constructor. // Constructor.
// //
// `m` holds the message we are serializing, which will // `h` holds the headers of the message we are
// always have the `basic_file_body` as the body type. // serializing, while `b` holds the body.
// //
// Note that the message is passed by non-const reference. // Note that the message is passed by non-const reference.
// This is intentional, because reading from the file // This is intentional, because reading from the file
@@ -262,8 +262,7 @@ public:
// a time. // a time.
// //
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
writer(message< writer(header<isRequest, Fields>& h, value_type& b);
isRequest, basic_file_body, Fields>& m);
// Initializer // Initializer
// //
@@ -296,9 +295,11 @@ template<class File>
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
basic_file_body<File>:: basic_file_body<File>::
writer:: writer::
writer(message<isRequest, basic_file_body, Fields>& m) writer(header<isRequest, Fields>& h, value_type& b)
: body_(m.body()) : body_(b)
{ {
boost::ignore_unused(h);
// The file must already be open // The file must already be open
BOOST_ASSERT(body_.file_.is_open()); BOOST_ASSERT(body_.file_.is_open());
@@ -398,13 +399,12 @@ public:
// //
// This is called after the header is parsed and // This is called after the header is parsed and
// indicates that a non-zero sized body may be present. // indicates that a non-zero sized body may be present.
// `m` holds the message we are receiving, which will // `h` holds the received message headers.
// always have the `basic_file_body` as the body type. // `b` is an instance of `basic_file_body`.
// //
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader( reader(header<isRequest, Fields>&h, value_type& b);
message<isRequest, basic_file_body, Fields>& m);
// Initializer // Initializer
// //
@@ -447,9 +447,10 @@ template<class File>
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
basic_file_body<File>:: basic_file_body<File>::
reader:: reader::
reader(message<isRequest, basic_file_body, Fields>& m) reader(header<isRequest, Fields>& h, value_type& body)
: body_(m.body()) : body_(body)
{ {
boost::ignore_unused(h);
} }
template<class File> template<class File>

View File

@@ -105,8 +105,8 @@ struct buffer_body
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, buffer_body, Fields>& m) reader(header<isRequest, Fields>&, value_type& b)
: body_(m.body()) : body_(b)
{ {
} }
@@ -167,9 +167,8 @@ struct buffer_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
buffer_body, Fields> const& msg) : body_(b)
: body_(msg.body())
{ {
} }

View File

@@ -194,6 +194,22 @@ struct is_fields_helper : T
t10::value && t11::value && t12::value>; t10::value && t11::value && t12::value>;
}; };
template<class T>
using has_deprecated_body_writer =
std::integral_constant<bool,
std::is_constructible<typename T::writer,
message<true, T, detail::fields_model>&>::value &&
std::is_constructible<typename T::writer,
message<false, T, detail::fields_model>&>::value>;
template<class T>
using has_deprecated_body_reader =
std::integral_constant<bool,
std::is_constructible<typename T::reader,
message<true, T, detail::fields_model>&>::value &&
std::is_constructible<typename T::reader,
message<false, T, detail::fields_model>&>::value>;
} // detail } // detail
} // http } // http
} // beast } // beast

View File

@@ -63,7 +63,7 @@ struct empty_body
{ {
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, empty_body, Fields>&) reader(header<isRequest, Fields>&, value_type&)
{ {
} }
@@ -104,8 +104,7 @@ struct empty_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const&)
empty_body, Fields> const&)
{ {
} }

View File

@@ -123,9 +123,8 @@ struct basic_file_body<file_win32>
boost::asio::const_buffer; boost::asio::const_buffer;
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
writer(message<isRequest, writer(header<isRequest, Fields>&, value_type& b)
basic_file_body<file_win32>, Fields>& m) : body_(b)
: body_(m.body())
{ {
} }
@@ -167,8 +166,8 @@ struct basic_file_body<file_win32>
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, basic_file_body, Fields>& m) reader(header<isRequest, Fields>&, value_type& b)
: body_(m.body()) : body_(b)
{ {
} }

View File

@@ -20,26 +20,87 @@ namespace http {
template<bool isRequest, class Body, class Allocator> template<bool isRequest, class Body, class Allocator>
parser<isRequest, Body, Allocator>:: parser<isRequest, Body, Allocator>::
parser() parser()
: parser{detail::has_deprecated_body_reader<Body>{}}
{
}
template<bool isRequest, class Body, class Allocator>
parser<isRequest, Body, Allocator>::
parser(std::true_type)
: rd_(m_) : rd_(m_)
{ {
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
// Deprecated BodyReader Concept (v1.66)
static_assert(sizeof(Body) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
}
template<bool isRequest, class Body, class Allocator>
parser<isRequest, Body, Allocator>::
parser(std::false_type)
: rd_(m_.base(), m_.body())
{
} }
template<bool isRequest, class Body, class Allocator> template<bool isRequest, class Body, class Allocator>
template<class Arg1, class... ArgN, class> template<class Arg1, class... ArgN, class>
parser<isRequest, Body, Allocator>:: parser<isRequest, Body, Allocator>::
parser(Arg1&& arg1, ArgN&&... argn) parser(Arg1&& arg1, ArgN&&... argn)
: parser(std::forward<Arg1>(arg1),
detail::has_deprecated_body_reader<Body>{},
std::forward<ArgN>(argn)...)
{
}
// VFALCO arg1 comes before `true_type` to make
// the signature unambiguous.
template<bool isRequest, class Body, class Allocator>
template<class Arg1, class... ArgN, class>
parser<isRequest, Body, Allocator>::
parser(Arg1&& arg1, std::true_type, ArgN&&... argn)
: m_(std::forward<Arg1>(arg1), : m_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...) std::forward<ArgN>(argn)...)
, rd_(m_) , rd_(m_)
{ {
m_.clear(); m_.clear();
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
/* Deprecated BodyWriter Concept (v1.66) */
static_assert(sizeof(Body) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif // BOOST_BEAST_ALLOW_DEPRECATED
}
// VFALCO arg1 comes before `false_type` to make
// the signature unambiguous.
template<bool isRequest, class Body, class Allocator>
template<class Arg1, class... ArgN, class>
parser<isRequest, Body, Allocator>::
parser(Arg1&& arg1, std::false_type, ArgN&&... argn)
: m_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
, rd_(m_.base(), m_.body())
{
m_.clear();
} }
template<bool isRequest, class Body, class Allocator> template<bool isRequest, class Body, class Allocator>
template<class OtherBody, class... Args, class> template<class OtherBody, class... Args, class>
parser<isRequest, Body, Allocator>:: parser<isRequest, Body, Allocator>::
parser(parser<isRequest, OtherBody, Allocator>&& other, parser(
Args&&... args) parser<isRequest, OtherBody, Allocator>&& other,
Args&&... args)
: parser(detail::has_deprecated_body_reader<Body>{},
std::move(other), std::forward<Args>(args)...)
{
}
template<bool isRequest, class Body, class Allocator>
template<class OtherBody, class... Args, class>
parser<isRequest, Body, Allocator>::
parser(std::true_type,
parser<isRequest, OtherBody, Allocator>&& other,
Args&&... args)
: base_type(std::move(other)) : base_type(std::move(other))
, m_(other.release(), std::forward<Args>(args)...) , m_(other.release(), std::forward<Args>(args)...)
, rd_(m_) , rd_(m_)
@@ -47,6 +108,25 @@ parser(parser<isRequest, OtherBody, Allocator>&& other,
if(other.rd_inited_) if(other.rd_inited_)
BOOST_THROW_EXCEPTION(std::invalid_argument{ BOOST_THROW_EXCEPTION(std::invalid_argument{
"moved-from parser has a body"}); "moved-from parser has a body"});
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
// Deprecated BodyReader Concept (v1.66)
static_assert(sizeof(Body) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
}
template<bool isRequest, class Body, class Allocator>
template<class OtherBody, class... Args, class>
parser<isRequest, Body, Allocator>::
parser(std::false_type, parser<isRequest, OtherBody, Allocator>&& other,
Args&&... args)
: base_type(std::move(other))
, m_(other.release(), std::forward<Args>(args)...)
, rd_(m_.base(), m_.body())
{
if(other.rd_inited_)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"moved-from parser has a body"});
} }
} // http } // http

View File

@@ -57,10 +57,32 @@ do_visit(error_code& ec, Visit& visit)
template< template<
bool isRequest, class Body, class Fields> bool isRequest, class Body, class Fields>
serializer<isRequest, Body, Fields>:: serializer<isRequest, Body, Fields>::
serializer(value_type& m) serializer(value_type& m, std::true_type)
: m_(m) : m_(m)
, wr_(m_) , wr_(m_)
{ {
#ifndef BOOST_BEAST_ALLOW_DEPRECATED
// Deprecated BodyWriter Concept (v1.66)
static_assert(sizeof(Body) == 0,
BOOST_BEAST_DEPRECATION_STRING);
#endif
}
template<
bool isRequest, class Body, class Fields>
serializer<isRequest, Body, Fields>::
serializer(value_type& m, std::false_type)
: m_(m)
, wr_(m_.base(), m_.body())
{
}
template<
bool isRequest, class Body, class Fields>
serializer<isRequest, Body, Fields>::
serializer(value_type& m)
: serializer(m, detail::has_deprecated_body_writer<Body>{})
{
} }
template< template<

View File

@@ -303,6 +303,39 @@ public:
private: private:
friend class basic_parser<isRequest, parser>; friend class basic_parser<isRequest, parser>;
parser(std::true_type);
parser(std::false_type);
template<class OtherBody, class... Args,
class = typename std::enable_if<
! std::is_same<Body, OtherBody>::value>::type>
parser(
std::true_type,
parser<isRequest, OtherBody, Allocator>&& parser,
Args&&... args);
template<class OtherBody, class... Args,
class = typename std::enable_if<
! std::is_same<Body, OtherBody>::value>::type>
parser(
std::false_type,
parser<isRequest, OtherBody, Allocator>&& parser,
Args&&... args);
template<class Arg1, class... ArgN,
class = typename std::enable_if<
! detail::is_parser<typename
std::decay<Arg1>::type>::value>::type>
explicit
parser(Arg1&& arg1, std::true_type, ArgN&&... argn);
template<class Arg1, class... ArgN,
class = typename std::enable_if<
! detail::is_parser<typename
std::decay<Arg1>::type>::value>::type>
explicit
parser(Arg1&& arg1, std::false_type, ArgN&&... argn);
void void
on_request_impl( on_request_impl(
verb method, verb method,

View File

@@ -71,14 +71,20 @@ public:
#if BOOST_BEAST_DOXYGEN #if BOOST_BEAST_DOXYGEN
using value_type = implementation_defined; using value_type = implementation_defined;
#else #else
using value_type = using value_type = typename std::conditional<
typename std::conditional< (std::is_constructible<typename Body::writer,
std::is_constructible<typename Body::writer, header<isRequest, Fields>&,
message<isRequest, Body, Fields>&>::value && typename Body::value_type&>::value &&
! std::is_constructible<typename Body::writer, ! std::is_constructible<typename Body::writer,
message<isRequest, Body, Fields> const&>::value, header<isRequest, Fields> const&,
message<isRequest, Body, Fields>, typename Body::value_type const&>::value) ||
message<isRequest, Body, Fields> const>::type; // Deprecated BodyWriter Concept (v1.66)
(std::is_constructible<typename Body::writer,
message<isRequest, Body, Fields>&>::value &&
! std::is_constructible<typename Body::writer,
message<isRequest, Body, Fields> const&>::value),
message<isRequest, Body, Fields>,
message<isRequest, Body, Fields> const>::type;
#endif #endif
private: private:
@@ -188,6 +194,8 @@ private:
bool header_done_ = false; bool header_done_ = false;
bool more_; bool more_;
serializer(value_type& msg, std::true_type);
serializer(value_type& msg, std::false_type);
public: public:
/// Constructor /// Constructor
serializer(serializer&&) = default; serializer(serializer&&) = default;

View File

@@ -73,9 +73,8 @@ public:
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, reader(header<isRequest, Fields>&, value_type& b)
span_body, Fields>& m) : body_(b)
: body_(m.body())
{ {
} }
@@ -138,9 +137,8 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
span_body, Fields> const& msg) : body_(b)
: body_(msg.body())
{ {
} }

View File

@@ -81,9 +81,8 @@ public:
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, reader(header<isRequest, Fields>&, value_type& b)
basic_string_body, Fields>& m) : body_(b)
: body_(m.body())
{ {
} }
@@ -166,9 +165,8 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
basic_string_body, Fields> const& msg) : body_(b)
: body_(msg.body())
{ {
} }

View File

@@ -89,11 +89,19 @@ struct is_body_writer<T, beast::detail::void_t<
std::declval<typename T::writer>().get(std::declval<error_code&>()), std::declval<typename T::writer>().get(std::declval<error_code&>()),
(void)0)>> : std::integral_constant<bool, (void)0)>> : std::integral_constant<bool,
boost::asio::is_const_buffer_sequence< boost::asio::is_const_buffer_sequence<
typename T::writer::const_buffers_type>::value && typename T::writer::const_buffers_type>::value && (
(std::is_constructible<typename T::writer,
header<true, detail::fields_model>&,
typename T::value_type&>::value &&
std::is_constructible<typename T::writer, std::is_constructible<typename T::writer,
header<false, detail::fields_model>&,
typename T::value_type&>::value) ||
// Deprecated BodyWriter Concept (v1.66)
(std::is_constructible<typename T::writer,
message<true, T, detail::fields_model>&>::value && message<true, T, detail::fields_model>&>::value &&
std::is_constructible<typename T::writer, std::is_constructible<typename T::writer,
message<false, T, detail::fields_model>&>::value message<false, T, detail::fields_model>&>::value)
)
> {}; > {};
#endif #endif
@@ -136,11 +144,18 @@ struct is_body_reader<T, beast::detail::void_t<decltype(
std::declval<typename T::reader&>().finish( std::declval<typename T::reader&>().finish(
std::declval<error_code&>()), std::declval<error_code&>()),
(void)0)>> : std::integral_constant<bool, (void)0)>> : std::integral_constant<bool,
(std::is_constructible<typename T::reader,
header<true, detail::fields_model>&,
typename T::value_type&>::value &&
std::is_constructible<typename T::reader, std::is_constructible<typename T::reader,
header<false,detail::fields_model>&,
typename T::value_type&>::value) ||
// Deprecated BodyReader Concept (v1.66)
(std::is_constructible<typename T::reader,
message<true, T, detail::fields_model>&>::value && message<true, T, detail::fields_model>&>::value &&
std::is_constructible<typename T::reader, std::is_constructible<typename T::reader,
message<false, T, detail::fields_model>&>::value message<false, T, detail::fields_model>&>::value)
> >
{ {
}; };
#endif #endif

View File

@@ -76,9 +76,8 @@ public:
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, reader(header<isRequest, Fields>&, value_type& b)
vector_body, Fields>& m) : body_(b)
: body_(m.body())
{ {
} }
@@ -155,9 +154,8 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
vector_body, Fields> const& msg) : body_(b)
: body_(msg.body())
{ {
} }

View File

@@ -21,6 +21,7 @@ project /boost/beast/test
cxx11_variadic_templates cxx11_variadic_templates
] ]
<include>./extern <include>./extern
<define>BOOST_BEAST_ALLOW_DEPRECATED
; ;
path-constant ZLIB_SOURCES : path-constant ZLIB_SOURCES :

View File

@@ -7,6 +7,8 @@
# Official repository: https://github.com/boostorg/beast # Official repository: https://github.com/boostorg/beast
# #
add_definitions (-DBOOST_BEAST_ALLOW_DEPRECATED)
GroupSources(include/boost/beast beast) GroupSources(include/boost/beast beast)
GroupSources(test/extras/include/boost/beast extras) GroupSources(test/extras/include/boost/beast extras)
GroupSources(subtree/unit_test/include/boost/beast extras) GroupSources(subtree/unit_test/include/boost/beast extras)

View File

@@ -48,7 +48,7 @@ public:
::operator delete(p); ::operator delete(p);
} }
template <class U> template<class U>
friend friend
bool bool
operator==(test_allocator<T> const&, test_allocator<U> const&) noexcept operator==(test_allocator<T> const&, test_allocator<U> const&) noexcept

View File

@@ -36,6 +36,42 @@ public:
using parser_type = using parser_type =
parser<isRequest, string_body>; parser<isRequest, string_body>;
struct deprecated_body
{
using value_type = std::string;
class reader
{
public:
template<bool isRequest, class Fields>
explicit
reader(message<isRequest, deprecated_body, Fields>&)
{
}
void
init(boost::optional<std::uint64_t> const&, error_code& ec)
{
ec = {};
}
template<class ConstBufferSequence>
std::size_t
put(ConstBufferSequence const& buffers, error_code& ec)
{
ec = {};
return boost::asio::buffer_size(buffers);
}
void
finish(error_code& ec)
{
ec = {};
}
};
};
static static
boost::asio::const_buffer boost::asio::const_buffer
buf(string_view s) buf(string_view s)
@@ -343,6 +379,12 @@ public:
BEAST_EXPECT(std::distance(m1.begin(), m1.end()) == 0); BEAST_EXPECT(std::distance(m1.begin(), m1.end()) == 0);
} }
void testBodyReaderCtor()
{
request_parser<deprecated_body> p;
boost::ignore_unused(p);
}
void void
run() override run() override
{ {
@@ -351,6 +393,7 @@ public:
testNeedMore<multi_buffer>(); testNeedMore<multi_buffer>();
testGotSome(); testGotSome();
testIssue818(); testIssue818();
testBodyReaderCtor();
} }
}; };

View File

@@ -20,6 +20,40 @@ namespace http {
class serializer_test : public beast::unit_test::suite class serializer_test : public beast::unit_test::suite
{ {
public: public:
struct deprecated_body
{
using value_type = std::string;
class writer
{
public:
using const_buffers_type =
boost::asio::const_buffer;
value_type const& body_;
template<bool isRequest, class Fields>
explicit
writer(message<isRequest, deprecated_body, Fields> const& m):
body_{m.body()}
{
}
void init(error_code& ec)
{
ec.assign(0, ec.category());
}
boost::optional<std::pair<const_buffers_type, bool>>
get(error_code& ec)
{
ec.assign(0, ec.category());
return {{const_buffers_type{
body_.data(), body_.size()}, false}};
}
};
};
struct const_body struct const_body
{ {
struct value_type{}; struct value_type{};
@@ -30,7 +64,7 @@ public:
boost::asio::const_buffer; boost::asio::const_buffer;
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
writer(message<isRequest, const_body, Fields> const&); writer(header<isRequest, Fields> const&, value_type const&);
void void
init(error_code& ec); init(error_code& ec);
@@ -50,7 +84,7 @@ public:
boost::asio::const_buffer; boost::asio::const_buffer;
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
writer(message<isRequest, mutable_body, Fields>&); writer(header<isRequest, Fields>&, value_type&);
void void
init(error_code& ec); init(error_code& ec);
@@ -115,10 +149,20 @@ public:
} }
} }
void testBodyWriterCtor()
{
response<deprecated_body> res;
request<deprecated_body> req;
serializer<false, deprecated_body> sr1{res};
serializer<true, deprecated_body> sr2{req};
boost::ignore_unused(sr1, sr2);
}
void void
run() override run() override
{ {
testWriteLimit(); testWriteLimit();
testBodyWriterCtor();
} }
}; };

View File

@@ -34,7 +34,7 @@ struct span_body_test
BEAST_EXPECT(req.body().size() == 3); BEAST_EXPECT(req.body().size() == 3);
BEAST_EXPECT(B::size(req.body()) == 3); BEAST_EXPECT(B::size(req.body()) == 3);
B::writer r{req}; B::writer r{req, req.body()};
error_code ec; error_code ec;
r.init(ec); r.init(ec);
BEAST_EXPECTS(! ec, ec.message()); BEAST_EXPECTS(! ec, ec.message());
@@ -50,7 +50,7 @@ struct span_body_test
using B = span_body<char>; using B = span_body<char>;
request<B> req; request<B> req;
req.body() = span<char>{buf, sizeof(buf)}; req.body() = span<char>{buf, sizeof(buf)};
B::reader w{req}; B::reader w{req, req.body()};
error_code ec; error_code ec;
w.init(boost::none, ec); w.init(boost::none, ec);
BEAST_EXPECTS(! ec, ec.message()); BEAST_EXPECTS(! ec, ec.message());

View File

@@ -48,9 +48,8 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
unsized_body, Fields> const& msg) : body_(b)
: body_(msg.body())
{ {
} }
@@ -93,9 +92,8 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
test_body, Fields> const& msg) : body_(b)
: body_(msg.body())
{ {
} }
@@ -230,9 +228,8 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, writer(header<isRequest, Fields> const&, value_type const& b)
fail_body, Fields> const& msg) : body_(b)
: body_(msg.body())
{ {
} }

View File

@@ -57,11 +57,12 @@ public:
/** Construct the writer. /** Construct the writer.
@param msg The message whose body is to be serialized. @param h The header for the message being serialized
@param body The body being serialized
*/ */
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Fields>
explicit BodyWriter(header<isRequest, Fields> const& h, value_type const& body);
BodyWriter(message<isRequest, Body, Fields> const& msg);
/** Initialize the writer. /** Initialize the writer.
@@ -120,11 +121,12 @@ struct BodyReader
{ {
/** Construct the reader. /** Construct the reader.
@param msg The message whose body is to be parsed. @param h The header for the message being parsed
@param body The body to store the parsed results into
*/ */
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Fields>
explicit BodyReader(header<isRequest, Fields>& h, value_type& body);
BodyReader(message<isRequest, Body, Fields>& msg);
/** Initialize the reader. /** Initialize the reader.