Distinguish HTTP/1 messages from general HTTP messages:

The version field is moved into message_v1, all public interfaces
are reworked to identify HTTP/1 wire format operations (suffix "_v1")
versus general HTTP.
This commit is contained in:
Vinnie Falco
2016-05-01 11:14:10 -04:00
parent 3af4cf0a28
commit 9e5e16c18d
42 changed files with 724 additions and 697 deletions

View File

@@ -9,13 +9,15 @@
#define BEAST_HTTP_HPP_INCLUDED
#include <beast/http/basic_headers.hpp>
#include <beast/http/basic_parser.hpp>
#include <beast/http/basic_parser_v1.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/error.hpp>
#include <beast/http/headers.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/parse_error.hpp>
#include <beast/http/parser.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/http/reason.hpp>
#include <beast/http/resume_context.hpp>

View File

@@ -5,13 +5,13 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_BASIC_PARSER_HPP
#define BEAST_HTTP_BASIC_PARSER_HPP
#ifndef BEAST_HTTP_BASIC_PARSER_v1_HPP
#define BEAST_HTTP_BASIC_PARSER_v1_HPP
#include <beast/http/message.hpp>
#include <beast/http/parse_error.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/http/detail/basic_parser.hpp>
#include <beast/http/detail/basic_parser_v1.hpp>
#include <beast/type_check.hpp>
#include <boost/asio/buffer.hpp>
#include <array>
@@ -37,7 +37,7 @@ enum values
};
} // parse_flag
/** Parser for producing HTTP requests and responses.
/** Base class for parsing HTTP/1 requests and responses.
During parsing, callbacks will be made to the derived class
if those members are present (detected through SFINAE). The
@@ -84,7 +84,7 @@ enum values
@li `void on_complete(error_code& ec)`
Called when the entire message has been parsed successfully.
At this point, basic_parser::complete() returns `true`, and
At this point, basic_parser_v1::complete() returns `true`, and
the parser is ready to parse another message if keep_alive()
would return `true`.
@@ -109,10 +109,10 @@ enum values
and the error is returned to the caller.
*/
template<bool isRequest, class Derived>
class basic_parser
class basic_parser_v1
{
private:
using self = basic_parser;
using self = basic_parser_v1;
typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
static std::uint64_t constexpr no_content_length =
@@ -237,13 +237,13 @@ private:
public:
/// Copy constructor.
basic_parser(basic_parser const&) = default;
basic_parser_v1(basic_parser_v1 const&) = default;
/// Copy assignment.
basic_parser& operator=(basic_parser const&) = default;
basic_parser_v1& operator=(basic_parser_v1 const&) = default;
/// Constructor
basic_parser()
basic_parser_v1()
{
init(std::integral_constant<bool, isRequest>{});
}
@@ -759,6 +759,6 @@ private:
} // http
} // beast
#include <beast/http/impl/basic_parser.ipp>
#include <beast/http/impl/basic_parser_v1.ipp>
#endif

View File

@@ -0,0 +1,19 @@
//
// 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_BODY_WRITER_HPP
#define BEAST_HTTP_BODY_WRITER_HPP
// Convenience header to include everything necessary for
// declaring an object meeting the BodyWriter requirements.
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <boost/logic/tribool.hpp>
#endif

View File

@@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
#define BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
#define BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
#include <boost/system/error_code.hpp>
#include <boost/utility/string_ref.hpp>

View File

@@ -0,0 +1,43 @@
//
// 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_DETAIL_HAS_CONTENT_LENGTH_HPP
#define BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP
#include <cstdint>
#include <type_traits>
namespace beast {
namespace http {
namespace detail {
template<class T>
class has_content_length_value
{
template<class U, class R = typename std::is_convertible<
decltype(std::declval<U>().content_length()),
std::uint64_t>>
static R check(int);
template <class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
// `true` if `T` meets the requirements.
static bool const value = type::value;
};
// Determines if the writer can provide the content length
template<class T>
using has_content_length =
std::integral_constant<bool,
has_content_length_value<T>::value>;
} // detail
} // http
} // beast
#endif

