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-03 20:33:54 -07:00
parent 2ee088de5f
commit b0e52dd246
11 changed files with 487 additions and 210 deletions

View File

@@ -5,6 +5,15 @@ HTTP:
* basic_parser optimizations * basic_parser optimizations
* Add basic_parser tests * Add basic_parser tests
API Changes:
* Refactor header and message constructors
Actions Required:
* Evaluate each message constructor call site and
adjust the constructor argument list as needed.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
Version 72: Version 72:

View File

@@ -48,10 +48,7 @@ int main()
return fail("connect", ec); return fail("connect", ec);
// Set up an HTTP GET request message // Set up an HTTP GET request message
http::request<http::string_body> req; http::request<http::string_body> req{http::verb::get, "/", 11};
req.method(http::verb::get);
req.target("/");
req.version = 11;
req.set(http::field::host, host + ":" + req.set(http::field::host, host + ":" +
std::to_string(sock.remote_endpoint().port())); std::to_string(sock.remote_endpoint().port()));
req.set(http::field::user_agent, BEAST_VERSION_STRING); req.set(http::field::user_agent, BEAST_VERSION_STRING);

View File

@@ -75,10 +75,7 @@ main(int, char const*[])
} }
// Set up an HTTP GET request // Set up an HTTP GET request
http::request<http::string_body> req; http::request<http::string_body> req{http::verb::get, "/", 11};
req.version = 11;
req.method(http::verb::get);
req.target("/");
req.set(http::field::host, host + std::string(":") + std::to_string(ep.port())); req.set(http::field::host, host + std::string(":") + std::to_string(ep.port()));
req.set(http::field::user_agent, BEAST_VERSION_STRING); req.set(http::field::user_agent, BEAST_VERSION_STRING);

View File

