diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5a498eb4..d6798571 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,16 @@
1.0.0-b19
+HTTP
+
WebSocket
* Optimize utf8 validation
* Optimize mask operations
+API Changes:
+
+* Refactor message and message_headers declarations
+
--------------------------------------------------------------------------------
1.0.0-b18
diff --git a/doc/reference.xsl b/doc/reference.xsl
index d0f2d990..b163e93f 100644
--- a/doc/reference.xsl
+++ b/doc/reference.xsl
@@ -1052,10 +1052,26 @@
]
-
+
+ [heading Static Data Members]
+ [table
[[Name][Description]]
+
+
+ [
+ [[link beast.ref.
+ .
+ [*
+
+ ]]]
[
+
+
]
]
+
+ ]
+
+
[heading Data Members]
[table
[[Name][Description]]
-
+
[
[[link beast.ref.
diff --git a/include/beast/http/impl/message.ipp b/include/beast/http/impl/message.ipp
index 6d853587..7c29bf48 100644
--- a/include/beast/http/impl/message.ipp
+++ b/include/beast/http/impl/message.ipp
@@ -20,6 +20,43 @@
namespace beast {
namespace http {
+template
+void
+swap(
+ message_headers& m1,
+ message_headers& m2)
+{
+ using std::swap;
+ swap(m1.version, m2.version);
+ swap(m1.method, m2.method);
+ swap(m1.url, m2.url);
+ swap(m1.headers, m2.headers);
+}
+
+template
+void
+swap(
+ message_headers& a,
+ message_headers& b)
+{
+ using std::swap;
+ swap(a.version, b.version);
+ swap(a.status, b.status);
+ swap(a.reason, b.reason);
+ swap(a.headers, b.headers);
+}
+
+template
+void
+swap(
+ message& m1,
+ message& m2)
+{
+ using std::swap;
+ swap(m1.base(), m2.base());
+ swap(m1.body, m2.body);
+}
+
template
bool
is_keep_alive(message const& msg)
diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp
index 406e8c1b..8a136abd 100644
--- a/include/beast/http/message.hpp
+++ b/include/beast/http/message.hpp
@@ -18,7 +18,8 @@
namespace beast {
namespace http {
-/** A container for HTTP request headers.
+#if GENERATING_DOCS
+/** A container for HTTP request or response headers.
The container includes the headers, as well as the
request method and URL. Objects of this type may be
@@ -27,12 +28,24 @@ namespace http {
example, when receiving a request with the header value
"Expect: 100-continue".
*/
+template
+struct message_headers
+
+#else
+template
+struct message_headers;
+
template
-struct request_headers
+struct message_headers
+#endif
{
- /// Indicates if the message is a request.
- using is_request =
- std::integral_constant;
+ /// Indicates if the message headers are a request or response.
+#if GENERATING_DOCS
+ static bool constexpr is_request = isRequest;
+
+#else
+ static bool constexpr is_request = true;
+#endif
/// The type representing the headers.
using headers_type = Headers;
@@ -48,57 +61,65 @@ struct request_headers
*/
int version;
- /// The Request Method.
+ /** The Request Method
+
+ @note This field is present only if `isRequest == true`.
+ */
std::string method;
- /// The Request URI.
+ /** The Request URI
+
+ @note This field is present only if `isRequest == true`.
+ */
std::string url;
- /// The HTTP headers.
+ /// The HTTP field values.
Headers headers;
- /** Construct HTTP request headers.
+ /// Default constructor
+ message_headers() = default;
- Arguments, if any, are forwarded to the constructor
- of the headers member.
+ /// Move constructor
+ message_headers(message_headers&&) = default;
+
+ /// Copy constructor
+ message_headers(message_headers const&) = default;
+
+ /// Move assignment
+ message_headers& operator=(message_headers&&) = default;
+
+ /// Copy assignment
+ message_headers& operator=(message_headers const&) = default;
+
+ /** Construct message headers.
+
+ All arguments are forwarded to the constructor
+ of the `headers` member.
+
+ @note This constructor participates in overload resolution
+ if and only if the first parameter is not convertible to
+ `message_headers`.
*/
- /** @{ */
- request_headers() = default;
+#if GENERATING_DOCS
+ template
+ explicit
+ message_headers(Args&&... args);
+#else
template 0) || ! std::is_convertible<
typename std::decay::type,
- request_headers>::value>::type>
+ message_headers>::value>::type>
explicit
- request_headers(Arg1&& arg1, ArgN&&... argn)
+ message_headers(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward(arg1),
std::forward(argn)...)
{
}
- /** @} */
};
-/** Swap two HTTP request headers.
-
- Requirements:
-
- Headers is Swappable.
-*/
-template
-void
-swap(
- request_headers& a,
- request_headers& b)
-{
- using std::swap;
- swap(a.version, b.version);
- swap(a.method, b.method);
- swap(a.url, b.url);
- swap(a.headers, b.headers);
-}
-
-/** A container for HTTP response headers.
+/** A container for HTTP request or response headers.
The container includes the headers, as well as the
response status and reasons. Objects of this type may
@@ -107,11 +128,10 @@ swap(
example, when responding to a HEAD request.
*/
template
-struct response_headers
+struct message_headers
{
- /// Indicates if the message is a response.
- using is_request =
- std::integral_constant;
+ /// Indicates if the message headers are a request or response.
+ static bool constexpr is_request = false;
/// The type representing the headers.
using headers_type = Headers;
@@ -127,94 +147,45 @@ struct response_headers
*/
int version;
- /// The Response Status-Code.
- int status;
-
- /** The Response Reason-Phrase.
-
- The Reason-Phrase is obsolete as of rfc7230.
- */
- std::string reason;
-
- /// The HTTP headers.
+ /// The HTTP field values.
Headers headers;
- /** Construct HTTP request headers.
+ /// Default constructor
+ message_headers() = default;
- Arguments, if any, are forwarded to the constructor
- of the headers member.
+ /// Move constructor
+ message_headers(message_headers&&) = default;
+
+ /// Copy constructor
+ message_headers(message_headers const&) = default;
+
+ /// Move assignment
+ message_headers& operator=(message_headers&&) = default;
+
+ /// Copy assignment
+ message_headers& operator=(message_headers const&) = default;
+
+ /** Construct message headers.
+
+ All arguments are forwarded to the constructor
+ of the `headers` member.
+
+ @note This constructor participates in overload resolution
+ if and only if the first parameter is not convertible to
+ `message_headers`.
*/
- /** @{ */
- response_headers() = default;
-
template 0) || ! std::is_convertible<
typename std::decay::type,
- response_headers>::value>::type>
+ message_headers>::value>::type>
explicit
- response_headers(Arg1&& arg1, ArgN&&... argn)
+ message_headers(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward(arg1),
std::forward(argn)...)
{
}
- /** @} */
-};
-
-/** Swap two HTTP response headers.
-
- Requirements:
-
- Headers is Swappable.
-*/
-template
-void
-swap(
- response_headers& a,
- response_headers& b)
-{
- using std::swap;
- swap(a.version, b.version);
- swap(a.status, b.status);
- swap(a.reason, b.reason);
- swap(a.headers, b.headers);
-}
-
-/** A container for HTTP request or response headers.
-*/
-#if GENERATING_DOCS
-template
-struct message_headers
-{
- /// Indicates if the message is a request.
- using is_request =
- std::integral_constant;
-
- /// The type representing the headers.
- using headers_type = Headers;
-
- /** The HTTP version.
-
- This holds both the major and minor version numbers,
- using these formulas:
- @code
- major = version / 10;
- minor = version % 10;
- @endcode
- */
- int version;
-
- /** The Request Method.
-
- @note This field is present only if `isRequest == true`.
- */
- std::string method;
-
- /** The Request-URI.
-
- @note This field is present only if `isRequest == true`.
- */
- std::string url;
+#endif
/** The Response Status-Code.
@@ -229,29 +200,9 @@ struct message_headers
@note This field is present only if `isRequest == false`.
*/
std::string reason;
-
- /// The HTTP headers.
- Headers headers;
-
- /** Construct message headers.
-
- Any provided arguments are forwarded to the
- constructor of the headers member.
- */
- template
- message_headers(Args&&... args);
};
-#else
-template
-using message_headers =
- typename std::conditional,
- response_headers>::type;
-
-#endif
-
-/** A complete HTTP message.
+/** A container for a complete HTTP message.
A message can be a request or response, depending on the `isRequest`
template argument value. Requests and responses have different types,
@@ -260,93 +211,35 @@ using message_headers =
The `Body` template argument type determines the model used
to read or write the content body of the message.
- @tparam isRequest `true` if this is a request.
+ @tparam isRequest `true` if this represents a request,
+ or `false` if this represents a response. Some class data
+ members are conditionally present depending on this value.
@tparam Body A type meeting the requirements of Body.
- @tparam Headers A type meeting the requirements of Headers.
+ @tparam Headers The type of container used to hold the
+ field value pairs.
*/
template
struct message :
-#if GENERATING_DOCS
- implementation_defined
-#else
message_headers
-#endif
{
-#if GENERATING_DOCS
- /// Indicates if the message is a request.
- using is_request =
- std::integral_constant;
-
- /// The type representing the headers.
- using headers_type = Headers;
-
- /** The type controlling the body traits.
-
- The body member will be of type `body_type::value_type`.
- */
- using body_type = Body;
-
- /** The HTTP version.
-
- This holds both the major and minor version numbers,
- using these formulas:
- @code
- major = version / 10;
- minor = version % 10;
- @endcode
- */
- int version;
-
- /** The Request Method.
-
- @note This field is present only if `isRequest == true`.
- */
- std::string method;
-
- /** The Request-URI.
-
- @note This field is present only if `isRequest == true`.
- */
- std::string url;
-
- /** The Response Status-Code.
-
- @note This field is present only if `isRequest == false`.
- */
- int status;
-
- /** The Response Reason-Phrase.
-
- The Reason-Phrase is obsolete as of rfc7230.
-
- @note This field is present only if `isRequest == false`.
- */
- std::string reason;
-
- /// The HTTP headers.
- Headers headers;
-
-#else
- /// The container used to hold the request or response headers
+ /// The base class used to hold the request or response headers
using base_type = message_headers;
- /** The type controlling the body traits.
+ /** The type providing the body traits.
- The body member will be of type `body_type::value_type`.
+ The `body` member will be of type `body_type::value_type`.
*/
using body_type = Body;
-#endif
-
- /// A container representing the body.
+ /// A value representing the body.
typename Body::value_type body;
/// Default constructor
message() = default;
- /** Construct a message from headers.
+ /** Construct a message from message headers.
Additional arguments, if any, are forwarded to
the constructor of the body member.
@@ -359,7 +252,7 @@ struct message :
{
}
- /** Construct a message from headers.
+ /** Construct a message from message headers.
Additional arguments, if any, are forwarded to
the constructor of the body member.
@@ -394,6 +287,7 @@ struct message :
/** Construct a message.
@param u An argument forwarded to the body constructor.
+
@param v An argument forwarded to the headers constructor.
@note This constructor participates in overload resolution
@@ -425,6 +319,7 @@ struct message :
/** Construct a message.
@param un A tuple forwarded as a parameter pack to the body constructor.
+
@param vn A tuple forwarded as a parameter pack to the headers constructor.
*/
template
@@ -436,6 +331,20 @@ struct message :
{
}
+ /// Returns the message headers portion of the message
+ base_type&
+ base()
+ {
+ return *this;
+ }
+
+ /// Returns the message headers portion of the message
+ base_type const&
+ base() const
+ {
+ return *this;
+ }
+
private:
template
message(std::piecewise_construct_t,
@@ -456,31 +365,52 @@ private:
}
};
-/// Swap one message for another message.
+//------------------------------------------------------------------------------
+
+#if GENERATING_DOCS
+/** Swap two HTTP message headers.
+
+ @par Requirements
+ `Headers` is @b Swappable.
+*/
+template
+void
+swap(
+ message_headers& m1,
+ message_headers& m2);
+#endif
+
+/** Swap two HTTP messages.
+
+ @par Requirements:
+ `Body` and `Headers` are @b Swappable.
+*/
template
void
swap(
- message& a,
- message& b)
-{
- using std::swap;
- using base_type = typename message<
- isRequest, Body, Headers>::base_type;
- swap(static_cast(a),
- static_cast(b));
- swap(a.body, b.body);
-}
+ message& m1,
+ message& m2);
-/// A typical HTTP request
+/// Message headers for a typical HTTP request
+using request_headers = message_headers>>;
+
+/// Message headers for a typical HTTP response
+using response_headers = message_headers>>;
+
+/// A typical HTTP request message
template>>
using request = message;
-/// A typical HTTP response
+/// A typical HTTP response message
template>>
using response = message;
+//------------------------------------------------------------------------------
+
/** Returns `true` if a HTTP/1 message indicates a keep alive.
Undefined behavior if version is greater than 11.
diff --git a/include/beast/http/write.hpp b/include/beast/http/write.hpp
index 6bc57ad3..15a7bd12 100644
--- a/include/beast/http/write.hpp
+++ b/include/beast/http/write.hpp
@@ -17,6 +17,120 @@
namespace beast {
namespace http {
+/** Write HTTP/1 message headers on a stream.
+
+ This function is used to write message headers to a stream. The
+ call will block until one of the following conditions is true:
+
+ @li All the message headers are sent.
+
+ @li An error occurs.
+
+ This operation is implemented in terms of one or more calls
+ to the stream's `write_some` function.
+
+ Regardless of the semantic meaning of the headers (for example,
+ specifying a zero-length message body and Connection: Close),
+ this function will not return `boost::asio::error::eof`.
+
+ @param stream The stream to which the data is to be written.
+ The type must support the @b `SyncWriteStream` concept.
+
+ @param msg The message headers to write.
+
+ @throws system_error Thrown on failure.
+*/
+template
+void
+write(SyncWriteStream& stream,
+ message_headers const& msg);
+
+/** Write HTTP/1 message headers on a stream.
+
+ This function is used to write message headers to a stream. The
+ call will block until one of the following conditions is true:
+
+ @li All the message headers are sent.
+
+ @li An error occurs.
+
+ This operation is implemented in terms of one or more calls
+ to the stream's `write_some` function.
+
+ Regardless of the semantic meaning of the headers (for example,
+ specifying a zero-length message body and Connection: Close),
+ this function will not return `boost::asio::error::eof`.
+
+ @param stream The stream to which the data is to be written.
+ The type must support the @b `SyncWriteStream` concept.
+
+ @param msg The message headers to write.
+
+ @param ec Set to the error, if any occurred.
+*/
+template
+void
+write(SyncWriteStream& stream,
+ message_headers const& msg,
+ error_code& ec);
+
+/** Start an asynchronous operation to write HTTP/1 message headers to a stream.
+
+ This function is used to asynchronously write message headers to a stream.
+ The function call always returns immediately. The asynchronous
+ operation will continue until one of the following conditions is true:
+
+ @li The entire message headers are sent.
+
+ @li An error occurs.
+
+ This operation is implemented in terms of one or more calls to the
+ stream's `async_write_some` functions, and is known as a composed
+ operation. The program must ensure that the stream performs no
+ other write operations (such as @ref async_write, the stream's
+ `async_write_some` function, or any other composed operations that
+ perform writes) until this operation completes.
+
+ Regardless of the semantic meaning of the headers (for example,
+ specifying a zero-length message body and Connection: Close),
+ the handler will not be called with `boost::asio::error::eof`.
+
+ @param stream The stream to which the data is to be written.
+ The type must support the @b `AsyncWriteStream` concept.
+
+ @param msg The message headers to send.
+
+ @param handler The handler to be called when the request completes.
+ Copies will be made of the handler as required. The equivalent
+ function signature of the handler must be:
+ @code void handler(
+ error_code const& error // result of operation
+ ); @endcode
+ Regardless of whether the asynchronous operation completes
+ immediately or not, the handler will not be invoked from within
+ this function. Invocation of the handler will be performed in a
+ manner equivalent to using `boost::asio::io_service::post`.
+
+ @note The message object must remain valid at least until the
+ completion handler is called, no copies are made.
+*/
+template
+#if GENERATING_DOCS
+void_or_deduced
+#else
+typename async_completion<
+ WriteHandler, void(error_code)>::result_type
+#endif
+async_write(AsyncWriteStream& stream,
+ message_headers const& msg,
+ WriteHandler&& handler);
+
+//------------------------------------------------------------------------------
+
/** Write a HTTP/1 message on a stream.
This function is used to write a message to a stream. The call
@@ -135,7 +249,24 @@ async_write(AsyncWriteStream& stream,
message const& msg,
WriteHandler&& handler);
-/** Serialize a HTTP/1 message to an ostream.
+//------------------------------------------------------------------------------
+
+/** Serialize HTTP/1 message headers to a `std::ostream`.
+
+ The function converts the message headers to its HTTP/1
+ serialized representation and stores the result in the output
+ stream.
+
+ @param os The output stream to write to.
+
+ @param msg The message headers to write.
+*/
+template
+std::ostream&
+operator<<(std::ostream& os,
+ message_headers const& msg);
+
+/** Serialize a HTTP/1 message to a `std::ostream`.
The function converts the message to its HTTP/1 serialized
representation and stores the result in the output stream.
@@ -143,7 +274,7 @@ async_write(AsyncWriteStream& stream,
The implementation will automatically perform chunk encoding if
the contents of the message indicate that chunk encoding is required.
- @param os The ostream to write to.
+ @param os The output stream to write to.
@param msg The message to write.
*/
diff --git a/test/http/message.cpp b/test/http/message.cpp
index 06689155..e01ad2e5 100644
--- a/test/http/message.cpp
+++ b/test/http/message.cpp
@@ -168,13 +168,13 @@ public:
void testHeaders()
{
{
- using req_type = request_headers;
+ using req_type = request_headers;
static_assert(std::is_copy_constructible::value, "");
static_assert(std::is_move_constructible::value, "");
static_assert(std::is_copy_assignable::value, "");
static_assert(std::is_move_assignable::value, "");
- using res_type = response_headers;
+ using res_type = response_headers;
static_assert(std::is_copy_constructible::value, "");
static_assert(std::is_move_constructible::value, "");
static_assert(std::is_copy_assignable::value, "");
@@ -183,7 +183,7 @@ public:
{
MoveHeaders h;
- request_headers r{std::move(h)};
+ message_headers r{std::move(h)};
BEAST_EXPECT(h.moved_from);
BEAST_EXPECT(r.headers.moved_to);
request m{std::move(r)};
diff --git a/test/http/nodejs_parser.hpp b/test/http/nodejs_parser.hpp
index 76110050..3dd98ad6 100644
--- a/test/http/nodejs_parser.hpp
+++ b/test/http/nodejs_parser.hpp
@@ -818,7 +818,8 @@ private:
{
return on_request(method, url,
major, minor, keep_alive, upgrade,
- typename message_type::is_request{});
+ std::integral_constant<
+ bool, message_type::is_request>{});
}
bool
@@ -847,7 +848,7 @@ private:
{
return on_response(
status, reason, major, minor, keep_alive, upgrade,
- std::integral_constant{});
+ std::integral_constant{});
}
void
diff --git a/test/http/parser_v1.cpp b/test/http/parser_v1.cpp
index 7717d8ce..02075d86 100644
--- a/test/http/parser_v1.cpp
+++ b/test/http/parser_v1.cpp
@@ -64,7 +64,7 @@ public:
streambuf rb;
headers_parser_v1 p0;
parse(ss, rb, p0);
- request_headers const& reqh = p0.get();
+ request_headers const& reqh = p0.get();
BEAST_EXPECT(reqh.method == "GET");
BEAST_EXPECT(reqh.url == "/");
BEAST_EXPECT(reqh.version == 11);