View File

@@ -1,83 +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_DETAIL_WRITE_PREPARATION_HPP
#define BEAST_HTTP_DETAIL_WRITE_PREPARATION_HPP
#include <beast/http/error.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/streambuf.hpp>
#include <beast/write_streambuf.hpp>
namespace beast {
namespace http {
namespace detail {
template<class T>
class has_content_length_value
{
template<class U, class R = typename std::is_convertible<
decltype(std::declval<U>().content_length()),
std::size_t>>
static R check(int);
template <class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
// `true` if `T` meets the requirements.
static bool const value = type::value;
};
// Determines if the writer can provide the content length
template<class T>
using has_content_length =
std::integral_constant<bool,
has_content_length_value<T>::value>;
template<bool isRequest, class Body, class Headers>
struct write_preparation
{
using headers_type =
basic_headers<std::allocator<char>>;
message<isRequest, Body, Headers> const& msg;
typename Body::writer w;
streambuf sb;
bool chunked;
bool close;
explicit
write_preparation(
message<isRequest, Body, Headers> const& msg_)
: msg(msg_)
, w(msg)
, chunked(rfc2616::token_in_list(
msg.headers["Transfer-Encoding"], "chunked"))
, close(rfc2616::token_in_list(
msg.headers["Connection"], "close") ||
(msg.version < 11 && ! msg.headers.exists(
"Content-Length")))
{
}
void
init(error_code& ec)
{
w.init(ec);
if(ec)
return;
msg.write_firstline(sb);
write_fields(sb, msg.headers);
beast::write(sb, "\r\n");
}
};
} // detail
} // http
} // beast
#endif

View File