@@ -60,8 +60,7 @@ private:
http::response<http::string_view_body> http::response<http::string_view_body>
client_error(http::status result, beast::string_view text) client_error(http::status result, beast::string_view text)
{ {
http::response<http::string_view_body> res; http::response<http::string_view_body> res{result, 11};
res.result(result);
res.set(http::field::server, BEAST_VERSION_STRING); res.set(http::field::server, BEAST_VERSION_STRING);
res.set(http::field::content_type, "text/plain"); res.set(http::field::content_type, "text/plain");
res.set(http::field::connection, "close"); res.set(http::field::connection, "close");
@@ -75,8 +74,7 @@ private:
beast::http::response<beast::http::string_body> beast::http::response<beast::http::string_body>
not_found() const not_found() const
{ {
beast::http::response<beast::http::string_body> res; beast::http::response<beast::http::string_body> res{beast::http::status::not_found, 11};
res.result(beast::http::status::not_found);
res.set(beast::http::field::server, BEAST_VERSION_STRING); res.set(beast::http::field::server, BEAST_VERSION_STRING);
res.set(beast::http::field::content_type, "text/html"); res.set(beast::http::field::content_type, "text/html");
res.set(http::field::connection, "close"); res.set(http::field::connection, "close");
@@ -90,8 +88,7 @@ private:
beast::http::response<beast::http::string_body> beast::http::response<beast::http::string_body>
server_error(beast::error_code const& ec) const server_error(beast::error_code const& ec) const
{ {
beast::http::response<beast::http::string_body> res; beast::http::response<beast::http::string_body> res{beast::http::status::internal_server_error, 11};
res.result(beast::http::status::internal_server_error);
res.set(beast::http::field::server, BEAST_VERSION_STRING); res.set(beast::http::field::server, BEAST_VERSION_STRING);
res.set(beast::http::field::content_type, "text/html"); res.set(beast::http::field::content_type, "text/html");
res.set(http::field::connection, "close"); res.set(http::field::connection, "close");

View File

@@ -264,7 +264,7 @@ protected:
// We construct the dynamic body with a 1MB limit // We construct the dynamic body with a 1MB limit
// to prevent vulnerability to buffer attacks. // to prevent vulnerability to buffer attacks.
// //
parser_.emplace(1024 * 1024); parser_.emplace(std::piecewise_construct, std::make_tuple(1024 * 1024));
// Read just the header // Read just the header
beast::http::async_read_header( beast::http::async_read_header(

View File

@@ -188,7 +188,8 @@ private:
// We construct the dynamic body with a 1MB limit // We construct the dynamic body with a 1MB limit
// to prevent vulnerability to buffer attacks. // to prevent vulnerability to buffer attacks.
// //
beast::http::request_parser<beast::http::dynamic_body> parser(1024* 1024); beast::http::request_parser<beast::http::dynamic_body> parser(
std::piecewise_construct, std::make_tuple(1024* 1024));
// Read the header first // Read the header first
beast::http::read_header(impl().stream(), buffer_, parser, ec); beast::http::read_header(impl().stream(), buffer_, parser, ec);

View File

@@ -111,6 +111,19 @@ header(Arg1&& arg1, ArgN&&... argn)
std::forward<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> template<class Fields>
inline inline
status status
@@ -189,23 +202,118 @@ swap(
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Fields>
template<class... Args> template<class... BodyArgs>
message<isRequest, Body, Fields>:: message<isRequest, Body, Fields>::
message(header_type&& h, Args&&... args) message(header_type&& h, BodyArgs&&... body_args)
: header_type(std::move(h)) : header_type(std::move(h))
, body(std::forward<Args>(args)...) , body(std::forward<BodyArgs>(body_args)...)
{ {
} }
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Fields>
template<class... Args> template<class... BodyArgs>
message<isRequest, Body, Fields>:: message<isRequest, Body, Fields>::
message(header_type const& h, Args&&... args) message(header_type const& h, BodyArgs&&... body_args)
: header_type(h) : 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<bool isRequest, class Body, class Fields>
template<class BodyArg, class> template<class BodyArg, class>
message<isRequest, Body, Fields>:: 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<bool isRequest, class Body, class Fields>
template<class... BodyArgs, class... HeaderArgs> template<class... BodyArgs, class... HeaderArgs>
message<isRequest, Body, Fields>:: message<isRequest, Body, Fields>::
@@ -248,6 +345,7 @@ message(std::piecewise_construct_t,
sizeof...(HeaderArgs)>{}) sizeof...(HeaderArgs)>{})
{ {
} }
#endif
template<bool isRequest, class Body, class Fields> template<bool isRequest, class Body, class Fields>
boost::optional<std::uint64_t> boost::optional<std::uint64_t>

View File

@@ -158,8 +158,8 @@ struct header<true, Fields> : Fields
void void
target(string_view s); target(string_view s);
// VFALCO Don't move these declarations around, // VFALCO Don't rearrange these declarations or
// otherwise the documentation will be wrong. // ifdefs, or else the documentation will break.
/** Constructor /** Constructor
@@ -168,7 +168,8 @@ struct header<true, Fields> : Fields
@note This constructor participates in overload @note This constructor participates in overload
resolution if and only if the first parameter is 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 #if BEAST_DOXYGEN
template<class... Args> template<class... Args>
@@ -178,9 +179,13 @@ struct header<true, Fields> : Fields
#else #else
template<class Arg1, class... ArgN, template<class Arg1, class... ArgN,
class = typename std::enable_if< class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible< ! std::is_convertible<typename
typename std::decay<Arg1>::type, std::decay<Arg1>::type, header>::value &&
header>::value>::type> ! std::is_convertible<typename
std::decay<Arg1>::type, verb>::value &&
! std::is_convertible<typename
std::decay<Arg1>::type, header>::value
>::type>
explicit explicit
header(Arg1&& arg1, ArgN&&... argn); header(Arg1&& arg1, ArgN&&... argn);
@@ -193,6 +198,19 @@ private:
void void
swap(header<true, T>& m1, header<true, T>& m2); 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; verb method_ = verb::unknown;
}; };
@@ -207,11 +225,7 @@ struct header<false, Fields> : Fields
"Fields requirements not met"); "Fields requirements not met");
/// Indicates if the header is a request or response. /// 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; using is_request = std::false_type;
#endif
/// The type representing the fields. /// The type representing the fields.
using fields_type = Fields; using fields_type = Fields;
@@ -225,7 +239,8 @@ struct header<false, Fields> : Fields
unsigned minor = version % 10; unsigned minor = version % 10;
@endcode @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; unsigned version = 11;
@@ -251,13 +266,16 @@ struct header<false, Fields> : Fields
@note This constructor participates in overload @note This constructor participates in overload
resolution if and only if the first parameter is 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, template<class Arg1, class... ArgN,
class = typename std::enable_if< class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible< ! std::is_convertible<typename
typename std::decay<Arg1>::type, std::decay<Arg1>::type, status>::value &&
header>::value>::type> ! std::is_convertible<typename
std::decay<Arg1>::type, header>::value
>::type>
explicit explicit
header(Arg1&& arg1, ArgN&&... argn); header(Arg1&& arg1, ArgN&&... argn);
#endif #endif
@@ -347,6 +365,17 @@ private:
void void
swap(header<false, T>& m1, header<false, T>& m2); 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; status result_ = status::ok;
#endif #endif
}; };
@@ -403,82 +432,184 @@ struct message : header<isRequest, Fields>
/// A value representing the body. /// A value representing the body.
typename Body::value_type body; typename Body::value_type body;
/// Default constructor /// Constructor
message() = default; message() = default;
/// Move constructor /// Constructor
message(message&&) = default; message(message&&) = default;
/// Copy constructor /// Constructor
message(message const&) = default; message(message const&) = default;
/// Move assignment /// Assignment
message& operator=(message&&) = default; message& operator=(message&&) = default;
/// Copy assignment /// Assignment
message& operator=(message const&) = default; message& operator=(message const&) = default;
/** Constructor. /** Constructor
@param h The header to move construct from. @param h The header to move construct from.
@param args Optional arguments forwarded @param body_args Optional arguments forwarded
to the body constructor. to the `body` constructor.
*/ */
template<class... Args> template<class... BodyArgs>
explicit explicit
message(header_type&& h, Args&&... args); message(header_type&& h, BodyArgs&&... body_args);
/** Constructor. /** Constructor.
@param h The header to copy construct from. @param h The header to copy construct from.
@param args Optional arguments forwarded @param body_args Optional arguments forwarded
to the body constructor. to the `body` constructor.
*/ */
template<class... Args> template<class... BodyArgs>
explicit 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 @param target The request-target.
only if `body_arg` is not convertible to `header_type`.
@param version The HTTP-version
@note This function is only available when `isRequest == true`.
*/ */
template<class BodyArg #if BEAST_DOXYGEN
#if ! BEAST_DOXYGEN message(verb method, string_view target, unsigned version);
, class = typename std::enable_if< #else
! std::is_convertible<typename template<class Version,
std::decay<BodyArg>::type, header_type>::value>::type class = typename std::enable_if<isRequest &&
std::is_convertible<Version, unsigned>::value>::type>
message(verb method, string_view target, Version version);
#endif #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 explicit
message(BodyArg&& body_arg); message(std::piecewise_construct_t);
/** Construct a message. /** Construct a message.
@param body_arg An argument forwarded to the body constructor. @param body_args A tuple forwarded as a parameter
pack 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.
*/ */
template<class... BodyArgs> template<class... BodyArgs>
message(std::piecewise_construct_t, message(std::piecewise_construct_t,
@@ -486,14 +617,16 @@ struct message : header<isRequest, Fields>
/** Construct a message. /** 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, message(std::piecewise_construct_t,
std::tuple<BodyArgs...>&& body_args, std::tuple<BodyArgs...> body_args,
std::tuple<HeaderArgs...>&& header_args); std::tuple<FieldsArgs...> fields_args);
/// Returns the header portion of the message /// Returns the header portion of the message
header_type const& header_type const&
@@ -524,7 +657,6 @@ struct message : header<isRequest, Fields>
boost::optional<std::uint64_t> boost::optional<std::uint64_t>
payload_size() const; payload_size() const;
/** Prepare the message payload fields for the body. /** Prepare the message payload fields for the body.
This function will adjust the Content-Length and This function will adjust the Content-Length and
@@ -533,10 +665,7 @@ struct message : header<isRequest, Fields>
@par Example @par Example
@code @code
request<string_body> req; request<string_body> req{verb::post, "/"};
req.version = 11;
req.method(verb::upgrade);
req.target("/");
req.set(field::user_agent, "Beast"); req.set(field::user_agent, "Beast");
req.body = "Hello, world!"; req.body = "Hello, world!";
req.prepare_payload(); req.prepare_payload();

View File

@@ -8,6 +8,7 @@
// Test that header file is self-contained. // Test that header file is self-contained.
#include <beast/http/message.hpp> #include <beast/http/message.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/string_body.hpp> #include <beast/http/string_body.hpp>
#include <beast/http/fields.hpp> #include <beast/http/fields.hpp>
#include <beast/http/string_body.hpp> #include <beast/http/string_body.hpp>
@@ -70,62 +71,78 @@ public:
}; };
}; };
// 0-arg
BOOST_STATIC_ASSERT(std::is_constructible<
request<default_body>>::value);
// 1-arg
BOOST_STATIC_ASSERT(! std::is_constructible<request<one_arg_body>
>::value);
//BOOST_STATIC_ASSERT(! std::is_constructible<request<one_arg_body>,
// verb, string_view, unsigned>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1&&>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1 const>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1 const&>::value);
// 1-arg + fields
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>,
verb, string_view, unsigned, Arg1, fields::allocator_type>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<one_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>, std::tuple<fields::allocator_type>>::value);
// special members
BOOST_STATIC_ASSERT(std::is_copy_constructible<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_move_constructible<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_copy_assignable<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_move_assignable<header<true>>::value);
BOOST_STATIC_ASSERT(std::is_copy_constructible<header<false>>::value);
BOOST_STATIC_ASSERT(std::is_move_constructible<header<false>>::value);
BOOST_STATIC_ASSERT(std::is_copy_assignable<header<false>>::value);
BOOST_STATIC_ASSERT(std::is_move_assignable<header<false>>::value);
void void
testMessage() testMessage()
{ {
BOOST_STATIC_ASSERT(std::is_constructible<
request<default_body>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<one_arg_body>, Arg1>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<one_arg_body>, Arg1 const>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<one_arg_body>, Arg1 const&>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<one_arg_body>, Arg1&&>::value);
BOOST_STATIC_ASSERT(! std::is_constructible<
request<one_arg_body>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<one_arg_body>,
Arg1, fields::allocator_type>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<one_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>>::value);
BOOST_STATIC_ASSERT(std::is_constructible<
request<two_arg_body>, std::piecewise_construct_t,
std::tuple<Arg1, Arg2>, std::tuple<fields::allocator_type>>::value);
{ {
Arg1 arg1; Arg1 arg1;
request<one_arg_body>{std::move(arg1)}; request<one_arg_body>{verb::get, "/", 11, std::move(arg1)};
BEAST_EXPECT(arg1.moved); BEAST_EXPECT(arg1.moved);
} }
{ {
header<true> h; header<true> h;
h.insert(field::user_agent, "test"); h.set(field::user_agent, "test");
request<one_arg_body> m{Arg1{}, h}; BEAST_EXPECT(h[field::user_agent] == "test");
BEAST_EXPECT(h["User-Agent"] == "test"); request<default_body> m{std::move(h)};
BEAST_EXPECT(m["User-Agent"] == "test"); BEAST_EXPECT(m[field::user_agent] == "test");
BEAST_EXPECT(h.count(field::user_agent) == 0);
} }
{ {
header<true> h; request<empty_body> h{verb::get, "/", 10};
h.insert(field::user_agent, "test"); h.set(field::user_agent, "test");
request<one_arg_body> m{Arg1{}, std::move(h)}; request<one_arg_body> m{std::move(h.base()), Arg1{}};
BEAST_EXPECT(! h.count(http::field::user_agent));
BEAST_EXPECT(m["User-Agent"] == "test"); BEAST_EXPECT(m["User-Agent"] == "test");
BEAST_EXPECT(h.count(http::field::user_agent) == 0);
BEAST_EXPECT(m.method() == verb::get);
BEAST_EXPECT(m.target() == "/");
BEAST_EXPECT(m.version == 10);
} }
// swap // swap
@@ -166,31 +183,79 @@ public:
} }
}; };
struct token {};
struct test_fields
{
std::string target;
test_fields() = delete;
test_fields(token) {}
void set_method_impl(string_view) {}
void set_target_impl(string_view s) { target = s.to_string(); }
void set_reason_impl(string_view) {}
string_view get_method_impl() const { return {}; }
string_view get_target_impl() const { return target; }
string_view get_reason_impl() const { return {}; }
void prepare_payload_impl(bool, boost::optional<std::uint64_t>) {}
};
void void
testHeaders() testMessageCtors()
{ {
{ {
using req_type = header<true>; request<empty_body> req;
BOOST_STATIC_ASSERT(std::is_copy_constructible<req_type>::value); BEAST_EXPECT(req.version == 11);
BOOST_STATIC_ASSERT(std::is_move_constructible<req_type>::value); BEAST_EXPECT(req.method() == verb::unknown);
BOOST_STATIC_ASSERT(std::is_copy_assignable<req_type>::value); BEAST_EXPECT(req.target() == "");
BOOST_STATIC_ASSERT(std::is_move_assignable<req_type>::value);
using res_type = header<false>;
BOOST_STATIC_ASSERT(std::is_copy_constructible<res_type>::value);
BOOST_STATIC_ASSERT(std::is_move_constructible<res_type>::value);
BOOST_STATIC_ASSERT(std::is_copy_assignable<res_type>::value);
BOOST_STATIC_ASSERT(std::is_move_assignable<res_type>::value);
} }
{ {
MoveFields h; request<empty_body> req{verb::get, "/", 11};
header<true, MoveFields> r{std::move(h)}; BEAST_EXPECT(req.version == 11);
BEAST_EXPECT(h.moved_from); BEAST_EXPECT(req.method() == verb::get);
BEAST_EXPECT(r.moved_to); BEAST_EXPECT(req.target() == "/");
request<string_body, MoveFields> m{std::move(r)}; }
BEAST_EXPECT(r.moved_from); {
BEAST_EXPECT(m.moved_to); request<string_body> req{verb::get, "/", 11, "Hello"};
BEAST_EXPECT(req.version == 11);
BEAST_EXPECT(req.method() == verb::get);
BEAST_EXPECT(req.target() == "/");
BEAST_EXPECT(req.body == "Hello");
}
{
request<string_body, test_fields> req{
verb::get, "/", 11, "Hello", token{}};
BEAST_EXPECT(req.version == 11);
BEAST_EXPECT(req.method() == verb::get);
BEAST_EXPECT(req.target() == "/");
BEAST_EXPECT(req.body == "Hello");
}
{
response<string_body> res;
BEAST_EXPECT(res.version == 11);
BEAST_EXPECT(res.result() == status::ok);
BEAST_EXPECT(res.reason() == "OK");
}
{
response<string_body> res{status::bad_request, 10};
BEAST_EXPECT(res.version == 10);
BEAST_EXPECT(res.result() == status::bad_request);
BEAST_EXPECT(res.reason() == "Bad Request");
}
{
response<string_body> res{status::bad_request, 10, "Hello"};
BEAST_EXPECT(res.version == 10);
BEAST_EXPECT(res.result() == status::bad_request);
BEAST_EXPECT(res.reason() == "Bad Request");
BEAST_EXPECT(res.body == "Hello");
}
{
response<string_body, test_fields> res{
status::bad_request, 10, "Hello", token{}};
BEAST_EXPECT(res.version == 10);
BEAST_EXPECT(res.result() == status::bad_request);
BEAST_EXPECT(res.reason() == "Bad Request");
BEAST_EXPECT(res.body == "Hello");
} }
} }
@@ -292,7 +357,7 @@ public:
run() override run() override
{ {
testMessage(); testMessage();
testHeaders(); testMessageCtors();
testSwap(); testSwap();
testSpecialMembers(); testSpecialMembers();
testMethod(); testMethod();

View File

@@ -27,10 +27,11 @@ public:
{ {
static_assert(is_body_reader<string_view_body>::value, ""); static_assert(is_body_reader<string_view_body>::value, "");
static_assert(! is_body_writer<string_view_body>::value, ""); static_assert(! is_body_writer<string_view_body>::value, "");
request<string_view_body> req{"Hello, world!"}; request<string_view_body> req;
req.version = 11; req.version = 11;
req.method(verb::post); req.method(verb::post);
req.target("/"); req.target("/");
req.body = "Hello, world!";
req.prepare_payload(); req.prepare_payload();
static_buffer_n<512> b; static_buffer_n<512> b;
ostream(b) << req; ostream(b) << req;

View File

@@ -278,9 +278,8 @@ public:
response<string_body> m; response<string_body> m;
m.version = 10; m.version = 10;
m.result(status::ok); m.result(status::ok);
m.reason("OK"); m.set(field::server, "test");
m.insert(field::server, "test"); m.set(field::content_length, "5");
m.insert("Content-Length", "5");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
test::string_ostream ss{ios_}; test::string_ostream ss{ios_};
@@ -297,9 +296,8 @@ public:
response<string_body> m; response<string_body> m;
m.version = 11; m.version = 11;
m.result(status::ok); m.result(status::ok);
m.reason("OK"); m.set(field::server, "test");
m.insert(field::server, "test"); m.set(field::transfer_encoding, "chunked");
m.insert("Transfer-Encoding", "chunked");
m.body = "*****"; m.body = "*****";
error_code ec; error_code ec;
test::string_ostream ss(ios_); test::string_ostream ss(ios_);
@@ -327,11 +325,8 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
request<fail_body> m{fc}; request<fail_body> m(verb::get, "/", 10, fc);
m.method(verb::get); m.set(field::user_agent, "test");
m.target("/");
m.version = 10;
m.insert(field::user_agent, "test");
m.set(field::connection, "keep-alive"); m.set(field::connection, "keep-alive");
m.set(field::content_length, "5"); m.set(field::content_length, "5");
m.body = "*****"; m.body = "*****";
@@ -360,12 +355,9 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
request<fail_body> m{fc}; request<fail_body> m{verb::get, "/", 10, fc};
m.method(verb::get); m.set(field::user_agent, "test");
m.target("/"); m.set(field::transfer_encoding, "chunked");
m.version = 10;
m.insert(field::user_agent, "test");
m.insert("Transfer-Encoding", "chunked");
m.body = "*****"; m.body = "*****";
error_code ec = test::error::fail_error; error_code ec = test::error::fail_error;
write(fs, m, ec); write(fs, m, ec);
@@ -393,12 +385,9 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
request<fail_body> m{fc}; request<fail_body> m{verb::get, "/", 10, fc};
m.method(verb::get); m.set(field::user_agent, "test");
m.target("/"); m.set(field::transfer_encoding, "chunked");
m.version = 10;
m.insert(field::user_agent, "test");
m.insert("Transfer-Encoding", "chunked");
m.body = "*****"; m.body = "*****";
error_code ec = test::error::fail_error; error_code ec = test::error::fail_error;
async_write(fs, m, do_yield[ec]); async_write(fs, m, do_yield[ec]);
@@ -426,11 +415,8 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
request<fail_body> m{fc}; request<fail_body> m{verb::get, "/", 10, fc};
m.method(verb::get); m.set(field::user_agent, "test");
m.target("/");
m.version = 10;
m.insert(field::user_agent, "test");
m.set(field::connection, "keep-alive"); m.set(field::connection, "keep-alive");
m.set(field::content_length, "5"); m.set(field::content_length, "5");
m.body = "*****"; m.body = "*****";
@@ -456,11 +442,8 @@ public:
test::fail_counter fc(n); test::fail_counter fc(n);
test::fail_stream< test::fail_stream<
test::string_ostream> fs(fc, ios_); test::string_ostream> fs(fc, ios_);
request<fail_body> m{fc}; request<fail_body> m{verb::get, "/", 10, fc};
m.method(verb::get); m.set(field::user_agent, "test");
m.target("/");
m.version = 10;
m.insert(field::user_agent, "test");
m.set(field::connection, "keep-alive"); m.set(field::connection, "keep-alive");
m.set(field::content_length, "5"); m.set(field::content_length, "5");
m.body = "*****"; m.body = "*****";
@@ -491,7 +474,7 @@ public:
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
m.insert(field::user_agent, "test"); m.set(field::user_agent, "test");
m.body = "*"; m.body = "*";
m.prepare_payload(); m.prepare_payload();
BEAST_EXPECT(str(m) == BEAST_EXPECT(str(m) ==
@@ -508,7 +491,7 @@ public:
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 10; m.version = 10;
m.insert(field::user_agent, "test"); m.set(field::user_agent, "test");
m.body = "*"; m.body = "*";
m.prepare_payload(); m.prepare_payload();
test::string_ostream ss(ios_); test::string_ostream ss(ios_);
@@ -528,7 +511,7 @@ public:
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 11; m.version = 11;
m.insert(field::user_agent, "test"); m.set(field::user_agent, "test");
m.body = "*"; m.body = "*";
m.prepare_payload(); m.prepare_payload();
BEAST_EXPECT(str(m) == BEAST_EXPECT(str(m) ==
@@ -545,7 +528,7 @@ public:
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 11; m.version = 11;
m.insert(field::user_agent, "test"); m.set(field::user_agent, "test");
m.body = "*"; m.body = "*";
m.prepare_payload(); m.prepare_payload();
test::string_ostream ss(ios_); test::string_ostream ss(ios_);
@@ -570,7 +553,7 @@ public:
m.method(verb::get); m.method(verb::get);
m.target("/"); m.target("/");
m.version = 11; m.version = 11;
m.insert(field::user_agent, "test"); m.set(field::user_agent, "test");
m.body = "*"; m.body = "*";
BEAST_EXPECT(boost::lexical_cast<std::string>(m) == BEAST_EXPECT(boost::lexical_cast<std::string>(m) ==
"GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*"); "GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*");
@@ -600,7 +583,7 @@ public:
m.method(verb::get); m.method(verb::get);
m.version = 11; m.version = 11;
m.target("/"); m.target("/");
m.insert("Content-Length", 5); m.set("Content-Length", 5);
m.body = "*****"; m.body = "*****";
async_write(os, m, handler{}); async_write(os, m, handler{});
BEAST_EXPECT(handler::count() > 0); BEAST_EXPECT(handler::count() > 0);
@@ -622,7 +605,7 @@ public:
m.method(verb::get); m.method(verb::get);
m.version = 11; m.version = 11;
m.target("/"); m.target("/");
m.insert("Content-Length", 5); m.set("Content-Length", 5);
m.body = "*****"; m.body = "*****";
async_write(is, m, handler{}); async_write(is, m, handler{});
BEAST_EXPECT(handler::count() > 0); BEAST_EXPECT(handler::count() > 0);
@@ -704,7 +687,7 @@ public:
m0.version = 11; m0.version = 11;
m0.result(status::ok); m0.result(status::ok);
m0.reason("OK"); m0.reason("OK");
m0.insert(field::server, "test"); m0.set(field::server, "test");
m0.body.s = "Hello, world!\n"; m0.body.s = "Hello, world!\n";
{ {
@@ -761,7 +744,7 @@ public:
} }
} }
{ {
m0.insert("Transfer-Encoding", "chunked"); m0.set("Transfer-Encoding", "chunked");
{ {
auto m = m0; auto m = m0;
error_code ec; error_code ec;