Refactor header and message constructors:

fix #581

* request and response headers now have convenience
  constructors so important fields like method, target,
  result, and version may be set upon construction.

Actions Required:

* Evaluate each message constructor call site and
  adjust the constructor argument list as needed.
This commit is contained in:
Vinnie Falco
2017-07-20 08:15:29 -07:00
parent 2ee088de5f
commit b0e52dd246
11 changed files with 487 additions and 210 deletions
+115 -17
View File
@@ -111,6 +111,19 @@ header(Arg1&& arg1, ArgN&&... argn)
std::forward<ArgN>(argn)...)
{
}
#if 0
template<class Fields>
template<class... Args>
header<false, Fields>::
header(status result, unsigned version_, Args&&... args)
: Fields(std::forward<Args>(args)...)
, version(version_)
, result_(result)
{
}
#endif
template<class Fields>
inline
status
@@ -189,23 +202,118 @@ swap(
//------------------------------------------------------------------------------
template<bool isRequest, class Body, class Fields>
template<class... Args>
template<class... BodyArgs>
message<isRequest, Body, Fields>::
message(header_type&& h, Args&&... args)
message(header_type&& h, BodyArgs&&... body_args)
: header_type(std::move(h))
, body(std::forward<Args>(args)...)
, body(std::forward<BodyArgs>(body_args)...)
{
}
template<bool isRequest, class Body, class Fields>
template<class... Args>
template<class... BodyArgs>
message<isRequest, Body, Fields>::
message(header_type const& h, Args&&... args)
message(header_type const& h, BodyArgs&&... body_args)
: header_type(h)
, body(std::forward<Args>(args)...)
, body(std::forward<BodyArgs>(body_args)...)
{
}
template<bool isRequest, class Body, class Fields>
template<class Version, class>
message<isRequest, Body, Fields>::
message(verb method, string_view target, Version version)
: header_type(method, target, version)
{
}
template<bool isRequest, class Body, class Fields>
template<class Version, class BodyArg, class>
message<isRequest, Body, Fields>::
message(verb method, string_view target,
Version version, BodyArg&& body_arg)
: header_type(method, target, version)
, body(std::forward<BodyArg>(body_arg))
{
}
template<bool isRequest, class Body, class Fields>
template<class Version, class BodyArg, class FieldsArg, class>
message<isRequest, Body, Fields>::
message(
verb method, string_view target, Version version,
BodyArg&& body_arg,
FieldsArg&& fields_arg)
: header_type(method, target, version,
std::forward<FieldsArg>(fields_arg))
, body(std::forward<BodyArg>(body_arg))
{
}
template<bool isRequest, class Body, class Fields>
template<class Version, class>
message<isRequest, Body, Fields>::
message(status result, Version version)
: header_type(result, version)
{
}
template<bool isRequest, class Body, class Fields>
template<class Version, class BodyArg, class>
message<isRequest, Body, Fields>::
message(status result, Version version,
BodyArg&& body_arg)
: header_type(result, version)
, body(std::forward<BodyArg>(body_arg))
{
}
template<bool isRequest, class Body, class Fields>
template<class Version, class BodyArg, class FieldsArg, class>
message<isRequest, Body, Fields>::
message(status result, Version version,
BodyArg&& body_arg, FieldsArg&& fields_arg)
: header_type(result, version,
std::forward<FieldsArg>(fields_arg))
, body(std::forward<BodyArg>(body_arg))
{
}
template<bool isRequest, class Body, class Fields>
message<isRequest, Body, Fields>::
message(std::piecewise_construct_t)
{
}
template<bool isRequest, class Body, class Fields>
template<class... BodyArgs>
message<isRequest, Body, Fields>::
message(std::piecewise_construct_t,
std::tuple<BodyArgs...> body_args)
: message(std::piecewise_construct,
body_args,
beast::detail::make_index_sequence<
sizeof...(BodyArgs)>{})
{
}
template<bool isRequest, class Body, class Fields>
template<class... BodyArgs, class... FieldsArgs>
message<isRequest, Body, Fields>::
message(std::piecewise_construct_t,
std::tuple<BodyArgs...> body_args,
std::tuple<FieldsArgs...> fields_args)
: message(std::piecewise_construct,
body_args,
fields_args,
beast::detail::make_index_sequence<
sizeof...(BodyArgs)>{},
beast::detail::make_index_sequence<
sizeof...(FieldsArgs)>{})
{
}
#if 0
template<bool isRequest, class Body, class Fields>
template<class BodyArg, class>
message<isRequest, Body, Fields>::
@@ -223,17 +331,6 @@ message(BodyArg&& body_arg, HeaderArg&& header_arg)
{
}
template<bool isRequest, class Body, class Fields>
template<class... BodyArgs>
message<isRequest, Body, Fields>::
message(std::piecewise_construct_t,
std::tuple<BodyArgs...> body_args)
: message(std::piecewise_construct, body_args,
beast::detail::make_index_sequence<
sizeof...(BodyArgs)>{})
{
}
template<bool isRequest, class Body, class Fields>
template<class... BodyArgs, class... HeaderArgs>
message<isRequest, Body, Fields>::
@@ -248,6 +345,7 @@ message(std::piecewise_construct_t,
sizeof...(HeaderArgs)>{})
{
}
#endif
template<bool isRequest, class Body, class Fields>
boost::optional<std::uint64_t>
+199 -70
View File
@@ -158,8 +158,8 @@ struct header<true, Fields> : Fields
void
target(string_view s);
// VFALCO Don't move these declarations around,
// otherwise the documentation will be wrong.
// VFALCO Don't rearrange these declarations or
// ifdefs, or else the documentation will break.
/** Constructor
@@ -168,7 +168,8 @@ struct header<true, Fields> : Fields
@note This constructor participates in overload
resolution if and only if the first parameter is
not convertible to @ref header.
not convertible to @ref header, @ref verb, or
@ref status.
*/
#if BEAST_DOXYGEN
template<class... Args>
@@ -178,9 +179,13 @@ struct header<true, Fields> : Fields
#else
template<class Arg1, class... ArgN,
class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type,
header>::value>::type>
! std::is_convertible<typename
std::decay<Arg1>::type, header>::value &&
! std::is_convertible<typename
std::decay<Arg1>::type, verb>::value &&
! std::is_convertible<typename
std::decay<Arg1>::type, header>::value
>::type>
explicit
header(Arg1&& arg1, ArgN&&... argn);
@@ -193,6 +198,19 @@ private:
void
swap(header<true, T>& m1, header<true, T>& m2);
template<class... FieldsArgs>
header(
verb method,
string_view target_,
unsigned version_,
FieldsArgs&&... fields_args)
: Fields(std::forward<FieldsArgs>(fields_args)...)
, version(version_)
, method_(method)
{
target(target_);
}
verb method_ = verb::unknown;
};
@@ -207,11 +225,7 @@ struct header<false, Fields> : Fields
"Fields requirements not met");
/// Indicates if the header is a request or response.
#if BEAST_DOXYGEN
using is_request = std::integral_constant<bool, isRequest>;
#else
using is_request = std::false_type;
#endif
/// The type representing the fields.
using fields_type = Fields;
@@ -225,7 +239,8 @@ struct header<false, Fields> : Fields
unsigned minor = version % 10;
@endcode
Newly constructed headers will use HTTP/1.1 by default.
Newly constructed headers will use HTTP/1.1 by default
unless otherwise specified.
*/
unsigned version = 11;
@@ -251,13 +266,16 @@ struct header<false, Fields> : Fields
@note This constructor participates in overload
resolution if and only if the first parameter is
not convertible to @ref header.
not convertible to @ref header, @ref verb, or
@ref status.
*/
template<class Arg1, class... ArgN,
class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type,
header>::value>::type>
! std::is_convertible<typename
std::decay<Arg1>::type, status>::value &&
! std::is_convertible<typename
std::decay<Arg1>::type, header>::value
>::type>
explicit
header(Arg1&& arg1, ArgN&&... argn);
#endif
@@ -347,6 +365,17 @@ private:
void
swap(header<false, T>& m1, header<false, T>& m2);
template<class... FieldsArgs>
header(
status result,
unsigned version_,
FieldsArgs&&... fields_args)
: Fields(std::forward<FieldsArgs>(fields_args)...)
, version(version_)
, result_(result)
{
}
status result_ = status::ok;
#endif
};
@@ -403,82 +432,184 @@ struct message : header<isRequest, Fields>
/// A value representing the body.
typename Body::value_type body;
/// Default constructor
/// Constructor
message() = default;
/// Move constructor
/// Constructor
message(message&&) = default;
/// Copy constructor
/// Constructor
message(message const&) = default;
/// Move assignment
/// Assignment
message& operator=(message&&) = default;
/// Copy assignment
/// Assignment
message& operator=(message const&) = default;
/** Constructor.
/** Constructor
@param h The header to move construct from.
@param args Optional arguments forwarded
to the body constructor.
@param body_args Optional arguments forwarded
to the `body` constructor.
*/
template<class... Args>
template<class... BodyArgs>
explicit
message(header_type&& h, Args&&... args);
message(header_type&& h, BodyArgs&&... body_args);
/** Constructor.
@param h The header to copy construct from.
@param args Optional arguments forwarded
to the body constructor.
@param body_args Optional arguments forwarded
to the `body` constructor.
*/
template<class... Args>
template<class... BodyArgs>
explicit
message(header_type const& h, Args&&... args);
message(header_type const& h, BodyArgs&&... body_args);
/** Construct a message.
/** Constructor
@param body_arg An argument forwarded to the body constructor.
@param method The request-method to use
@note This constructor participates in overload resolution
only if `body_arg` is not convertible to `header_type`.
@param target The request-target.
@param version The HTTP-version
@note This function is only available when `isRequest == true`.
*/
template<class BodyArg
#if ! BEAST_DOXYGEN
, class = typename std::enable_if<
! std::is_convertible<typename
std::decay<BodyArg>::type, header_type>::value>::type
#if BEAST_DOXYGEN
message(verb method, string_view target, unsigned version);
#else
template<class Version,
class = typename std::enable_if<isRequest &&
std::is_convertible<Version, unsigned>::value>::type>
message(verb method, string_view target, Version version);
#endif
>
/** Constructor
@param method The request-method to use
@param target The request-target.
@param version The HTTP-version
@param body_arg An argument forwarded to the `body` constructor.
@note This function is only available when `isRequest == true`.
*/
#if BEAST_DOXYGEN
template<class BodyArg>
message(verb method, string_view target,
unsigned version, BodyArg&& body_arg);
#else
template<class Version, class BodyArg,
class = typename std::enable_if<isRequest &&
std::is_convertible<Version, unsigned>::value>::type>
message(verb method, string_view target,
Version version, BodyArg&& body_arg);
#endif
/** Constructor
@param method The request-method to use
@param target The request-target.
@param version The HTTP-version
@param body_arg An argument forwarded to the `body` constructor.
@param fields_arg An argument forwarded to the `Fields` constructor.
@note This function is only available when `isRequest == true`.
*/
#if BEAST_DOXYGEN
template<class BodyArg, class FieldsArg>
message(verb method, string_view target, unsigned version,
BodyArg&& body_arg, FieldsArg&& fields_arg);
#else
template<class Version, class BodyArg, class FieldsArg,
class = typename std::enable_if<isRequest &&
std::is_convertible<Version, unsigned>::value>::type>
message(verb method, string_view target, Version version,
BodyArg&& body_arg, FieldsArg&& fields_arg);
#endif
/** Constructor
@param result The status-code for the response
@param version The HTTP-version
@note This member is only available when `isRequest == false`.
*/
#if BEAST_DOXYGEN
message(status result, unsigned version);
#else
template<class Version,
class = typename std::enable_if<! isRequest &&
std::is_convertible<Version, unsigned>::value>::type>
message(status result, Version version);
#endif
/** Constructor
@param result The status-code for the response
@param version The HTTP-version
@param body_arg An argument forwarded to the `body` constructor.
@note This member is only available when `isRequest == false`.
*/
#if BEAST_DOXYGEN
template<class BodyArg>
message(status result, unsigned version, BodyArg&& body_arg);
#else
template<class Version, class BodyArg,
class = typename std::enable_if<! isRequest &&
std::is_convertible<Version, unsigned>::value>::type>
message(status result, Version version, BodyArg&& body_arg);
#endif
/** Constructor
@param result The status-code for the response
@param version The HTTP-version
@param body_arg An argument forwarded to the `body` constructor.
@param fields_arg An argument forwarded to the `Fields` base class constructor.
@note This member is only available when `isRequest == false`.
*/
#if BEAST_DOXYGEN
template<class BodyArg, class FieldsArg>
message(status result, unsigned version,
BodyArg&& body_arg, FieldsArg&& fields_arg);
#else
template<class Version, class BodyArg, class FieldsArg,
class = typename std::enable_if<! isRequest &&
std::is_convertible<Version, unsigned>::value>::type>
message(status result, Version version,
BodyArg&& body_arg, FieldsArg&& fields_arg);
#endif
/** Constructor
The header and body are default-constructed.
*/
explicit
message(BodyArg&& body_arg);
message(std::piecewise_construct_t);
/** Construct a message.
@param body_arg An argument forwarded to the body constructor.
@param header_arg An argument forwarded to the header constructor.
@note This constructor participates in overload resolution
only if `body_arg` is not convertible to `header_type`.
*/
template<class BodyArg, class HeaderArg
#if ! BEAST_DOXYGEN
,class = typename std::enable_if<
! std::is_convertible<
typename std::decay<BodyArg>::type,
header_type>::value>::type
#endif
>
message(BodyArg&& body_arg, HeaderArg&& header_arg);
/** Construct a message.
@param body_args A tuple forwarded as a parameter pack to the body constructor.
@param body_args A tuple forwarded as a parameter
pack to the body constructor.
*/
template<class... BodyArgs>
message(std::piecewise_construct_t,
@@ -486,14 +617,16 @@ struct message : header<isRequest, Fields>
/** Construct a message.
@param body_args A tuple forwarded as a parameter pack to the body constructor.
@param body_args A tuple forwarded as a parameter
pack to the body constructor.
@param header_args A tuple forwarded as a parameter pack to the fields constructor.
@param fields_args A tuple forwarded as a parameter
pack to the `Fields` constructor.
*/
template<class... BodyArgs, class... HeaderArgs>
template<class... BodyArgs, class... FieldsArgs>
message(std::piecewise_construct_t,
std::tuple<BodyArgs...>&& body_args,
std::tuple<HeaderArgs...>&& header_args);
std::tuple<BodyArgs...> body_args,
std::tuple<FieldsArgs...> fields_args);
/// Returns the header portion of the message
header_type const&
@@ -524,7 +657,6 @@ struct message : header<isRequest, Fields>
boost::optional<std::uint64_t>
payload_size() const;
/** Prepare the message payload fields for the body.
This function will adjust the Content-Length and
@@ -533,10 +665,7 @@ struct message : header<isRequest, Fields>
@par Example
@code
request<string_body> req;
req.version = 11;
req.method(verb::upgrade);
req.target("/");
request<string_body> req{verb::post, "/"};
req.set(field::user_agent, "Beast");
req.body = "Hello, world!";
req.prepare_payload();