@@ -8,8 +8,7 @@
#ifndef BEAST_HTTP_EMPTY_BODY_HPP
#define BEAST_HTTP_EMPTY_BODY_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
@@ -35,9 +34,9 @@ private:
struct reader
{
template<bool isRequest, class Allocator>
template<bool isRequest, class Headers>
explicit
reader(message<isRequest, empty_body, Allocator>&)
reader(message<isRequest, empty_body, Headers>&)
{
}
@@ -49,9 +48,12 @@ private:
struct writer
{
template<bool isRequest, class Allocator>
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<isRequest, empty_body, Allocator> const& m)
writer(message<isRequest, empty_body, Headers> const& m)
{
}

View File

@@ -5,15 +5,15 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_IPP
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
namespace beast {
namespace http {
template<bool isRequest, class Derived>
bool
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
keep_alive() const
{
if(http_major_ > 0 && http_minor_ > 0)
@@ -34,7 +34,7 @@ keep_alive() const
template<bool isRequest, class Derived>
template<class ConstBufferSequence, class>
std::size_t
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
write(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_ConstBufferSequence<ConstBufferSequence>::value,
@@ -51,7 +51,7 @@ write(ConstBufferSequence const& buffers, error_code& ec)
template<bool isRequest, class Derived>
std::size_t
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
write(boost::asio::const_buffer const& buffer, error_code& ec)
{
using beast::http::detail::is_digit;
@@ -1022,7 +1022,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
template<bool isRequest, class Derived>
void
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
write_eof(error_code& ec)
{
switch(s_)
@@ -1042,7 +1042,7 @@ write_eof(error_code& ec)
template<bool isRequest, class Derived>
bool
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
needs_eof(std::true_type) const
{
return false;
@@ -1050,7 +1050,7 @@ needs_eof(std::true_type) const
template<bool isRequest, class Derived>
bool
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
needs_eof(std::false_type) const
{
// See RFC 2616 section 4.4

View File

@@ -5,33 +5,21 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_IMPL_MESSAGE_IPP
#define BEAST_HTTP_IMPL_MESSAGE_IPP
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#include <beast/http/resume_context.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/write_streambuf.hpp>
#include <beast/http/detail/has_content_length.hpp>
#include <beast/type_check.hpp>
#include <beast/http/detail/write_preparation.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/optional.hpp>
#include <condition_variable>
#include <mutex>
#include <stdexcept>
namespace beast {
namespace http {
template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message()
{
}
template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message(request_params params)
message_v1<isRequest, Body, Headers>::
message_v1(request_params params)
{
static_assert(isRequest, "message is not a request");
this->method = params.method;
@@ -40,8 +28,8 @@ message(request_params params)
}
template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message(response_params params)
message_v1<isRequest, Body, Headers>::
message_v1(response_params params)
{
static_assert(! isRequest, "message is not a response");
this->status = params.status;
@@ -49,126 +37,11 @@ message(response_params params)
version = params.version;
}
template<bool isRequest, class Body, class Headers>
template<class Streambuf>
void
message<isRequest, Body, Headers>::
write_firstline(Streambuf& streambuf,
std::true_type) const
{
write(streambuf, this->method);
write(streambuf, " ");
write(streambuf, this->url);
switch(version)
{
case 10:
write(streambuf, " HTTP/1.0\r\n");
break;
case 11:
write(streambuf, " HTTP/1.1\r\n");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, version / 10);
write(streambuf, ".");
write(streambuf, version % 10);
write(streambuf, "\r\n");
break;
}
}
template<bool isRequest, class Body, class Headers>
template<class Streambuf>
void
message<isRequest, Body, Headers>::
write_firstline(Streambuf& streambuf,
std::false_type) const
{
switch(version)
{
case 10:
write(streambuf, "HTTP/1.0 ");
break;
case 11:
write(streambuf, "HTTP/1.1 ");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, version / 10);
write(streambuf, ".");
write(streambuf, version % 10);
write(streambuf, " ");
break;
}
write(streambuf, this->status);
write(streambuf, " ");
write(streambuf, this->reason);
write(streambuf, "\r\n");
}
//------------------------------------------------------------------------------
template<bool isRequest, class Body, class Headers>
void
set_connection(bool keep_alive,
message<isRequest, Body, Headers>& req)
{
if(req.version >= 11)
{
if(! keep_alive)
req.headers.replace("Connection", "close");
else
req.headers.erase("Connection");
}
else
{
if(keep_alive)
req.headers.replace("Connection", "keep-alive");
else
req.headers.erase("Connection");
}
}
template<class Body, class Headers,
class OtherBody, class OtherAllocator>
void
set_connection(bool keep_alive,
message<false, Body, Headers>& resp,
message<true, OtherBody, OtherAllocator> const& req)
{
if(req.version >= 11)
{
if(rfc2616::token_in_list(req["Connection"], "close"))
keep_alive = false;
}
else
{
if(! rfc2616::token_in_list(req["Connection"], "keep-alive"))
keep_alive = false;
}
set_connection(keep_alive, resp);
}
template<class Streambuf, class FieldSequence>
void
write_fields(Streambuf& streambuf, FieldSequence const& fields)
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
//static_assert(is_FieldSequence<FieldSequence>::value,
// "FieldSequence requirements not met");
for(auto const& field : fields)
{
write(streambuf, field.name());
write(streambuf, ": ");
write(streambuf, field.value());
write(streambuf, "\r\n");
}
}
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message<isRequest, Body, Headers> const& msg)
is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
{
if(msg.version >= 11)
{
@@ -185,7 +58,7 @@ is_keep_alive(message<isRequest, Body, Headers> const& msg)
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message<isRequest, Body, Headers> const& msg)
is_upgrade(message_v1<isRequest, Body, Headers> const& msg)
{
if(msg.version < 11)
return false;
@@ -207,14 +80,14 @@ template<bool isRequest, class Body, class Headers>
inline
void
prepare_options(prepare_info& pi,
message<isRequest, Body, Headers>& msg)
message_v1<isRequest, Body, Headers>& msg)
{
}
template<bool isRequest, class Body, class Headers>
void
prepare_option(prepare_info& pi,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
connection value)
{
pi.connection_value = value;
@@ -225,7 +98,7 @@ template<
class Opt, class... Opts>
void
prepare_options(prepare_info& pi,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
Opt&& opt, Opts&&... opts)
{
prepare_option(pi, msg, opt);
@@ -236,7 +109,7 @@ prepare_options(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_content_length(prepare_info& pi,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
std::true_type)
{
typename Body::writer w(msg);
@@ -247,7 +120,7 @@ prepare_content_length(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_content_length(prepare_info& pi,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
std::false_type)
{
pi.content_length = boost::none;
@@ -258,7 +131,7 @@ prepare_content_length(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_connection(
message<isRequest, Body, Headers>& msg)
message_v1<isRequest, Body, Headers>& msg)
{
if(msg.version >= 11)
{
@@ -286,7 +159,7 @@ template<
bool isRequest, class Body, class Headers,
class... Options>
void
prepare(message<isRequest, Body, Headers>& msg,
prepare(message_v1<isRequest, Body, Headers>& msg,
Options&&... options)
{
// VFALCO TODO

View File

@@ -8,6 +8,7 @@
#ifndef BEAST_HTTP_IMPL_READ_IPP_HPP
#define BEAST_HTTP_IMPL_READ_IPP_HPP
#include <beast/http/parser_v1.hpp>
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <cassert>
@@ -26,10 +27,10 @@ class read_op
handler_alloc<char, Handler>;
using parser_type =
parser<isRequest, Body, Headers>;
parser_v1<isRequest, Body, Headers>;
using message_type =
message<isRequest, Body, Headers>;
message_v1<isRequest, Body, Headers>;
struct data
{
@@ -214,14 +215,14 @@ template<class SyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& m,
message_v1<isRequest, Body, Headers>& m,
error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
parser<isRequest, Body, Headers> p;
parser_v1<isRequest, Body, Headers> p;
bool started = false;
for(;;)
{
@@ -264,7 +265,7 @@ template<class AsyncReadStream, class Streambuf,
typename async_completion<
ReadHandler, void(error_code)>::result_type
async_read(AsyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& m,
message_v1<isRequest, Body, Headers>& m,
ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,

View File

@@ -10,12 +10,13 @@
#include <beast/http/resume_context.hpp>
#include <beast/http/detail/chunk_encode.hpp>
#include <beast/http/detail/write_preparation.hpp>
#include <beast/http/detail/has_content_length.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <beast/streambuf.hpp>
#include <beast/type_check.hpp>
#include <beast/write_streambuf.hpp>
#include <boost/asio/write.hpp>
#include <boost/logic/tribool.hpp>
#include <condition_variable>
@@ -29,6 +30,114 @@ namespace http {
namespace detail {
template<class Streambuf, class Body, class Headers>
void
write_firstline(Streambuf& streambuf,
message_v1<true, Body, Headers> const& msg)
{
write(streambuf, msg.method);
write(streambuf, " ");
write(streambuf, msg.url);
switch(msg.version)
{
case 10:
write(streambuf, " HTTP/1.0\r\n");
break;
case 11:
write(streambuf, " HTTP/1.1\r\n");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, msg.version / 10);
write(streambuf, ".");
write(streambuf, msg.version % 10);
write(streambuf, "\r\n");
break;
}
}
template<class Streambuf, class Body, class Headers>
void
write_firstline(Streambuf& streambuf,
message_v1<false, Body, Headers> const& msg)
{
switch(msg.version)
{
case 10:
write(streambuf, "HTTP/1.0 ");
break;
case 11:
write(streambuf, "HTTP/1.1 ");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, msg.version / 10);
write(streambuf, ".");
write(streambuf, msg.version % 10);
write(streambuf, " ");
break;
}
write(streambuf, msg.status);
write(streambuf, " ");
write(streambuf, msg.reason);
write(streambuf, "\r\n");
}
template<class Streambuf, class FieldSequence>
void
write_fields(Streambuf& streambuf, FieldSequence const& fields)
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
//static_assert(is_FieldSequence<FieldSequence>::value,
// "FieldSequence requirements not met");
for(auto const& field : fields)
{
write(streambuf, field.name());
write(streambuf, ": ");
write(streambuf, field.value());
write(streambuf, "\r\n");
}
}
template<bool isRequest, class Body, class Headers>
struct write_preparation
{
using headers_type =
basic_headers<std::allocator<char>>;
message_v1<isRequest, Body, Headers> const& msg;
typename Body::writer w;
streambuf sb;
bool chunked;
bool close;
explicit
write_preparation(
message_v1<isRequest, Body, Headers> const& msg_)
: msg(msg_)
, w(msg)
, chunked(rfc2616::token_in_list(
msg.headers["Transfer-Encoding"], "chunked"))
, close(rfc2616::token_in_list(
msg.headers["Connection"], "close") ||
(msg.version < 11 && ! msg.headers.exists(
"Content-Length")))
{
}
void
init(error_code& ec)
{
w.init(ec);
if(ec)
return;
write_firstline(sb, msg);
write_fields(sb, msg.headers);
beast::write(sb, "\r\n");
}
};
template<class Stream, class Handler,
bool isRequest, class Body, class Headers>
class write_op
@@ -50,7 +159,7 @@ class write_op
template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_,
message<isRequest, Body, Headers> const& m_)
message_v1<isRequest, Body, Headers> const& m_)
: s(s_)
, wp(m_)
, h(std::forward<DeducedHandler>(h_))
@@ -356,7 +465,21 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
error_code ec;
write(stream, msg, ec);
if(ec)
throw boost::system::system_error{ec};
}
template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg,
boost::system::error_code& ec)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
@@ -441,7 +564,7 @@ template<class AsyncWriteStream,
typename async_completion<
WriteHandler, void(error_code)>::result_type
async_write(AsyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
WriteHandler&& handler)
{
static_assert(
@@ -506,7 +629,7 @@ public:
template<bool isRequest, class Body, class Headers>
std::ostream&
operator<<(std::ostream& os,
message<isRequest, Body, Headers> const& msg)
message_v1<isRequest, Body, Headers> const& msg)
{
detail::ostream_SyncStream oss(os);
error_code ec;

View File

@@ -32,24 +32,6 @@ struct response_fields
} // detail
#if ! GENERATING_DOCS
struct request_params
{
std::string method;
std::string url;
int version;
};
struct response_params
{
int status;
std::string reason;
int version;
};
#endif
/** A HTTP message.
A message can be a request or response, depending on the `isRequest`
@@ -70,62 +52,24 @@ struct message
: std::conditional<isRequest,
detail::request_fields, detail::response_fields>::type
{
/** The trait type characterizing the body.
/** The type controlling 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;
/// The type representing the headers.
using headers_type = Headers;
/// Indicates if the message is a request.
using is_request =
std::integral_constant<bool, isRequest>;
int version; // 10 or 11
/// The container holding the headers.
headers_type headers;
/// A container representing the body.
typename Body::value_type body;
message();
message(message&&) = default;
message(message const&) = default;
message& operator=(message&&) = default;
message& operator=(message const&) = default;
/** Construct a HTTP request.
*/
explicit
message(request_params params);
/** Construct a HTTP response.
*/
explicit
message(response_params params);
/// Serialize the request or response line to a Streambuf.
template<class Streambuf>
void
write_firstline(Streambuf& streambuf) const
{
write_firstline(streambuf,
std::integral_constant<bool, isRequest>{});
}
/// Diagnostics only
template<bool, class, class>
friend
std::ostream&
operator<<(std::ostream& os,
message const& m);
private:
template<class Streambuf>
void
write_firstline(Streambuf& streambuf,
std::true_type) const;
template<class Streambuf>
void
write_firstline(Streambuf& streambuf,
std::false_type) const;
};
#if ! GENERATING_DOCS
@@ -142,53 +86,7 @@ using response = message<false, Body, Headers>;
#endif
/// Write a FieldSequence to a Streambuf.
template<class Streambuf, class FieldSequence>
void
write_fields(Streambuf& streambuf, FieldSequence const& fields);
/// Returns `true` if a message indicates a keep alive
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message<isRequest, Body, Headers> const& msg);
/// Returns `true` if a message indicates a HTTP Upgrade request or response
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message<isRequest, Body, Headers> const& msg);
/** Connection prepare options.
These values are used with prepare().
*/
enum class connection
{
/// Indicates the message should specify Connection: close semantics
close,
/// Indicates the message should specify Connection: keep-alive semantics if possible
keep_alive,
/// Indicates the message should specify a Connection: upgrade
upgrade
};
/** Prepare a 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.
*/
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

@@ -0,0 +1,131 @@
//
// 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 <beast/type_check.hpp>
#include <memory>
#include <string>
namespace beast {
namespace http {
#if ! GENERATING_DOCS
struct request_params
{
std::string method;
std::string url;
int version;
};
struct response_params
{
int status;
std::string reason;
int version;
};
#endif
/** 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;
message_v1() = default;
/// Construct a HTTP/1 request.
explicit
message_v1(request_params params);
/// Construct a HTTP/1 response.
explicit
message_v1(response_params params);
};
#if ! GENERATING_DOCS
/// 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>;
#endif
/// 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 `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

@@ -5,12 +5,12 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_PARSER_HPP
#define BEAST_HTTP_PARSER_HPP
#ifndef BEAST_HTTP_PARSER_V1_HPP
#define BEAST_HTTP_PARSER_V1_HPP
#include <beast/http/basic_parser.hpp>
#include <beast/http/basic_parser_v1.hpp>
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <boost/optional.hpp>
#include <functional>
#include <string>
@@ -35,15 +35,20 @@ struct parser_response
} // detail
/** 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`.
*/
template<bool isRequest, class Body, class Headers>
class parser
: public basic_parser<isRequest,
parser<isRequest, Body, Headers>>
class parser_v1
: public basic_parser_v1<isRequest,
parser_v1<isRequest, Body, Headers>>
, private std::conditional<isRequest,
detail::parser_request, detail::parser_response>::type
{
using message_type =
message<isRequest, Body, Headers>;
message_v1<isRequest, Body, Headers>;
std::string field_;
std::string value_;
@@ -51,9 +56,9 @@ class parser
typename message_type::body_type::reader r_;
public:
parser(parser&&) = default;
parser_v1(parser_v1&&) = default;
parser()
parser_v1()
: r_(m_)
{
}
@@ -65,7 +70,7 @@ public:
}
private:
friend class basic_parser<isRequest, parser>;
friend class basic_parser_v1<isRequest, parser_v1>;
void flush()
{

View File

@@ -8,16 +8,16 @@
#ifndef BEAST_HTTP_READ_HPP
#define BEAST_HTTP_READ_HPP
#include <beast/async_completion.hpp>
#include <beast/http/error.hpp>
#include <beast/http/parser.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/async_completion.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>
namespace beast {
namespace http {
/** Read a HTTP message from a stream.
/** Read a HTTP/1 message from a stream.
@param stream The stream to read the message from.
@@ -35,7 +35,7 @@ template<class SyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& msg)
message_v1<isRequest, Body, Headers>& msg)
{
error_code ec;
read(stream, streambuf, msg, ec);
@@ -61,7 +61,7 @@ template<class SyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
error_code& ec);
/** Start reading a HTTP message from a stream asynchronously.
@@ -97,7 +97,7 @@ typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(AsyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
ReadHandler&& handler);
} // http

View File

@@ -8,8 +8,7 @@
#ifndef BEAST_HTTP_STREAMBUF_BODY_HPP
#define BEAST_HTTP_STREAMBUF_BODY_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/streambuf.hpp>
#include <memory>
@@ -59,10 +58,13 @@ private:
Streambuf const& body_;
public:
template<bool isRequest, class Allocator>
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<isRequest, basic_streambuf_body,
Allocator> const& m)
writer(message<
isRequest, basic_streambuf_body, Headers> const& m)
: body_(m.body)
{
}

View File

@@ -8,9 +8,7 @@
#ifndef BEAST_HTTP_STRING_BODY_HPP
#define BEAST_HTTP_STRING_BODY_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/streambuf.hpp>
#include <memory>
@@ -58,9 +56,13 @@ private:
value_type const& body_;
public:
template<bool isRequest, class Allocator>
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<isRequest, string_body, Allocator> const& msg)
writer(message<
isRequest, string_body, Headers> const& msg)
: body_(msg.body)
{
}

View File

@@ -9,9 +9,8 @@
#define BEAST_HTTP_WRITE_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/async_completion.hpp>
#include <beast/type_check.hpp>
#include <boost/system/error_code.hpp>
#include <ostream>
#include <type_traits>
@@ -19,7 +18,7 @@
namespace beast {
namespace http {
/** Write a HTTP message to a stream.
/** Write a HTTP/1 message to a stream.
@param stream The stream to send the message on.
@@ -31,15 +30,9 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg)
{
error_code ec;
write(stream, msg, ec);
if(ec)
throw boost::system::system_error{ec};
}
message_v1<isRequest, Body, Headers> const& msg);
/** Write a HTTP message to a stream.
/** Write a HTTP/1 message to a stream.
@param stream The stream to send the message on.
@@ -51,10 +44,10 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
error_code& ec);
/** Start writing a HTTP message to a stream asynchronously.
/** Start writing a HTTP/1 message to a stream asynchronously.
@param stream The stream to send the message on.
@@ -84,12 +77,12 @@ typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
async_write(AsyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
WriteHandler&& handler);
/** Serialize a message to an ostream.
/** Serialize a HTTP/1 message to an ostream.
The function converts the message to its HTTP/1.* serialized
The function converts the message to its HTTP/1 serialized
representation and stores the result in the output stream.
@param os The ostream to write to.
@@ -99,7 +92,7 @@ async_write(AsyncWriteStream& stream,
template<bool isRequest, class Body, class Headers>
std::ostream&
operator<<(std::ostream& os,
message<isRequest, Body, Headers> const& msg);
message_v1<isRequest, Body, Headers> const& msg);
} // http
} // beast

View File

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

View File

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

View File

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

View File

@@ -241,7 +241,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
stream_.buffer().commit(buffer_copy(
stream_.buffer().prepare(
buffer_size(buffers)), buffers));
http::request<http::empty_body> m;
http::request_v1<http::empty_body> m;
http::read(next_layer(), stream_.buffer(), m, ec);
if(ec)
return;
@@ -272,7 +272,7 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
accept(http::message<true, Body, Headers> const& request)
accept(http::request_v1<Body, Headers> const& request)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
@@ -285,12 +285,12 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
accept(http::message<true, Body, Headers> const& req,
accept(http::request_v1<Body, Headers> const& req,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
auto resp = build_response(req);
auto const resp = build_response(req);
http::write(stream_, resp, ec);
if(resp.status != 101)
{
@@ -307,7 +307,7 @@ template<class Body, class Headers, class AcceptHandler>
typename async_completion<
AcceptHandler, void(error_code)>::result_type
stream<NextLayer>::
async_accept(http::message<true, Body, Headers> const& req,
async_accept(http::request_v1<Body, Headers> const& req,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
@@ -348,7 +348,7 @@ handshake(boost::string_ref const& host,
build_request(host, resource, key), ec);
if(ec)
return;
http::response<http::string_body> resp;
http::response_v1<http::string_body> resp;
http::read(next_layer(), stream_.buffer(), resp, ec);
if(ec)
return;
@@ -826,12 +826,12 @@ async_write_frame(bool fin,
//------------------------------------------------------------------------------
template<class NextLayer>
http::request<http::empty_body>
http::request_v1<http::empty_body>
stream<NextLayer>::
build_request(boost::string_ref const& host,
boost::string_ref const& resource, std::string& key)
{
http::request<http::empty_body> req;
http::request_v1<http::empty_body> req;
req.url = "/";
req.version = 11;
req.method = "GET";
@@ -847,14 +847,14 @@ build_request(boost::string_ref const& host,
template<class NextLayer>
template<class Body, class Headers>
http::response<http::string_body>
http::response_v1<http::string_body>
stream<NextLayer>::
build_response(http::message<true, Body, Headers> const& req)
build_response(http::request_v1<Body, Headers> const& req)
{
auto err =
[&](std::string const& text)
{
http::response<http::string_body> resp(
http::response_v1<http::string_body> resp(
{400, http::reason_string(400), req.version});
resp.body = text;
// VFALCO TODO respect keep-alive here
@@ -881,7 +881,7 @@ build_response(http::message<true, Body, Headers> const& req)
if(! rfc2616::token_in_list(
req.headers["Upgrade"], "websocket"))
return err("Missing websocket Upgrade token");
http::response<http::string_body> resp(
http::response_v1<http::string_body> resp(
{101, http::reason_string(101), req.version});
resp.headers.insert("Upgrade", "websocket");
{
@@ -901,7 +901,7 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
do_response(http::message<false, Body, Headers> const& resp,
do_response(http::response_v1<Body, Headers> const& resp,
boost::string_ref const& key, error_code& ec)
{
// VFALCO Review these error codes

View File

@@ -10,11 +10,11 @@
#include <beast/websocket/option.hpp>
#include <beast/websocket/detail/stream_base.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/string_body.hpp>
#include <beast/streambuf_readstream.hpp>
#include <beast/async_completion.hpp>
#include <beast/detail/get_lowest_layer.hpp>
#include <beast/http/message.hpp>
#include <beast/http/string_body.hpp>
#include <boost/asio.hpp>
#include <boost/utility/string_ref.hpp>
#include <algorithm>
@@ -495,8 +495,7 @@ public:
// VFALCO TODO This should also take a streambuf with any leftover bytes.
template<class Body, class Headers>
void
accept(http::message<true,
Body, Headers> const& request);
accept(http::request_v1<Body, Headers> const& request);
/** Respond to a WebSocket HTTP Upgrade request
@@ -525,8 +524,8 @@ public:
*/
template<class Body, class Headers>
void
accept(http::message<true,
Body, Headers> const& request, error_code& ec);
accept(http::request_v1<Body, Headers> const& request,
error_code& ec);
/** Start reading and responding to a WebSocket HTTP Upgrade request.
@@ -560,8 +559,8 @@ public:
template<class Body, class Headers, class AcceptHandler>
typename async_completion<
AcceptHandler, void(error_code)>::result_type
async_accept(http::message<true,
Body, Headers> const& request, AcceptHandler&& handler);
async_accept(http::request_v1<Body, Headers> const& request,
AcceptHandler&& handler);
/** Send a WebSocket Upgrade request.
@@ -1129,18 +1128,18 @@ private:
template<class Buffers, class Handler> class write_op;
template<class Buffers, class Handler> class write_frame_op;
http::request<http::empty_body>
http::request_v1<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<http::string_body>
build_response(http::message<true, Body, Headers> const& req);
http::response_v1<http::string_body>
build_response(http::request_v1<Body, Headers> const& req);
template<class Body, class Headers>
void
do_response(http::message<false, Body, Headers> const& resp,
do_response(http::response_v1<Body, Headers> const& resp,
boost::string_ref const& key, error_code& ec);
void