BodyReader, BodyWriter use two-phase init (API Change):

These types now perform error-based initialization in
a separate init() functions instead of in the constructor.

Actions Required:

* Modify instances of user-defined BodyReader and BodyWriter
  types to perfrom two-phase initialization, as per the
  updated documented type requirements.
This commit is contained in:
Vinnie Falco
2017-07-07 20:08:52 -07:00
parent 8a3df73ffc
commit e06a055503
19 changed files with 325 additions and 146 deletions

View File

@@ -10,12 +10,17 @@ Version 76:
API Changes: API Changes:
* Rename to serializer::keep_alive * Rename to serializer::keep_alive
* BodyReader, BodyWriter use two-phase init
Actions Required: Actions Required:
* Use serializer::keep_alive instead of serializer::close and * Use serializer::keep_alive instead of serializer::close and
take the logical NOT of the return value. take the logical NOT of the return value.
* Modify instances of user-defined BodyReader and BodyWriter
types to perfrom two-phase initialization, as per the
updated documented type requirements.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Version 75: Version 75:

View File

@@ -36,8 +36,14 @@ In this table:
* `R<T>` is the type `boost::optional<std::pair<T, bool>>`. * `R<T>` is the type `boost::optional<std::pair<T, bool>>`.
[table BodyReader requirements [heading Associated Types]
[[expression] [type] [semantics, pre/post-conditions]]
* __Body__
* [link beast.ref.beast__http__is_body_reader `is_body_reader`]
[heading BodyReader requirements]
[table Valid Expressions
[[Expression] [Type] [Semantics, Pre/Post-conditions]]
[ [
[`X::const_buffers_type`] [`X::const_buffers_type`]
[] []
@@ -46,22 +52,33 @@ In this table:
This is the type of buffer returned by `X::get`. This is the type of buffer returned by `X::get`.
] ]
][ ][
[`X(m,ec);`] [`X(m);`]
[] []
[ [
Constructible from `m`. The lifetime of `m` is guaranteed Constructible from `m`. The lifetime of `m` is guaranteed
to end no earlier than after the `X` is destroyed. to end no earlier than after the `X` is destroyed.
The reader shall not access the contents of `m` before the
first call to `init`, permitting lazy construction of the
message.
The constructor may optionally require that `m` is const, which The constructor may optionally require that `m` is const, which
has these consequences: has these consequences:
* If `X` requires that `m` is a const reference, then serializers * If `X` requires that `m` 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 `X` requires that `m` is a non-const reference, then serializers * If `X` requires that `m` 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.
]
][
[`a.init(ec)`]
[]
[
Called once to fully initialize the object before any calls to
`get`. The message body becomes valid before entering this function,
and remains valid until the reader is destroyed.
The function will ensure that `!ec` is `true` if there was The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if there was one. no error or set to the appropriate error code if there was one.
] ]
@@ -69,9 +86,9 @@ In this table:
[`a.get(ec)`] [`a.get(ec)`]
[`R<X::const_buffers_type>`] [`R<X::const_buffers_type>`]
[ [
Called repeatedly after `init` succeeds. This function returns Called one or more times after `init` succeeds. This function
`boost::none` if all buffers representing the body have been returns `boost::none` if all buffers representing the body have
returned in previous calls or if it sets `ec` to indicate an been returned in previous calls or if it sets `ec` to indicate an
error. Otherwise, if there are buffers remaining the function error. Otherwise, if there are buffers remaining the function
should return a pair with the first element containing a non-zero should return a pair with the first element containing a non-zero
length buffer sequence representing the next set of octets in length buffer sequence representing the next set of octets in
@@ -82,13 +99,6 @@ In this table:
The function will ensure that `!ec` is `true` if there was The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if there was one. no error or set to the appropriate error code if there was one.
] ]
][
[`is_body_reader<B>`]
[`std::true_type`]
[
An alias for `std::true_type` for `B`, otherwise an alias
for `std::false_type`.
]
] ]
] ]
@@ -96,4 +106,11 @@ In this table:
[concept_BodyReader] [concept_BodyReader]
[heading Models]
* [link beast.ref.beast__http__basic_dynamic_body.reader `basic_dynamic_body::reader`]
* [link beast.ref.beast__http__basic_file_body__reader `basic_file_body::reader`]
* [link beast.ref.beast__http__empty_body.reader `empty_body::reader`]
* [link beast.ref.beast__http__string_body.reader `string_body::reader`]
[endsect] [endsect]

