Refine message class hierarchy:

Two new objects, request_headers and response_headers,
represent the portion of HTTP messages excluding the body.
This commit is contained in:
Vinnie Falco
2016-10-09 06:34:35 -04:00
parent 056d6b94c2
commit a4d8a154b1
31 changed files with 569 additions and 487 deletions

View File

@ -42,6 +42,17 @@ API Changes:
* Rename mask_buffer_size to write_buffer_size
* Make auto_fragment a boolean option
The message class hierarchy is refactored (breaking change):
* One message class now models both HTTP/1 and HTTP/2 messages
* message_v1, request_v1, response_v1 removed
* New classes basic_request and basic_response model
messages without the body.
Error resolution: Callers should use message, request,
and response instead of message_v1, request_v1, and
response_v1 respectively.
--------------------------------------------------------------------------------
1.0.0-b15

View File

@ -11,7 +11,7 @@
[block '''
<informaltable frame="all"><tgroup cols="1"><colspec colname="a"/><tbody><row><entry valign="top"><simplelist>
<member><link linkend="beast.http.message">Message</link></member>
<member><link linkend="beast.http.message">Messages</link></member>
<member><link linkend="beast.http.headers">Headers</link></member>
<member><link linkend="beast.http.body">Body</link></member>
<member><link linkend="beast.http.algorithms">Algorithms</link></member>
@ -44,25 +44,25 @@ messages called responses.
[section:message Message]
[section:message Messages]
The __message__ class template models HTTP/2 requests and responses, while the
derived class __message_v1__ models HTTP/1 requests and responses, adding the
required version field. These objects are complete: they contain
all the information required to permit the algorithms to operate. These objects
are first class: They may be returned from functions, moved, copied, passed
as arguments, and stored in containers. Request and response messages are
distinct types; functions may be overloaded on just one or the other if
desired. Because this class template supports HTTP/1 and HTTP/2, it is
sometimes referred to as the universal message model.
The __message__ class template models HTTP/1 and HTTP/2 requests and responses.
These class templates are complete: they contain all the information needed
by the algorithms. Objects of this type are first class: They may be returned
from functions, moved, copied, passed as arguments, and stored in containers.
Request and response messages are distinct types; functions may be overloaded
on just one or the other if desired. Because this class template supports
HTTP/1 and HTTP/2, it is sometimes referred to as the universal message model.
These class templates have three template parameters:
There are three important template parameters in the message class:
```
template<bool isRequest, class Body, class Headers>
template<
bool isRequest,
class Body,
class Headers
>
class message;
template<bool isRequest, class Body, class Headers>
class message_v1;
```
* [*`isRequest`]: Controls whether or not the message is a request or response.
@ -76,28 +76,26 @@ These class templates have three template parameters:
For notational convenience, the following template type aliases are provided:
```
template<class Body, class Headers = basic_headers<std::allocator<char>>>
template<
class Body,
class Headers = basic_headers<std::allocator<char>>>
using request = message<true, Body, Headers>;
template<class Body, class Headers = basic_headers<std::allocator<char>>>
template<
class Body,
class Headers = basic_headers<std::allocator<char>>>
using response = message<false, Body, Headers>;
template<class Body, class Headers = basic_headers<std::allocator<char>>>
using request_v1 = message_v1<true, Body, Headers>;
template<class Body, class Headers = basic_headers<std::allocator<char>>>
using response_v1 = message_v1<false, Body, Headers>;
```
Although these aliases have a common base class, they have different fields
depending on whether the message is a request or a response. These simplified
declarations notionally illustrate the members of HTTP/1 messages:
The message class template has different data members depending on whether
it represents a request or response. These simplified declarations
notionally illustrate the members of HTTP/1 messages:
```
template<class Body, class Headers>
struct request_v1
struct request
{
int version; 10 or 11
int version; // 10 for HTTP/1.0, 11 for HTTP/1.1
std::string method;
std::string url;
Headers headers;
@ -105,9 +103,9 @@ declarations notionally illustrate the members of HTTP/1 messages:
};
template<class Body, class Headers>
struct response_v1
struct response
{
int version; 10 or 11
int version; // 10 for HTTP/1.0, 11 for HTTP/1.1
int status;
std::string reason;
Headers headers;
@ -117,17 +115,17 @@ declarations notionally illustrate the members of HTTP/1 messages:
These statements set fields in request and response message objects:
```
request_v1<string_body> req;
request<string_body> req;
req.version = 11; // HTTP/1.1
req.method = "GET";
req.url = "/index.html";
req.version = 11; // HTTP/1.1
req.headers.insert("User-Agent", "Beast.HTTP");
req.body = "";
response_v1<string_body> res;
response<string_body> res;
res.version = 10; // HTTP/1.0
res.status = 404;
res.reason = "Not Found";
res.version = 10; // HTTP/1.0
res.headers.insert("Server", "Beast.HTTP");
res.body = "The requested resource was not found.";
```
@ -147,7 +145,7 @@ The field names are not case-sensitive.
These statements change the values of the headers in the message passed:
```
template<class Body>
void set_fields(request_v1<Body>& req)
void set_fields(request<Body>& req)
{
if(! req.exists("User-Agent"))
req.insert("User-Agent", "myWebClient");
@ -184,7 +182,7 @@ and serialization. Beast provides three very common [*`Body`] types:
* [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body.
Used in GET requests where there is no message body. Example:
```
request_v1<empty_body> req;
request<empty_body> req;
req.version = 11;
req.method = "GET";
req.url = "/index.html";
@ -196,7 +194,7 @@ or response with simple text in the message body (such as an error message).
Has the same insertion complexity of `std::string`. This is the type of body
used in the examples:
```
response_v1<string_body> res;
response<string_body> res;
static_assert(std::is_same<decltype(res.body), std::string>::value);
res.body = "Here is the data you requested";
```
@ -282,7 +280,7 @@ An asynchronous interface is available:
```
void handle_write(boost::system::error_code);
...
request_v1<empty_body> req;
request<empty_body> req;
...
async_write(sock, req, std::bind(&handle_write, std::placeholders::_1));
```
@ -297,7 +295,7 @@ stored in the streambuf parameter for use in a subsequent call to read:
```
boost::asio::streambuf sb;
...
response_v1<string_body> res;
response<string_body> res;
read(sock, sb, res); // Throws exception on error
...
// Alternatively
@ -314,7 +312,7 @@ called:
void handle_read(boost::system::error_code);
...
boost::asio::streambuf sb;
response_v1<string_body> res;
response<string_body> res;
...
async_read(sock, res, std::bind(&handle_read, std::placeholders::_1));
```
@ -326,7 +324,7 @@ is optimized for performance:
void handle_read(boost::system::error_code);
...
beast::streambuf sb;
response_v1<string_body> res;
response<string_body> res;
read(sock, sb, res);
```

View File

@ -35,7 +35,11 @@
<member><link linkend="beast.ref.http__empty_body">empty_body</link></member>
<member><link linkend="beast.ref.http__headers">headers</link></member>
<member><link linkend="beast.ref.http__message">message</link></member>
<member><link linkend="beast.ref.http__message_v1">message_v1</link></member>
<member><link linkend="beast.ref.http__message_headers">message_headers</link></member>
<member><link linkend="beast.ref.http__request">request</link></member>
<member><link linkend="beast.ref.http__request_headers">request_headers</link></member>
<member><link linkend="beast.ref.http__response">response</link></member>
<member><link linkend="beast.ref.http__response_headers">response_headers</link></member>
<member><link linkend="beast.ref.http__resume_context">resume_context</link></member>
<member><link linkend="beast.ref.http__streambuf_body">streambuf_body</link></member>
<member><link linkend="beast.ref.http__string_body">string_body</link></member>
@ -62,6 +66,9 @@
<member><link linkend="beast.ref.http__async_parse">async_parse</link></member>
<member><link linkend="beast.ref.http__async_read">async_read</link></member>
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
<member><link linkend="beast.ref.http__async_write">async_write</link></member>
<member><link linkend="beast.ref.http__is_keep_alive">is_keep_alive</link></member>
<member><link linkend="beast.ref.http__is_upgrade">is_upgrade</link></member>
<member><link linkend="beast.ref.http__parse">parse</link></member>
<member><link linkend="beast.ref.http__prepare">prepare</link></member>
<member><link linkend="beast.ref.http__read">read</link></member>

View File

@ -32,8 +32,8 @@ class http_async_server
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using req_type = request_v1<string_body>;
using resp_type = response_v1<file_body>;
using req_type = request<string_body>;
using resp_type = response<file_body>;
std::mutex m_;
bool log_ = true;
@ -94,13 +94,13 @@ private:
struct data
{
Stream& s;
message_v1<isRequest, Body, Headers> m;
message<isRequest, Body, Headers> m;
Handler h;
bool cont;
template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_,
message_v1<isRequest, Body, Headers>&& m_)
message<isRequest, Body, Headers>&& m_)
: s(s_)
, m(std::move(m_))
, h(std::forward<DeducedHandler>(h_))
@ -174,7 +174,7 @@ private:
class DeducedHandler>
static
void
async_write(Stream& stream, message_v1<
async_write(Stream& stream, message<
isRequest, Body, Headers>&& msg,
DeducedHandler&& handler)
{
@ -236,7 +236,7 @@ private:
path = server_.root_ + path;
if(! boost::filesystem::exists(path))
{
response_v1<string_body> res;
response<string_body> res;
res.status = 404;
res.reason = "Not Found";
res.version = req_.version;
@ -265,7 +265,7 @@ private:
}
catch(std::exception const& e)
{
response_v1<string_body> res;
response<string_body> res;
res.status = 500;
res.reason = "Internal Error";
res.version = req_.version;

View File

@ -35,7 +35,7 @@ int main(int, char const*[])
ip::tcp::socket sock(ios);
connect(sock, it);
auto ep = sock.remote_endpoint();
request_v1<empty_body> req;
request<empty_body> req;
req.method = "GET";
req.url = "/";
req.version = 11;
@ -44,7 +44,7 @@ int main(int, char const*[])
req.headers.insert("User-Agent", "beast/http");
prepare(req);
write(sock, req);
response_v1<string_body> res;
response<string_body> res;
streambuf sb;
beast::http::read(sock, sb, res);
std::cout << res;

View File

@ -21,7 +21,7 @@ int main()
r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"}));
// Send HTTP request using beast
beast::http::request_v1<beast::http::empty_body> req;
beast::http::request<beast::http::empty_body> req;
req.method = "GET";
req.url = "/";
req.version = 11;
@ -32,7 +32,7 @@ int main()
// Receive and print HTTP response using beast
beast::streambuf sb;
beast::http::response_v1<beast::http::streambuf_body> resp;
beast::http::response<beast::http::streambuf_body> resp;
beast::http::read(sock, sb, resp);
std::cout << resp;
}

View File

@ -32,8 +32,8 @@ class http_sync_server
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using req_type = request_v1<string_body>;
using resp_type = response_v1<file_body>;
using req_type = request<string_body>;
using resp_type = response<file_body>;
bool log_ = true;
std::mutex m_;
@ -161,7 +161,7 @@ private:
path = root_ + path;
if(! boost::filesystem::exists(path))
{
response_v1<string_body> res;
response<string_body> res;
res.status = 404;
res.reason = "Not Found";
res.version = req.version;
@ -190,7 +190,7 @@ private:
}
catch(std::exception const& e)
{
response_v1<string_body> res;
response<string_body> res;
res.status = 500;
res.reason = "Internal Error";
res.version = req.version;

View File

@ -33,7 +33,7 @@ int main()
stream.handshake(ssl::stream_base::client);
// Send HTTP request over SSL using Beast
beast::http::request_v1<beast::http::empty_body> req;
beast::http::request<beast::http::empty_body> req;
req.method = "GET";
req.url = "/";
req.version = 11;
@ -45,7 +45,7 @@ int main()
// Receive and print HTTP response using Beast
beast::streambuf sb;
beast::http::response_v1<beast::http::streambuf_body> resp;
beast::http::response<beast::http::streambuf_body> resp;
beast::http::read(stream, sb, resp);
std::cout << resp;

View File

@ -14,7 +14,6 @@
#include <beast/http/empty_body.hpp>
#include <beast/http/headers.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/parse.hpp>
#include <beast/http/parse_error.hpp>
#include <beast/http/parser_v1.hpp>

View File

@ -251,14 +251,14 @@ public:
@note Meets the requirements of @b `FieldSequence`.
*/
template<class Allocator>
class basic_headers
class basic_headers :
#if ! GENERATING_DOCS
: private beast::detail::empty_base_optimization<
private beast::detail::empty_base_optimization<
typename std::allocator_traits<Allocator>::
template rebind_alloc<
detail::basic_headers_base::element>>
, public detail::basic_headers_base
detail::basic_headers_base::element>>,
#endif
public detail::basic_headers_base
{
using alloc_type = typename
std::allocator_traits<Allocator>::

View File

@ -5,13 +5,14 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#ifndef BEAST_HTTP_IMPL_MESSAGE_IPP
#define BEAST_HTTP_IMPL_MESSAGE_IPP
#include <beast/core/error.hpp>
#include <beast/http/concepts.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/core/detail/ci_char_traits.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <stdexcept>
@ -20,9 +21,10 @@ namespace http {
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
is_keep_alive(message<isRequest, Body, Headers> const& msg)
{
if(msg.version >= 11)
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
if(msg.version == 11)
{
if(token_list{msg.headers["Connection"]}.exists("close"))
return false;
@ -35,9 +37,10 @@ is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message_v1<isRequest, Body, Headers> const& msg)
is_upgrade(message<isRequest, Body, Headers> const& msg)
{
if(msg.version < 11)
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
if(msg.version == 10)
return false;
if(token_list{msg.headers["Connection"]}.exists("upgrade"))
return true;
@ -56,14 +59,14 @@ template<bool isRequest, class Body, class Headers>
inline
void
prepare_options(prepare_info& pi,
message_v1<isRequest, Body, Headers>& msg)
message<isRequest, Body, Headers>& msg)
{
}
template<bool isRequest, class Body, class Headers>
void
prepare_option(prepare_info& pi,
message_v1<isRequest, Body, Headers>& msg,
message<isRequest, Body, Headers>& msg,
connection value)
{
pi.connection_value = value;
@ -74,7 +77,7 @@ template<
class Opt, class... Opts>
void
prepare_options(prepare_info& pi,
message_v1<isRequest, Body, Headers>& msg,
message<isRequest, Body, Headers>& msg,
Opt&& opt, Opts&&... opts)
{
prepare_option(pi, msg, opt);
@ -85,7 +88,7 @@ prepare_options(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_content_length(prepare_info& pi,
message_v1<isRequest, Body, Headers> const& msg,
message<isRequest, Body, Headers> const& msg,
std::true_type)
{
typename Body::writer w(msg);
@ -100,7 +103,7 @@ prepare_content_length(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_content_length(prepare_info& pi,
message_v1<isRequest, Body, Headers> const& msg,
message<isRequest, Body, Headers> const& msg,
std::false_type)
{
pi.content_length = boost::none;
@ -112,7 +115,7 @@ template<
bool isRequest, class Body, class Headers,
class... Options>
void
prepare(message_v1<isRequest, Body, Headers>& msg,
prepare(message<isRequest, Body, Headers>& msg,
Options&&... options)
{
// VFALCO TODO
@ -121,7 +124,7 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
static_assert(has_writer<Body>::value,
"Body has no writer");
static_assert(is_Writer<typename Body::writer,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Writer requirements not met");
detail::prepare_info pi;
detail::prepare_content_length(pi, msg,
@ -148,7 +151,7 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
struct set_field
{
void
operator()(message_v1<true, Body, Headers>& msg,
operator()(message<true, Body, Headers>& msg,
detail::prepare_info const& pi) const
{
using beast::detail::ci_equal;
@ -161,7 +164,7 @@ prepare(message_v1<isRequest, Body, Headers>& msg,
}
void
operator()(message_v1<false, Body, Headers>& msg,
operator()(message<false, Body, Headers>& msg,
detail::prepare_info const& pi) const
{
if((msg.status / 100 ) != 1 &&

View File

@ -33,7 +33,7 @@ class read_op
parser_v1<isRequest, Body, Headers>;
using message_type =
message_v1<isRequest, Body, Headers>;
message<isRequest, Body, Headers>;
struct data
{
@ -144,7 +144,7 @@ template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg)
message<isRequest, Body, Headers>& msg)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met");
@ -155,7 +155,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
static_assert(has_reader<Body>::value,
"Body has no reader");
static_assert(is_Reader<typename Body::reader,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Reader requirements not met");
error_code ec;
beast::http::read(stream, dynabuf, msg, ec);
@ -167,7 +167,7 @@ template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& m,
message<isRequest, Body, Headers>& m,
error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
@ -179,7 +179,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf,
static_assert(has_reader<Body>::value,
"Body has no reader");
static_assert(is_Reader<typename Body::reader,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Reader requirements not met");
parser_v1<isRequest, Body, Headers> p;
beast::http::parse(stream, dynabuf, p, ec);
@ -195,7 +195,7 @@ template<class AsyncReadStream, class DynamicBuffer,
typename async_completion<
ReadHandler, void(error_code)>::result_type
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& m,
message<isRequest, Body, Headers>& m,
ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,
@ -207,7 +207,7 @@ async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
static_assert(has_reader<Body>::value,
"Body has no reader");
static_assert(is_Reader<typename Body::reader,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Reader requirements not met");
beast::async_completion<ReadHandler,
void(error_code)> completion(handler);

View File

@ -34,7 +34,7 @@ namespace detail {
template<class DynamicBuffer, class Body, class Headers>
void
write_firstline(DynamicBuffer& dynabuf,
message_v1<true, Body, Headers> const& msg)
message<true, Body, Headers> const& msg)
{
write(dynabuf, msg.method);
write(dynabuf, " ");
@ -62,7 +62,7 @@ write_firstline(DynamicBuffer& dynabuf,
template<class DynamicBuffer, class Body, class Headers>
void
write_firstline(DynamicBuffer& dynabuf,
message_v1<false, Body, Headers> const& msg)
message<false, Body, Headers> const& msg)
{
switch(msg.version)
{
@ -108,7 +108,7 @@ write_fields(DynamicBuffer& dynabuf, FieldSequence const& fields)
template<bool isRequest, class Body, class Headers>
struct write_preparation
{
message_v1<isRequest, Body, Headers> const& msg;
message<isRequest, Body, Headers> const& msg;
typename Body::writer w;
streambuf sb;
bool chunked;
@ -116,7 +116,7 @@ struct write_preparation
explicit
write_preparation(
message_v1<isRequest, Body, Headers> const& msg_)
message<isRequest, Body, Headers> const& msg_)
: msg(msg_)
, w(msg)
, chunked(token_list{
@ -161,7 +161,7 @@ class write_op
template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_,
message_v1<isRequest, Body, Headers> const& m_)
message<isRequest, Body, Headers> const& m_)
: s(s_)
, wp(m_)
, h(std::forward<DeducedHandler>(h_))
@ -467,7 +467,7 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg)
message<isRequest, Body, Headers> const& msg)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
@ -476,7 +476,7 @@ write(SyncWriteStream& stream,
static_assert(has_writer<Body>::value,
"Body has no writer");
static_assert(is_Writer<typename Body::writer,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Writer requirements not met");
error_code ec;
write(stream, msg, ec);
@ -488,7 +488,7 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg,
message<isRequest, Body, Headers> const& msg,
error_code& ec)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
@ -498,7 +498,7 @@ write(SyncWriteStream& stream,
static_assert(has_writer<Body>::value,
"Body has no writer");
static_assert(is_Writer<typename Body::writer,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Writer requirements not met");
detail::write_preparation<isRequest, Body, Headers> wp(msg);
wp.init(ec);
@ -584,7 +584,7 @@ template<class AsyncWriteStream,
typename async_completion<
WriteHandler, void(error_code)>::result_type
async_write(AsyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg,
message<isRequest, Body, Headers> const& msg,
WriteHandler&& handler)
{
static_assert(is_AsyncWriteStream<AsyncWriteStream>::value,
@ -594,7 +594,7 @@ async_write(AsyncWriteStream& stream,
static_assert(has_writer<Body>::value,
"Body has no writer");
static_assert(is_Writer<typename Body::writer,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Writer requirements not met");
beast::async_completion<WriteHandler,
void(error_code)> completion(handler);
@ -655,14 +655,14 @@ public:
template<bool isRequest, class Body, class Headers>
std::ostream&
operator<<(std::ostream& os,
message_v1<isRequest, Body, Headers> const& msg)
message<isRequest, Body, Headers> const& msg)
{
static_assert(is_Body<Body>::value,
"Body requirements not met");
static_assert(has_writer<Body>::value,
"Body has no writer");
static_assert(is_Writer<typename Body::writer,
message_v1<isRequest, Body, Headers>>::value,
message<isRequest, Body, Headers>>::value,
"Writer requirements not met");
detail::ostream_SyncStream oss(os);
error_code ec;

View File

@ -18,41 +18,174 @@
namespace beast {
namespace http {
namespace detail {
/** A container for HTTP request headers.
struct request_fields
The container includes the headers, as well as the
request method and URL. Objects of this type may be
used to represent incoming or outgoing requests for
which the body is not yet known or generated. For
example, when receiving a request with the header value
"Expect: 100-continue".
*/
template<class Headers>
struct request_headers
{
/// Indicates if the message is a request.
using is_request =
std::integral_constant<bool, true>;
/// 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 HTTP method.
std::string method;
/// The request URI.
std::string url;
protected:
void
swap(request_fields& other)
/// The HTTP headers.
Headers headers;
/** Construct HTTP request headers.
Arguments, if any, are forwarded to the constructor
of the headers member.
*/
/** @{ */
request_headers() = default;
template<class Arg1, class... ArgN,
class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type,
request_headers>::value>::type>
explicit
request_headers(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
{
using std::swap;
swap(method, other.method);
swap(url, other.url);
}
/** @} */
};
struct response_fields
/** Swap two HTTP request headers.
Requirements:
Headers is Swappable.
*/
template<class Headers>
void
swap(
request_headers<Headers>& a,
request_headers<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.
The container includes the headers, as well as the
response status and reasons. Objects of this type may
be used to represent incoming or outgoing responses for
which the body is not yet known or generated. For
example, when responding to a HEAD request.
*/
template<class Headers>
struct response_headers
{
/// Indicates if the message is a response.
using is_request =
std::integral_constant<bool, false>;
/// 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 HTTP response Status-Code.
int status;
/// The HTTP Reason-Phrase (obsolete).
std::string reason;
protected:
void
swap(response_fields& other)
/// The HTTP headers.
Headers headers;
/** Construct HTTP request headers.
Arguments, if any, are forwarded to the constructor
of the headers member.
*/
/** @{ */
response_headers() = default;
template<class Arg1, class... ArgN,
class = typename std::enable_if<
(sizeof...(ArgN) > 0) || ! std::is_convertible<
typename std::decay<Arg1>::type,
response_headers>::value>::type>
explicit
response_headers(Arg1&& arg1, ArgN&&... argn)
: headers(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
{
using std::swap;
swap(status, other.status);
swap(reason, other.reason);
}
/** @} */
};
} // detail
/** Swap two HTTP response headers.
/** A HTTP message.
Requirements:
Headers is Swappable.
*/
template<class Headers>
void
swap(
response_headers<Headers>& a,
response_headers<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.
*/
template<bool isRequest, class Headers>
using message_headers =
typename std::conditional<isRequest,
request_headers<Headers>,
response_headers<Headers>>::type;
/** 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,
@ -68,37 +201,56 @@ protected:
@tparam Headers A type meeting the requirements of Headers.
*/
template<bool isRequest, class Body, class Headers>
struct message
: std::conditional<isRequest,
detail::request_fields, detail::response_fields>::type
struct message : message_headers<isRequest, Headers>
{
/// The container used to hold the request or response headers
using base_type = message_headers<isRequest, Headers>;
/** The type controlling the body traits.
The body member will be of type `body_type::value_type`.
*/
using body_type = Body;
/// The type representing the headers.
using headers_type = Headers;
/// Indicates if the message is a request.
using is_request =
std::integral_constant<bool, isRequest>;
/// The container holding the headers.
headers_type headers;
/// A container representing the body.
typename Body::value_type body;
/// Default constructor
message() = default;
/** Construct a message from headers.
Additional arguments, if any, are forwarded to
the constructor of the body member.
*/
template<class... Args>
explicit
message(base_type&& base, Args&&... args)
: base_type(std::move(base))
, body(std::forward<Args>(args)...)
{
}
/** Construct a message from headers.
Additional arguments, if any, are forwarded to
the constructor of the body member.
*/
template<class... Args>
explicit
message(base_type const& base, Args&&... args)
: base_type(base)
, body(std::forward<Args>(args)...)
{
}
/** Construct a message.
@param u An argument forwarded to the body constructor.
*/
template<class U>
template<class U,
class = typename std::enable_if<! std::is_same<
typename std::decay<U>::type, base_type>::value>>
explicit
message(U&& u)
: body(std::forward<U>(u))
@ -110,9 +262,11 @@ struct message
@param u An argument forwarded to the body constructor.
@param v An argument forwarded to the headers constructor.
*/
template<class U, class V>
template<class U, class V,
class = typename std::enable_if<! std::is_same<
typename std::decay<U>::type, base_type>::value>>
message(U&& u, V&& v)
: headers(std::forward<V>(v))
: base_type(std::forward<V>(v))
, body(std::forward<U>(u))
{
}
@ -126,7 +280,6 @@ struct message
: message(std::piecewise_construct, un,
beast::detail::make_index_sequence<sizeof...(Un)>{})
{
}
/** Construct a message.
@ -143,14 +296,7 @@ struct message
{
}
/// Swap this message for another message.
void
swap(message& other);
private:
using base = typename std::conditional<isRequest,
detail::request_fields, detail::response_fields>::type;
template<class... Un, size_t... IUn>
message(std::piecewise_construct_t,
std::tuple<Un...>& tu, beast::detail::index_sequence<IUn...>)
@ -164,31 +310,25 @@ private:
std::tuple<Un...>& tu, std::tuple<Vn...>& tv,
beast::detail::index_sequence<IUn...>,
beast::detail::index_sequence<IVn...>)
: headers(std::forward<Vn>(std::get<IVn>(tv))...)
: base_type(std::forward<Vn>(std::get<IVn>(tv))...)
, body(std::forward<Un>(std::get<IUn>(tu))...)
{
}
};
template<bool isRequest, class Body, class Headers>
void
message<isRequest, Body, Headers>::
swap(message& other)
{
using std::swap;
base::swap(other);
swap(headers, other.headers);
swap(body, other.body);
}
/// Swap one message for another message.
template<bool isRequest, class Body, class Headers>
inline
void
swap(message<isRequest, Body, Headers>& lhs,
message<isRequest, Body, Headers>& rhs)
swap(
message<isRequest, Body, Headers>& a,
message<isRequest, Body, Headers>& b)
{
lhs.swap(rhs);
using std::swap;
using base_type = typename message<
isRequest, Body, Headers>::base_type;
swap(static_cast<base_type&>(a),
static_cast<base_type&>(b));
swap(a.body, b.body);
}
/// A typical HTTP request
@ -201,7 +341,58 @@ template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using response = message<false, Body, Headers>;
/** Returns `true` if a HTTP/1 message indicates a keep alive.
Undefined behavior if version is greater than 11.
*/
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message<isRequest, Body, Headers> const& msg);
/** Returns `true` if a HTTP/1 message indicates an Upgrade request or response.
Undefined behavior if version is greater than 11.
*/
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message<isRequest, Body, Headers> const& msg);
/** HTTP/1 connection prepare options.
@note These values are used with @ref prepare.
*/
enum class connection
{
/// Specify Connection: close.
close,
/// Specify Connection: keep-alive where possible.
keep_alive,
/// Specify Connection: upgrade.
upgrade
};
/** Prepare a HTTP message.
This function will adjust the Content-Length, Transfer-Encoding,
and Connection headers of the message based on the properties of
the body and the options passed in.
@param msg The message to prepare. The headers may be modified.
@param options A list of prepare options.
*/
template<
bool isRequest, class Body, class Headers,
class... Options>
void
prepare(message<isRequest, Body, Headers>& msg,
Options&&... options);
} // http
} // beast
#include <beast/http/impl/message.ipp>
#endif

View File

@ -1,139 +0,0 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_MESSAGE_V1_HPP
#define BEAST_HTTP_MESSAGE_V1_HPP
#include <beast/http/message.hpp>
#include <memory>
#include <string>
#include <type_traits>
namespace beast {
namespace http {
/** A HTTP/1 message.
A message can be a request or response, depending on the `isRequest`
template argument value. Requests and responses have different types,
so functions may be overloaded on them if desired.
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 Body A type meeting the requirements of Body.
@tparam Headers A type meeting the requirements of Headers.
*/
template<bool isRequest, class Body, class Headers>
struct message_v1 : message<isRequest, Body, Headers>
{
/// HTTP/1 version (10 or 11)
int version;
/// Default constructor
message_v1() = default;
/// Constructor
template<class Arg1, class... Argn,
class = typename std::enable_if<
! std::is_convertible<message_v1,
typename std::decay<Arg1>::type>::value>::type>
explicit
message_v1(Arg1&& arg1, Argn&&... argn)
: message<isRequest, Body, Headers>(
std::forward<Arg1>(arg1),
std::forward<Argn>(argn)...)
{
}
/// Swap this message for another message.
void
swap(message_v1& other);
};
template<bool isRequest, class Body, class Headers>
void
message_v1<isRequest, Body, Headers>::
swap(message_v1& other)
{
using std::swap;
message<isRequest, Body, Headers>::swap(other);
swap(version, other.version);
}
/// Swap one message for another message.
template<bool isRequest, class Body, class Headers>
inline
void
swap(message_v1<isRequest, Body, Headers>& lhs,
message_v1<isRequest, Body, Headers>& rhs)
{
lhs.swap(rhs);
}
/// A typical HTTP/1 request
template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using request_v1 = message_v1<true, Body, Headers>;
/// A typical HTTP/1 response
template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using response_v1 = message_v1<false, Body, Headers>;
/// Returns `true` if a HTTP/1 message indicates a keep alive
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message_v1<isRequest, Body, Headers> const& msg);
/// Returns `true` if a HTTP/1 message indicates an Upgrade request or response
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message_v1<isRequest, Body, Headers> const& msg);
/** HTTP/1 connection prepare options.
@note These values are used with @ref prepare.
*/
enum class connection
{
/// Specify Connection: close.
close,
/// Specify Connection: keep-alive where possible.
keep_alive,
/// Specify Connection: upgrade.
upgrade
};
/** Prepare a HTTP/1 message.
This function will adjust the Content-Length, Transfer-Encoding,
and Connection headers of the message based on the properties of
the body and the options passed in.
@param msg The message to prepare. The headers may be modified.
@param options A list of prepare options.
*/
template<
bool isRequest, class Body, class Headers,
class... Options>
void
prepare(message_v1<isRequest, Body, Headers>& msg,
Options&&... options);
} // http
} // beast
#include <beast/http/impl/message_v1.ipp>
#endif

View File

@ -10,7 +10,7 @@
#include <beast/http/basic_parser_v1.hpp>
#include <beast/http/concepts.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
#include <beast/core/error.hpp>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
@ -71,7 +71,7 @@ struct skip_body
/** A parser for producing HTTP/1 messages.
This class uses the basic HTTP/1 wire format parser to convert
a series of octets into a `message_v1`.
a series of octets into a `message`.
@note A new instance of the parser is required for each message.
*/
@ -85,7 +85,7 @@ class parser_v1
public:
/// The type of message this parser produces.
using message_type =
message_v1<isRequest, Body, Headers>;
message<isRequest, Body, Headers>;
private:
using reader =

View File

@ -10,7 +10,7 @@
#include <beast/core/async_completion.hpp>
#include <beast/core/error.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
namespace beast {
namespace http {
@ -49,7 +49,7 @@ template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg);
message<isRequest, Body, Headers>& msg);
/** Read a HTTP/1 message from a stream.
@ -85,7 +85,7 @@ template<class SyncReadStream, class DynamicBuffer,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg,
message<isRequest, Body, Headers>& msg,
error_code& ec);
/** Start an asynchronous operation to read a HTTP/1 message from a stream.
@ -136,7 +136,7 @@ typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf,
message_v1<isRequest, Body, Headers>& msg,
message<isRequest, Body, Headers>& msg,
ReadHandler&& handler);
} // http

View File

@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_WRITE_HPP
#define BEAST_HTTP_WRITE_HPP
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
#include <beast/core/error.hpp>
#include <beast/core/async_completion.hpp>
#include <ostream>
@ -46,7 +46,7 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg);
message<isRequest, Body, Headers> const& msg);
/** Write a HTTP/1 message on a stream.
@ -77,7 +77,7 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg,
message<isRequest, Body, Headers> const& msg,
error_code& ec);
/** Start an asynchronous operation to write a HTTP/1 message to a stream.
@ -132,7 +132,7 @@ typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
async_write(AsyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg,
message<isRequest, Body, Headers> const& msg,
WriteHandler&& handler);
/** Serialize a HTTP/1 message to an ostream.
@ -150,7 +150,7 @@ async_write(AsyncWriteStream& stream,
template<bool isRequest, class Body, class Headers>
std::ostream&
operator<<(std::ostream& os,
message_v1<isRequest, Body, Headers> const& msg);
message<isRequest, Body, Headers> const& msg);
} // http
} // beast

View File

@ -9,7 +9,7 @@
#define BEAST_WEBSOCKET_IMPL_ACCEPT_OP_HPP
#include <beast/websocket/impl/response_op.ipp>
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/core/handler_alloc.hpp>
@ -33,7 +33,7 @@ class stream<NextLayer>::accept_op
struct data
{
stream<NextLayer>& ws;
http::request_v1<http::string_body> req;
http::request<http::string_body> req;
Handler h;
bool cont;
int state = 0;

View File

@ -9,7 +9,7 @@
#define BEAST_WEBSOCKET_IMPL_HANDSHAKE_OP_HPP
#include <beast/http/empty_body.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
#include <beast/http/read.hpp>
#include <beast/http/write.hpp>
#include <beast/core/handler_alloc.hpp>
@ -33,8 +33,8 @@ class stream<NextLayer>::handshake_op
stream<NextLayer>& ws;
Handler h;
std::string key;
http::request_v1<http::empty_body> req;
http::response_v1<http::string_body> resp;
http::request<http::empty_body> req;
http::response<http::string_body> resp;
bool cont;
int state = 0;

View File

@ -8,7 +8,7 @@
#ifndef BEAST_WEBSOCKET_IMPL_RESPONSE_OP_HPP
#define BEAST_WEBSOCKET_IMPL_RESPONSE_OP_HPP
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
#include <beast/http/string_body.hpp>
#include <beast/http/write.hpp>
#include <beast/core/handler_alloc.hpp>
@ -28,7 +28,7 @@ class stream<NextLayer>::response_op
struct data
{
stream<NextLayer>& ws;
http::response_v1<http::string_body> resp;
http::response<http::string_body> resp;
Handler h;
error_code final_ec;
bool cont;
@ -37,7 +37,7 @@ class stream<NextLayer>::response_op
template<class DeducedHandler,
class Body, class Headers>
data(DeducedHandler&& h_, stream<NextLayer>& ws_,
http::request_v1<Body, Headers> const& req,
http::request<Body, Headers> const& req,
bool cont_)
: ws(ws_)
, resp(ws_.build_response(req))

View File

@ -116,7 +116,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
stream_.buffer().commit(buffer_copy(
stream_.buffer().prepare(
buffer_size(buffers)), buffers));
http::request_v1<http::string_body> m;
http::request<http::string_body> m;
http::read(next_layer(), stream_.buffer(), m, ec);
if(ec)
return;
@ -147,7 +147,7 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
accept(http::request_v1<Body, Headers> const& request)
accept(http::request<Body, Headers> const& request)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
@ -161,7 +161,7 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
accept(http::request_v1<Body, Headers> const& req,
accept(http::request<Body, Headers> const& req,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
@ -186,7 +186,7 @@ template<class Body, class Headers, class AcceptHandler>
typename async_completion<
AcceptHandler, void(error_code)>::result_type
stream<NextLayer>::
async_accept(http::request_v1<Body, Headers> const& req,
async_accept(http::request<Body, Headers> const& req,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
@ -230,7 +230,7 @@ handshake(boost::string_ref const& host,
build_request(host, resource, key), ec);
if(ec)
return;
http::response_v1<http::string_body> res;
http::response<http::string_body> res;
http::read(next_layer(), stream_.buffer(), res, ec);
if(ec)
return;
@ -839,12 +839,12 @@ reset()
}
template<class NextLayer>
http::request_v1<http::empty_body>
http::request<http::empty_body>
stream<NextLayer>::
build_request(boost::string_ref const& host,
boost::string_ref const& resource, std::string& key)
{
http::request_v1<http::empty_body> req;
http::request<http::empty_body> req;
req.url = { resource.data(), resource.size() };
req.version = 11;
req.method = "GET";
@ -860,14 +860,14 @@ build_request(boost::string_ref const& host,
template<class NextLayer>
template<class Body, class Headers>
http::response_v1<http::string_body>
http::response<http::string_body>
stream<NextLayer>::
build_response(http::request_v1<Body, Headers> const& req)
build_response(http::request<Body, Headers> const& req)
{
auto err =
[&](std::string const& text)
{
http::response_v1<http::string_body> res;
http::response<http::string_body> res;
res.status = 400;
res.reason = http::reason_string(res.status);
res.version = req.version;
@ -898,7 +898,7 @@ build_response(http::request_v1<Body, Headers> const& req)
return err("Missing Sec-WebSocket-Version");
if(version != "13")
{
http::response_v1<http::string_body> res;
http::response<http::string_body> res;
res.status = 426;
res.reason = http::reason_string(res.status);
res.version = req.version;
@ -910,7 +910,7 @@ build_response(http::request_v1<Body, Headers> const& req)
return res;
}
}
http::response_v1<http::string_body> res;
http::response<http::string_body> res;
res.status = 101;
res.reason = http::reason_string(res.status);
res.version = req.version;
@ -931,7 +931,7 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
do_response(http::response_v1<Body, Headers> const& res,
do_response(http::response<Body, Headers> const& res,
boost::string_ref const& key, error_code& ec)
{
// VFALCO Review these error codes

View File

@ -10,7 +10,7 @@
#include <beast/websocket/option.hpp>
#include <beast/websocket/detail/stream_base.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
#include <beast/http/string_body.hpp>
#include <beast/core/dynabuf_readstream.hpp>
#include <beast/core/async_completion.hpp>
@ -586,7 +586,7 @@ public:
// VFALCO TODO This should also take a DynamicBuffer with any leftover bytes.
template<class Body, class Headers>
void
accept(http::request_v1<Body, Headers> const& request);
accept(http::request<Body, Headers> const& request);
/** Respond to a WebSocket HTTP Upgrade request
@ -618,7 +618,7 @@ public:
*/
template<class Body, class Headers>
void
accept(http::request_v1<Body, Headers> const& request,
accept(http::request<Body, Headers> const& request,
error_code& ec);
/** Start responding to a WebSocket HTTP Upgrade request.
@ -669,7 +669,7 @@ public:
typename async_completion<
AcceptHandler, void(error_code)>::result_type
#endif
async_accept(http::request_v1<Body, Headers> const& request,
async_accept(http::request<Body, Headers> const& request,
AcceptHandler&& handler);
/** Send a HTTP WebSocket Upgrade request and receive the response.
@ -1530,18 +1530,18 @@ private:
void
reset();
http::request_v1<http::empty_body>
http::request<http::empty_body>
build_request(boost::string_ref const& host,
boost::string_ref const& resource,
std::string& key);
template<class Body, class Headers>
http::response_v1<http::string_body>
build_response(http::request_v1<Body, Headers> const& req);
http::response<http::string_body>
build_response(http::request<Body, Headers> const& req);
template<class Body, class Headers>
void
do_response(http::response_v1<Body, Headers> const& resp,
do_response(http::response<Body, Headers> const& resp,
boost::string_ref const& key, error_code& ec);
void

View File

@ -49,7 +49,6 @@ unit-test http-tests :
http/empty_body.cpp
http/headers.cpp
http/message.cpp
http/message_v1.cpp
http/parse.cpp
http/parse_error.cpp
http/parser_v1.cpp

View File

@ -18,7 +18,6 @@ add_executable (http-tests
empty_body.cpp
headers.cpp
message.cpp
message_v1.cpp
parse.cpp
parse_error.cpp
parser_v1.cpp

View File

@ -8,6 +8,7 @@
// Test that header file is self-contained.
#include <beast/http/message.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/headers.hpp>
#include <beast/http/string_body.hpp>
#include <beast/unit_test/suite.hpp>
@ -69,7 +70,7 @@ public:
};
};
void testConstruction()
void testMessage()
{
static_assert(std::is_constructible<
message<true, default_body, headers>>::value, "");
@ -125,10 +126,8 @@ public:
BEAST_EXPECT(! h.exists("User-Agent"));
BEAST_EXPECT(m.headers["User-Agent"] == "test");
}
}
void testSwap()
{
// swap
message<true, string_body, headers> m1;
message<true, string_body, headers> m2;
m1.url = "u";
@ -147,9 +146,144 @@ public:
BEAST_EXPECT(m2.headers.exists("h"));
}
struct MoveHeaders
{
bool moved_to = false;
bool moved_from = false;
MoveHeaders() = default;
MoveHeaders(MoveHeaders&& other)
: moved_to(true)
{
other.moved_from = true;
}
MoveHeaders& operator=(MoveHeaders&& other)
{
return *this;
}
};
void testHeaders()
{
{
using req_type = request_headers<headers>;
static_assert(std::is_copy_constructible<req_type>::value, "");
static_assert(std::is_move_constructible<req_type>::value, "");
static_assert(std::is_copy_assignable<req_type>::value, "");
static_assert(std::is_move_assignable<req_type>::value, "");
using res_type = response_headers<headers>;
static_assert(std::is_copy_constructible<res_type>::value, "");
static_assert(std::is_move_constructible<res_type>::value, "");
static_assert(std::is_copy_assignable<res_type>::value, "");
static_assert(std::is_move_assignable<res_type>::value, "");
}
{
MoveHeaders h;
request_headers<MoveHeaders> r{std::move(h)};
BEAST_EXPECT(h.moved_from);
BEAST_EXPECT(r.headers.moved_to);
request<string_body, MoveHeaders> m{std::move(r)};
BEAST_EXPECT(r.headers.moved_from);
BEAST_EXPECT(m.headers.moved_to);
}
}
void testFreeFunctions()
{
{
request<empty_body> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.headers.insert("Upgrade", "test");
BEAST_EXPECT(! is_upgrade(m));
prepare(m, connection::upgrade);
BEAST_EXPECT(is_upgrade(m));
BEAST_EXPECT(m.headers["Connection"] == "upgrade");
m.version = 10;
BEAST_EXPECT(! is_upgrade(m));
}
}
void testPrepare()
{
request<empty_body> m;
m.version = 10;
BEAST_EXPECT(! is_upgrade(m));
m.headers.insert("Transfer-Encoding", "chunked");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
}
m.headers.erase("Transfer-Encoding");
m.headers.insert("Content-Length", "0");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
pass();
}
m.headers.erase("Content-Length");
m.headers.insert("Connection", "keep-alive");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
pass();
}
m.version = 11;
m.headers.erase("Connection");
m.headers.insert("Connection", "close");
BEAST_EXPECT(! is_keep_alive(m));
}
void testSwap()
{
message<false, string_body, headers> m1;
message<false, string_body, headers> m2;
m1.status = 200;
m1.version = 10;
m1.body = "1";
m1.headers.insert("h", "v");
m2.status = 404;
m2.reason = "OK";
m2.body = "2";
m2.version = 11;
swap(m1, m2);
BEAST_EXPECT(m1.status == 404);
BEAST_EXPECT(m2.status == 200);
BEAST_EXPECT(m1.reason == "OK");
BEAST_EXPECT(m2.reason.empty());
BEAST_EXPECT(m1.version == 11);
BEAST_EXPECT(m2.version == 10);
BEAST_EXPECT(m1.body == "2");
BEAST_EXPECT(m2.body == "1");
BEAST_EXPECT(! m1.headers.exists("h"));
BEAST_EXPECT(m2.headers.exists("h"));
}
void run() override
{
testConstruction();
testMessage();
testHeaders();
testFreeFunctions();
testPrepare();
testSwap();
}
};
@ -158,4 +292,3 @@ BEAST_DEFINE_TESTSUITE(message,http,beast);
} // http
} // beast

View File

@ -1,119 +0,0 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/http/message_v1.hpp>
#include <beast/http/headers.hpp>
#include <beast/http/string_body.hpp>
#include <beast/unit_test/suite.hpp>
#include <beast/http/empty_body.hpp>
namespace beast {
namespace http {
class message_v1_test : public beast::unit_test::suite
{
public:
void testFreeFunctions()
{
{
request_v1<empty_body> m;
m.method = "GET";
m.url = "/";
m.version = 11;
m.headers.insert("Upgrade", "test");
BEAST_EXPECT(! is_upgrade(m));
prepare(m, connection::upgrade);
BEAST_EXPECT(is_upgrade(m));
BEAST_EXPECT(m.headers["Connection"] == "upgrade");
m.version = 10;
BEAST_EXPECT(! is_upgrade(m));
}
}
void testPrepare()
{
request_v1<empty_body> m;
m.version = 10;
BEAST_EXPECT(! is_upgrade(m));
m.headers.insert("Transfer-Encoding", "chunked");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
}
m.headers.erase("Transfer-Encoding");
m.headers.insert("Content-Length", "0");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
pass();
}
m.headers.erase("Content-Length");
m.headers.insert("Connection", "keep-alive");
try
{
prepare(m);
fail();
}
catch(std::exception const&)
{
pass();
}
m.version = 11;
m.headers.erase("Connection");
m.headers.insert("Connection", "close");
BEAST_EXPECT(! is_keep_alive(m));
}
void testSwap()
{
message_v1<false, string_body, headers> m1;
message_v1<false, string_body, headers> m2;
m1.status = 200;
m1.version = 10;
m1.body = "1";
m1.headers.insert("h", "v");
m2.status = 404;
m2.reason = "OK";
m2.body = "2";
m2.version = 11;
swap(m1, m2);
BEAST_EXPECT(m1.status == 404);
BEAST_EXPECT(m2.status == 200);
BEAST_EXPECT(m1.reason == "OK");
BEAST_EXPECT(m2.reason.empty());
BEAST_EXPECT(m1.version == 11);
BEAST_EXPECT(m2.version == 10);
BEAST_EXPECT(m1.body == "2");
BEAST_EXPECT(m2.body == "1");
BEAST_EXPECT(! m1.headers.exists("h"));
BEAST_EXPECT(m2.headers.exists("h"));
}
void run() override
{
testFreeFunctions();
testPrepare();
testSwap();
}
};
BEAST_DEFINE_TESTSUITE(message_v1,http,beast);
} // http
} // beast

View File

@ -10,7 +10,7 @@
#include "nodejs-parser/http_parser.h"
#include <beast/http/message_v1.hpp>
#include <beast/http/message.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/core/buffer_concepts.hpp>
#include <beast/core/error.hpp>
@ -741,7 +741,7 @@ class nodejs_parser
: public nodejs_basic_parser<nodejs_parser<isRequest, Body, Headers>>
{
using message_type =
message_v1<isRequest, Body, Headers>;
message<isRequest, Body, Headers>;
message_type m_;
typename message_type::body_type::reader r_;

View File

@ -259,7 +259,7 @@ public:
"Content-Length: 0\r\n"
"\r\n"
);
request_v1<streambuf_body> m;
request<streambuf_body> m;
try
{
streambuf sb;
@ -281,7 +281,7 @@ public:
"Content-Length: 0\r\n"
"\r\n"
);
request_v1<streambuf_body> m;
request<streambuf_body> m;
error_code ec;
streambuf sb;
read(fs, sb, m, ec);
@ -299,7 +299,7 @@ public:
"Content-Length: 0\r\n"
"\r\n"
);
request_v1<streambuf_body> m;
request<streambuf_body> m;
error_code ec;
streambuf sb;
async_read(fs, sb, m, do_yield[ec]);

View File

@ -222,7 +222,7 @@ public:
template<bool isRequest, class Body, class Headers>
std::string
str(message_v1<isRequest, Body, Headers> const& m)
str(message<isRequest, Body, Headers> const& m)
{
string_write_stream ss(ios_);
write(ss, m);
@ -233,7 +233,7 @@ public:
testAsyncWrite(yield_context do_yield)
{
{
message_v1<false, string_body, headers> m;
message<false, string_body, headers> m;
m.version = 10;
m.status = 200;
m.reason = "OK";
@ -252,7 +252,7 @@ public:
"*****");
}
{
message_v1<false, string_body, headers> m;
message<false, string_body, headers> m;
m.version = 11;
m.status = 200;
m.reason = "OK";
@ -285,7 +285,7 @@ public:
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
message<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
@ -318,7 +318,7 @@ public:
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
message<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
@ -353,7 +353,7 @@ public:
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
message<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
@ -388,7 +388,7 @@ public:
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
message<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
@ -418,7 +418,7 @@ public:
test::fail_counter fc(n);
test::fail_stream<
string_write_stream> fs(fc, ios_);
message_v1<true, fail_body, headers> m(
message<true, fail_body, headers> m(
std::piecewise_construct,
std::forward_as_tuple(fc, ios_));
m.method = "GET";
@ -449,7 +449,7 @@ public:
{
// auto content-length HTTP/1.0
{
message_v1<true, string_body, headers> m;
message<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 10;
@ -466,7 +466,7 @@ public:
}
// keep-alive HTTP/1.0
{
message_v1<true, string_body, headers> m;
message<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 10;
@ -484,7 +484,7 @@ public:
}
// upgrade HTTP/1.0
{
message_v1<true, string_body, headers> m;
message<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 10;
@ -502,7 +502,7 @@ public:
}
// no content-length HTTP/1.0
{
message_v1<true, unsized_body, headers> m;
message<true, unsized_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 10;
@ -522,7 +522,7 @@ public:
}
// auto content-length HTTP/1.1
{
message_v1<true, string_body, headers> m;
message<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 11;
@ -539,7 +539,7 @@ public:
}
// close HTTP/1.1
{
message_v1<true, string_body, headers> m;
message<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 11;
@ -561,7 +561,7 @@ public:
}
// upgrade HTTP/1.1
{
message_v1<true, empty_body, headers> m;
message<true, empty_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 11;
@ -576,7 +576,7 @@ public:
}
// no content-length HTTP/1.1
{
message_v1<true, unsized_body, headers> m;
message<true, unsized_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 11;
@ -600,7 +600,7 @@ public:
void testConvert()
{
message_v1<true, string_body, headers> m;
message<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 11;
@ -613,7 +613,7 @@ public:
void testOstream()
{
message_v1<true, string_body, headers> m;
message<true, string_body, headers> m;
m.method = "GET";
m.url = "/";
m.version = 11;

View File

@ -184,7 +184,7 @@ public:
for(n = 0; n < limit; ++n)
{
// valid
http::request_v1<http::empty_body> req;
http::request<http::empty_body> req;
req.method = "GET";
req.url = "/";
req.version = 11;