View File

@@ -38,20 +38,40 @@ In this table:
* `ec` is a value of type [link beast.ref.beast__error_code `error_code&`]. * `ec` is a value of type [link beast.ref.beast__error_code `error_code&`].
[heading Associated Types]
* __Body__
* [link beast.ref.beast__http__is_body_writer `is_body_writer`]
[table Writer requirements [table Writer requirements
[[expression] [type] [semantics, pre/post-conditions]] [[expression] [type] [semantics, pre/post-conditions]]
[ [
[`X(m,n,ec);`] [`X(m);`]
[] []
[ [
Constructible from `m`. The lifetime of `m` is guaranteed Constructible from `m`. The lifetime of `m` is guaranteed to
to end no earlier than after the `X` is destroyed. The constructor end no earlier than after the `X` is destroyed. The constructor
will be called after a complete header is stored in `m`, and before will be called after a complete header is stored in `m`, and
parsing body octets for messages indicating that a body is present. before parsing body octets for messages indicating that a body
is present The writer shall not access the contents of `m` before
the first call to `init`, permitting lazy construction of the
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)`]
[]
[
Called once to fully initialize the object before any calls to
`put`. The message body is valid before entering this function,
and remains valid until the writer is destroyed.
The value of `n` will be set to the content length of the The value of `n` will be set to the content length of the
body if known, otherwise `n` will be equal to `boost::none`. body if known, otherwise `n` will be equal to `boost::none`.
Implementations of [*BodyWriter] may use this information to Implementations of [*BodyWriter] may use this information to
optimize allocation. optimize allocation.
The function will ensure that `!ec` is `true` if there was The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if there was one. no error or set to the appropriate error code if there was one.
] ]
@@ -89,4 +109,11 @@ In this table:
[concept_BodyWriter] [concept_BodyWriter]
[heading Models]
* [link beast.ref.beast__http__basic_dynamic_body.writer `basic_dynamic_body::writer`]
* [link beast.ref.beast__http__basic_file_body__reader `basic_file_body::writer`]
* [link beast.ref.beast__http__empty_body.writer `empty_body::writer`]
* [link beast.ref.beast__http__string_body.writer `string_body::writer`]
[endsect] [endsect]

View File

@@ -68,9 +68,14 @@ struct const_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(beast::http::message<isRequest, const_body, reader(beast::http::message<isRequest,
Fields> const& msg, beast::error_code& ec) const_body, Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{
}
void
init(beast::error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }

View File

@@ -71,9 +71,14 @@ struct mutable_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(beast::http::message<isRequest, mutable_body, reader(beast::http::message<isRequest,
Fields> const& msg, beast::error_code& ec) mutable_body, Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{
}
void
init(beast::error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
@@ -99,14 +104,19 @@ struct mutable_body
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(beast::http::message<isRequest, mutable_body, Fields>& m, writer(beast::http::message<
boost::optional<std::uint64_t> const& content_length, isRequest, mutable_body, Fields>& m)
beast::error_code& ec)
: body_(m.body) : body_(m.body)
{ {
if(content_length) }
void
init(boost::optional<
std::uint64_t> const& length, beast::error_code& ec)
{ {
if(*content_length > (std::numeric_limits< if(length)
{
if(*length > (std::numeric_limits<
std::size_t>::max)()) std::size_t>::max)())
{ {
ec = beast::http::error::buffer_overflow; ec = beast::http::error::buffer_overflow;
@@ -115,7 +125,7 @@ struct mutable_body
try try
{ {
body_.reserve(static_cast< body_.reserve(static_cast<
std::size_t>(*content_length)); std::size_t>(*length));
} }
catch(std::exception const&) catch(std::exception const&)
{ {

View File

@@ -101,9 +101,14 @@ struct buffer_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, buffer_body, reader(message<isRequest,
Fields> const& msg, error_code& ec) buffer_body, Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{
}
void
init(error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
@@ -152,10 +157,13 @@ struct buffer_body
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, buffer_body, Fields>& m, writer(message<isRequest, buffer_body, Fields>& m)
boost::optional<std::uint64_t> const&,
error_code& ec)
: body_(m.body) : body_(m.body)
{
}
void
init(boost::optional<std::uint64_t> const&, error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }

View File

@@ -55,9 +55,14 @@ struct basic_dynamic_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, basic_dynamic_body, reader(message<isRequest,
Fields> const& m, error_code& ec) basic_dynamic_body, Fields> const& m)
: body_(m.body) : body_(m.body)
{
}
void
init(error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
@@ -82,10 +87,13 @@ struct basic_dynamic_body
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, basic_dynamic_body, Fields>& msg, writer(message<isRequest, basic_dynamic_body, Fields>& msg)
boost::optional<std::uint64_t> const&,
error_code& ec)
: body_(msg.body) : body_(msg.body)
{
}
void
init(boost::optional<std::uint64_t> const&, error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }

View File

@@ -54,8 +54,13 @@ struct empty_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, empty_body, reader(message<isRequest,
Fields> const&, error_code& ec) empty_body, Fields> const&)
{
}
void
init(error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
@@ -77,9 +82,12 @@ struct empty_body
{ {
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, empty_body, Fields>&, writer(message<isRequest, empty_body, Fields>&)
boost::optional<std::uint64_t> const&, {
error_code& ec) }
void
init(boost::optional<std::uint64_t> const&, error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }

View File

@@ -235,9 +235,17 @@ public:
// always have the `file_body` as the body type. // always have the `file_body` as the body type.
// //
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
reader( reader(message<
message<isRequest, basic_file_body, Fields> const& m, isRequest, basic_file_body, Fields> const& m);
error_code& ec);
// Initializer
//
// This is called before the body is serialized and
// gives the reader a chance to do something that might
// need to return an error code.
//
void
init(error_code& ec);
// This function is called zero or more times to // This function is called zero or more times to
// retrieve buffers. A return value of `boost::none` // retrieve buffers. A return value of `boost::none`
@@ -261,18 +269,29 @@ template<class File>
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
basic_file_body<File>:: basic_file_body<File>::
reader:: reader::
reader( reader(message<isRequest, basic_file_body, Fields> const& m)
message<isRequest, basic_file_body, Fields> const& m,
error_code& ec)
: body_(m.body) : body_(m.body)
{ {
// The file must already be open // The file must already be open
BOOST_ASSERT(body_.file_.is_open()); BOOST_ASSERT(body_.file_.is_open());
// Get the size of the file // Get the size of the file
remain_ = body_.file_.size(ec); remain_ = body_.file_size_;
if(ec) }
return;
// Initializer
template<class File>
void
basic_file_body<File>::
reader::
init(error_code& ec)
{
// The error_code specification requires that we
// either set the error to some value, or set it
// to indicate no error.
//
// We don't do anything fancy so set "no error"
ec.assign(0, ec.category());
} }
// This function is called repeatedly by the serializer to // This function is called repeatedly by the serializer to
@@ -353,9 +372,18 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer( writer(
message<isRequest, basic_file_body, Fields>& m, message<isRequest, basic_file_body, Fields>& m);
boost::optional<std::uint64_t> const& content_length,
error_code& ec); // Initializer
//
// This is called before the body is parsed and
// gives the writer a chance to do something that might
// need to return an error code. It informs us of
// the payload size (`content_length`) which we can
// optionally use for optimization.
//
void
init(boost::optional<std::uint64_t> const&, error_code& ec);
// This function is called one or more times to store // This function is called one or more times to store
// buffer sequences corresponding to the incoming body. // buffer sequences corresponding to the incoming body.
@@ -387,11 +415,18 @@ template<class File>
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
basic_file_body<File>:: basic_file_body<File>::
writer:: writer::
writer( writer(message<isRequest, basic_file_body, Fields>& m)
message<isRequest, basic_file_body, Fields>& m, : body_(m.body)
{
}
template<class File>
void
basic_file_body<File>::
writer::
init(
boost::optional<std::uint64_t> const& content_length, boost::optional<std::uint64_t> const& content_length,
error_code& ec) error_code& ec)
: body_(m.body)
{ {
// The file must already be open for writing // The file must already be open for writing
BOOST_ASSERT(body_.file_.is_open()); BOOST_ASSERT(body_.file_.is_open());
@@ -401,7 +436,11 @@ writer(
// to see if there is enough room to store the body. // to see if there is enough room to store the body.
boost::ignore_unused(content_length); boost::ignore_unused(content_length);
// This is required by the error_code specification // The error_code specification requires that we
// either set the error to some value, or set it
// to indicate no error.
//
// We don't do anything fancy so set "no error"
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }

View File

@@ -14,12 +14,20 @@
namespace beast { namespace beast {
namespace http { namespace http {
template<bool isRequest, class Body, class Allocator>
parser<isRequest, Body, Allocator>::
parser()
: wr_(m_)
{
}
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)
: m_(std::forward<Arg1>(arg1), : m_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...) std::forward<ArgN>(argn)...)
, wr_(m_)
{ {
} }
@@ -30,8 +38,9 @@ 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)...)
, wr_(m_)
{ {
if(p.wr_) if(wr_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"});
} }

View File

@@ -59,6 +59,7 @@ template<bool isRequest, class Body,
serializer<isRequest, Body, Fields, ChunkDecorator>:: serializer<isRequest, Body, Fields, ChunkDecorator>::
serializer(value_type& m) serializer(value_type& m)
: m_(m) : m_(m)
, rd_(m_)
{ {
} }
@@ -67,6 +68,7 @@ template<bool isRequest, class Body,
serializer<isRequest, Body, Fields, ChunkDecorator>:: serializer<isRequest, Body, Fields, ChunkDecorator>::
serializer(value_type& m, ChunkDecorator const& d) serializer(value_type& m, ChunkDecorator const& d)
: m_(m) : m_(m)
, rd_(m_)
, d_(d) , d_(d)
{ {
} }
@@ -96,12 +98,12 @@ next(error_code& ec, Visit&& visit)
case do_init: case do_init:
{ {
if(split_) rd_.init(ec);
goto go_header_only;
rd_.emplace(m_, ec);
if(ec) if(ec)
return; return;
auto result = rd_->get(ec); if(split_)
goto go_header_only;
auto result = rd_.get(ec);
if(ec == error::need_more) if(ec == error::need_more)
goto go_header_only; goto go_header_only;
if(ec) if(ec)
@@ -129,18 +131,12 @@ next(error_code& ec, Visit&& visit)
break; break;
case do_body: case do_body:
if(! rd_)
{
rd_.emplace(m_, ec);
if(ec)
return;
}
s_ = do_body + 1; s_ = do_body + 1;
BEAST_FALLTHROUGH; BEAST_FALLTHROUGH;
case do_body + 1: case do_body + 1:
{ {
auto result = rd_->get(ec); auto result = rd_.get(ec);
if(ec) if(ec)
return; return;
if(! result) if(! result)
@@ -161,12 +157,12 @@ next(error_code& ec, Visit&& visit)
s_ = do_init_c; s_ = do_init_c;
case do_init_c: case do_init_c:
{ {
if(split_) rd_.init(ec);
goto go_header_only_c;
rd_.emplace(m_, ec);
if(ec) if(ec)
return; return;
auto result = rd_->get(ec); if(split_)
goto go_header_only_c;
auto result = rd_.get(ec);
if(ec == error::need_more) if(ec == error::need_more)
goto go_header_only_c; goto go_header_only_c;
if(ec) if(ec)
@@ -237,18 +233,12 @@ next(error_code& ec, Visit&& visit)
break; break;
case do_body_c: case do_body_c:
if(! rd_)
{
rd_.emplace(m_, ec);
if(ec)
return;
}
s_ = do_body_c + 1; s_ = do_body_c + 1;
BEAST_FALLTHROUGH; BEAST_FALLTHROUGH;
case do_body_c + 1: case do_body_c + 1:
{ {
auto result = rd_->get(ec); auto result = rd_.get(ec);
if(ec) if(ec)
return; return;
if(! result) if(! result)

View File

@@ -60,21 +60,17 @@ class parser
parser<isRequest, Body, Allocator>>; parser<isRequest, Body, Allocator>>;
message<isRequest, Body, basic_fields<Allocator>> m_; message<isRequest, Body, basic_fields<Allocator>> m_;
boost::optional<typename Body::writer> wr_; typename Body::writer wr_;
std::function<void(parser&, error_code&)> cb_; std::function<void(parser&, error_code&)> cb_;
bool wr_inited_ = false;
public: public:
/// The type of message returned by the parser /// The type of message returned by the parser
using value_type = using value_type =
message<isRequest, Body, basic_fields<Allocator>>; message<isRequest, Body, basic_fields<Allocator>>;
/// Constructor (default) /// Constructor
parser() parser();
{
// avoid `parser()=default` otherwise value-init
// for members can happen (i.e. a big memset on
// static_buffer_n).
}
/// Copy constructor (disallowed) /// Copy constructor (disallowed)
parser(parser const&) = delete; parser(parser const&) = delete;
@@ -285,13 +281,14 @@ private:
std::uint64_t> const& content_length, std::uint64_t> const& content_length,
error_code& ec) error_code& ec)
{ {
wr_.emplace(m_, content_length, ec); wr_.init(content_length, ec);
wr_inited_ = true;
} }
std::size_t std::size_t
on_data(string_view s, error_code& ec) on_data(string_view s, error_code& ec)
{ {
return wr_->put(boost::asio::buffer( return wr_.put(boost::asio::buffer(
s.data(), s.size()), ec); s.data(), s.size()), ec);
} }
@@ -305,10 +302,7 @@ private:
void void
on_complete(error_code& ec) on_complete(error_code& ec)
{ {
if(wr_) wr_.finish(ec);
wr_->finish(ec);
else
ec.assign(0, ec.category());
} }
}; };

View File

@@ -134,7 +134,7 @@ public:
static_assert(is_body_reader<Body>::value, static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met"); "BodyReader requirements not met");
/** The type of the message referenced by this object. /** The type of message this serializer uses
This may be const or non-const depending on the This may be const or non-const depending on the
implementation of the corresponding @b BodyReader. implementation of the corresponding @b BodyReader.
@@ -145,11 +145,9 @@ public:
using value_type = using value_type =
typename std::conditional< typename std::conditional<
std::is_constructible<typename Body::reader, std::is_constructible<typename Body::reader,
message<isRequest, Body, Fields>&, message<isRequest, Body, Fields>&>::value &&
error_code&>::value &&
! std::is_constructible<typename Body::reader, ! std::is_constructible<typename Body::reader,
message<isRequest, Body, Fields> const&, message<isRequest, Body, Fields> const&>::value,
error_code&>::value,
message<isRequest, Body, Fields>, message<isRequest, Body, Fields>,
message<isRequest, Body, Fields> const>::type; message<isRequest, Body, Fields> const>::type;
#endif #endif
@@ -248,8 +246,8 @@ private:
using pcb8_t = buffer_prefix_view<cb8_t const&>; using pcb8_t = buffer_prefix_view<cb8_t const&>;
value_type& m_; value_type& m_;
reader rd_;
boost::optional<typename Fields::reader> frd_; boost::optional<typename Fields::reader> frd_;
boost::optional<reader> rd_;
boost::variant<boost::blank, boost::variant<boost::blank,
cb1_t, cb2_t, cb3_t, cb4_t, cb5_t cb1_t, cb2_t, cb3_t, cb4_t, cb5_t
#ifndef BEAST_NO_BIG_VARIANTS #ifndef BEAST_NO_BIG_VARIANTS

View File

@@ -52,9 +52,14 @@ struct string_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, string_body, reader(message<isRequest,
Fields> const& msg, error_code& ec) string_body, Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{
}
void
init(error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
@@ -80,23 +85,27 @@ struct string_body
public: public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
writer(message<isRequest, string_body, Fields>& m, writer(message<isRequest, string_body, Fields>& m)
boost::optional<std::uint64_t> content_length,
error_code& ec)
: body_(m.body) : body_(m.body)
{ {
if(content_length) }
void
init(boost::optional<
std::uint64_t> const& length, error_code& ec)
{ {
if(*content_length > (std::numeric_limits< if(length)
std::size_t>::max)()) {
if(*length > (
std::numeric_limits<std::size_t>::max)())
{ {
ec = error::buffer_overflow; ec = error::buffer_overflow;
return; return;
} }
try try
{ {
body_.reserve(static_cast< body_.reserve(
std::size_t>(*content_length)); static_cast<std::size_t>(*length));
} }
catch(std::exception const&) catch(std::exception const&)
{ {

View File

@@ -53,9 +53,14 @@ struct string_view_body
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, string_view_body, reader(message<isRequest,
Fields> const& m, error_code& ec) string_view_body, Fields> const& m)
: body_(m.body) : body_(m.body)
{
}
void
init(error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }

View File

@@ -80,6 +80,7 @@ struct is_body_reader<T, beast::detail::void_t<
typename T::reader, typename T::reader,
typename T::reader::const_buffers_type, typename T::reader::const_buffers_type,
decltype( decltype(
std::declval<typename T::reader&>().init(std::declval<error_code&>()),
std::declval<boost::optional<std::pair< std::declval<boost::optional<std::pair<
typename T::reader::const_buffers_type, bool>>&>() = typename T::reader::const_buffers_type, bool>>&>() =
std::declval<typename T::reader>().get(std::declval<error_code&>()), std::declval<typename T::reader>().get(std::declval<error_code&>()),
@@ -87,11 +88,9 @@ struct is_body_reader<T, beast::detail::void_t<
is_const_buffer_sequence< is_const_buffer_sequence<
typename T::reader::const_buffers_type>::value && typename T::reader::const_buffers_type>::value &&
std::is_constructible<typename T::reader, std::is_constructible<typename T::reader,
message<true, T, detail::fields_model>&, message<true, T, detail::fields_model>&>::value &&
error_code&>::value &&
std::is_constructible<typename T::reader, std::is_constructible<typename T::reader,
message<false, T, detail::fields_model>&, message<false, T, detail::fields_model>&>::value
error_code&>::value
> {}; > {};
#endif #endif
@@ -124,6 +123,9 @@ struct is_body_writer : std::false_type {};
template<class T> template<class T>
struct is_body_writer<T, beast::detail::void_t<decltype( struct is_body_writer<T, beast::detail::void_t<decltype(
std::declval<typename T::writer&>().init(
boost::optional<std::uint64_t>(),
std::declval<error_code&>()),
std::declval<std::size_t&>() = std::declval<std::size_t&>() =
std::declval<typename T::writer&>().put( std::declval<typename T::writer&>().put(
std::declval<boost::asio::const_buffers_1>(), std::declval<boost::asio::const_buffers_1>(),
@@ -132,10 +134,10 @@ struct is_body_writer<T, beast::detail::void_t<decltype(
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::writer, std::is_constructible<typename T::writer,
message<true, T, detail::fields_model>&, message<true, T, detail::fields_model>&>::value &&
boost::optional<std::uint64_t>, std::is_constructible<typename T::writer,
error_code& message<false, T, detail::fields_model>&>::value
>::value> >
{ {
}; };
#endif #endif

View File

@@ -58,10 +58,24 @@ public:
@param ec Set to the error, if any occurred. @param ec Set to the error, if any occurred.
*/ */
template<bool isRequest, class Body, class Headers> template<bool isRequest, class Body, class Fields>
explicit explicit
BodyReader(message<isRequest, Body, Headers> const& msg, BodyReader(message<isRequest, Body, Fields> const& msg);
error_code &ec);
/** Initialize the reader
This is called after construction and before the first
call to `get`. The message is valid and complete upon
entry.
@param ec Set to the error, if any occurred.
*/
void
init(error_code& ec)
{
// The specification requires this to indicate "no error"
ec.assign(0, ec.category());
}
/** Returns the next buffer in the body. /** Returns the next buffer in the body.
@@ -85,7 +99,7 @@ public:
get(error_code& ec) get(error_code& ec)
{ {
// The specification requires this to indicate "no error" // The specification requires this to indicate "no error"
ec = {}; ec.assign(0, ec.category());
return boost::none; // for exposition only return boost::none; // for exposition only
} }
@@ -109,14 +123,25 @@ struct BodyWriter
*/ */
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Fields>
explicit explicit
BodyWriter(message<isRequest, Body, Fields>& msg, BodyWriter(message<isRequest, Body, Fields>& msg);
boost::optional<std::uint64_t> content_length,
/** Initialize the writer
This is called after construction and before the first
call to `put`. The message is valid and complete upon
entry.
@param ec Set to the error, if any occurred.
*/
void
init(
boost::optional<std::uint64_t> const& content_length,
error_code& ec) error_code& ec)
{ {
boost::ignore_unused(msg, content_length); boost::ignore_unused(content_length);
// The specification requires this to indicate "no error" // The specification requires this to indicate "no error"
ec = {}; ec.assign(0, ec.category());
} }
/** Store buffers. /** Store buffers.

View File

@@ -27,8 +27,10 @@ public:
boost::asio::const_buffers_1; boost::asio::const_buffers_1;
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
reader(message<isRequest, const_body, Fields> const&, reader(message<isRequest, const_body, Fields> const&);
error_code&);
void
init(error_code& ec);
boost::optional<std::pair<const_buffers_type, bool>> boost::optional<std::pair<const_buffers_type, bool>>
get(error_code&); get(error_code&);
@@ -45,8 +47,10 @@ public:
boost::asio::const_buffers_1; boost::asio::const_buffers_1;
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
reader(message<isRequest, mutable_body, Fields>&, reader(message<isRequest, mutable_body, Fields>&);
error_code&);
void
init(error_code& ec);
boost::optional<std::pair<const_buffers_type, bool>> boost::optional<std::pair<const_buffers_type, bool>>
get(error_code&); get(error_code&);
@@ -55,6 +59,7 @@ public:
BOOST_STATIC_ASSERT(std::is_const< serializer< BOOST_STATIC_ASSERT(std::is_const< serializer<
true, const_body>::value_type>::value); true, const_body>::value_type>::value);
BOOST_STATIC_ASSERT(! std::is_const<serializer< BOOST_STATIC_ASSERT(! std::is_const<serializer<
true, mutable_body>::value_type>::value); true, mutable_body>::value_type>::value);

View File

@@ -47,9 +47,14 @@ public:
template<bool isRequest, class Allocator> template<bool isRequest, class Allocator>
explicit explicit
reader(message<isRequest, unsized_body, reader(message<isRequest,
Allocator> const& msg, error_code &ec) unsized_body, Allocator> const& msg)
: body_(msg.body) : body_(msg.body)
{
}
void
init(error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
@@ -87,9 +92,14 @@ public:
template<bool isRequest, class Fields> template<bool isRequest, class Fields>
explicit explicit
reader(message<isRequest, test_body, reader(message<isRequest,
Fields> const& msg, error_code& ec) test_body, Fields> const& msg)
: body_(msg.body) : body_(msg.body)
{
}
void
init(error_code& ec)
{ {
ec.assign(0, ec.category()); ec.assign(0, ec.category());
} }
@@ -219,9 +229,14 @@ public:
template<bool isRequest, class Allocator> template<bool isRequest, class Allocator>
explicit explicit
reader(message<isRequest, fail_body, reader(message<isRequest,
Allocator> const& msg, error_code& ec) fail_body, Allocator> const& msg)
: body_(msg.body) : body_(msg.body)
{
}
void
init(error_code& ec)
{ {
body_.fc_.fail(ec); body_.fc_.fail(ec);
} }