forked from boostorg/beast
Refactor HTTP serialization (API Change):
A new class `serializer` is introduced to permit incremental serialization of HTTP messages. Existing free functions are re-implemented in terms of this new class. * The BodyReader concept is refined to support a greater variety of strategies for providing buffers representing the body to the serialization algorithms. * Added buffer_body, a new model of Body which allows the caller to provide a series of owned buffers using their own serialization loop. * Added empty_body, a model of Body which is for serialization only, to represent HTTP messages with no content body. * Removed overloads of write and async_write which send only the HTTP header. * Removed public interfaces for performing low-level chunk encoding.
This commit is contained in:
@@ -11,8 +11,9 @@
|
||||
#include <beast/config.hpp>
|
||||
|
||||
#include <beast/http/basic_parser.hpp>
|
||||
#include <beast/http/chunk_encode.hpp>
|
||||
#include <beast/http/buffer_body.hpp>
|
||||
#include <beast/http/dynamic_body.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/fields.hpp>
|
||||
#include <beast/http/header_parser.hpp>
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 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_BUFFER_BODY_HPP
|
||||
#define BEAST_HTTP_BUFFER_BODY_HPP
|
||||
|
||||
#include <beast/http/concepts.hpp>
|
||||
#include <beast/http/error.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** A serializable body represented by caller provided buffers.
|
||||
|
||||
This body type permits incremental message sending of caller
|
||||
provided buffers using a @ref serializer.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
template<class SyncWriteStream>
|
||||
void send(SyncWriteStream& stream)
|
||||
{
|
||||
...
|
||||
}
|
||||
@endcode
|
||||
|
||||
@tparam isDeferred A `bool` which, when set to `true`,
|
||||
indicates to the serialization implementation that it should
|
||||
send the entire HTTP Header before attempting to acquire
|
||||
buffers representing the body.
|
||||
|
||||
@tparam ConstBufferSequence The type of buffer sequence
|
||||
stored in the body by the caller.
|
||||
*/
|
||||
template<
|
||||
bool isDeferred,
|
||||
class ConstBufferSequence>
|
||||
struct buffer_body
|
||||
{
|
||||
static_assert(is_const_buffer_sequence<ConstBufferSequence>::value,
|
||||
"ConstBufferSequence requirements not met");
|
||||
|
||||
/** The type of the body member when used in a message.
|
||||
|
||||
When engaged, the first element of the pair represents
|
||||
the current buffer sequence to be written.
|
||||
|
||||
The second element of the pair indicates whether or not
|
||||
additional buffers will be available. A value of `false`
|
||||
indicates the end of the message body.
|
||||
|
||||
If the buffer in the value is disengaged, and the second
|
||||
element of the pair is `true`, @ref serializer operations
|
||||
will return @ref http::error::need_more. This signals the
|
||||
calling code that a new buffer should be placed into the
|
||||
body, or that the caller should indicate that no more
|
||||
buffers will be available.
|
||||
*/
|
||||
using value_type =
|
||||
std::pair<boost::optional<ConstBufferSequence>, bool>;
|
||||
|
||||
#if BEAST_DOXYGEN
|
||||
/// The algorithm used when serializing this body
|
||||
using writer = implementation_defined;
|
||||
#else
|
||||
class writer
|
||||
{
|
||||
bool toggle_ = false;
|
||||
value_type const& body_;
|
||||
|
||||
public:
|
||||
using is_deferred =
|
||||
std::integral_constant<bool, isDeferred>;
|
||||
|
||||
using const_buffers_type = ConstBufferSequence;
|
||||
|
||||
template<bool isRequest, class Fields>
|
||||
explicit
|
||||
writer(message<isRequest, buffer_body,
|
||||
Fields> const& msg)
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
boost::optional<std::pair<ConstBufferSequence, bool>>
|
||||
get(error_code& ec)
|
||||
{
|
||||
if(toggle_)
|
||||
{
|
||||
if(body_.second)
|
||||
{
|
||||
toggle_ = false;
|
||||
ec = error::need_more;
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
if(body_.first)
|
||||
{
|
||||
toggle_ = true;
|
||||
return {{*body_.first, body_.second}};
|
||||
}
|
||||
if(body_.second)
|
||||
ec = error::need_more;
|
||||
return boost::none;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 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_CHUNK_ENCODE_HPP
|
||||
#define BEAST_HTTP_CHUNK_ENCODE_HPP
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** Returns a chunk-encoded ConstBufferSequence.
|
||||
|
||||
This returns a buffer sequence representing the
|
||||
first chunk of a chunked transfer coded body.
|
||||
|
||||
@param fin `true` if this is the last chunk.
|
||||
|
||||
@param buffers The input buffer sequence.
|
||||
|
||||
@return A chunk-encoded ConstBufferSequence representing the input.
|
||||
|
||||
@see <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
#if BEAST_DOXYGEN
|
||||
implementation_defined
|
||||
#else
|
||||
beast::buffers_view<
|
||||
detail::chunk_encode_delim,
|
||||
ConstBufferSequence,
|
||||
boost::asio::const_buffers_1>
|
||||
#endif
|
||||
chunk_encode(bool fin, ConstBufferSequence const& buffers)
|
||||
{
|
||||
using boost::asio::buffer_size;
|
||||
return buffer_cat(
|
||||
detail::chunk_encode_delim{buffer_size(buffers)},
|
||||
buffers,
|
||||
fin ? boost::asio::const_buffers_1{"\r\n0\r\n\r\n", 7}
|
||||
: boost::asio::const_buffers_1{"\r\n", 2});
|
||||
}
|
||||
|
||||
/** Returns a chunked encoding final chunk.
|
||||
|
||||
@see <a href=https://tools.ietf.org/html/rfc7230#section-4.1.3>rfc7230 section 4.1.3</a>
|
||||
*/
|
||||
inline
|
||||
#if BEAST_DOXYGEN
|
||||
implementation_defined
|
||||
#else
|
||||
boost::asio::const_buffers_1
|
||||
#endif
|
||||
chunk_encode_final()
|
||||
{
|
||||
return boost::asio::const_buffers_1{"0\r\n\r\n", 5};
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
#include <beast/core/type_traits.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
@@ -19,8 +20,18 @@
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
template<bool, class, class>
|
||||
struct message;
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct fields_model
|
||||
{
|
||||
string_view method() const;
|
||||
string_view reason() const;
|
||||
string_view target() const;
|
||||
};
|
||||
|
||||
struct write_function
|
||||
{
|
||||
template<class ConstBufferSequence>
|
||||
@@ -50,43 +61,6 @@ struct has_content_length<T, beast::detail::void_t<decltype(
|
||||
"Writer::content_length requirements not met");
|
||||
};
|
||||
|
||||
template<class T, class M>
|
||||
class is_Writer
|
||||
{
|
||||
template<class U, class R = decltype(
|
||||
std::declval<U>().init(std::declval<error_code&>()),
|
||||
std::true_type{})>
|
||||
static R check1(int);
|
||||
template<class>
|
||||
static std::false_type check1(...);
|
||||
using type1 = decltype(check1<T>(0));
|
||||
|
||||
// VFALCO This is unfortunate, we have to provide the template
|
||||
// argument type because this is not a deduced context?
|
||||
//
|
||||
template<class U, class R =
|
||||
std::is_convertible<decltype(
|
||||
std::declval<U>().template write<detail::write_function>(
|
||||
std::declval<error_code&>(),
|
||||
std::declval<detail::write_function>()))
|
||||
, bool>>
|
||||
static R check2(int);
|
||||
template<class>
|
||||
static std::false_type check2(...);
|
||||
using type2 = decltype(check2<T>(0));
|
||||
|
||||
public:
|
||||
static_assert(std::is_same<
|
||||
typename M::body_type::writer, T>::value,
|
||||
"Mismatched writer and message");
|
||||
|
||||
using type = std::integral_constant<bool,
|
||||
std::is_nothrow_constructible<T, M const&>::value
|
||||
&& type1::value
|
||||
&& type2::value
|
||||
>;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
/// Determine if `T` meets the requirements of @b Body.
|
||||
@@ -173,18 +147,34 @@ struct is_Reader<T, M, beast::detail::void_t<decltype(
|
||||
};
|
||||
#endif
|
||||
|
||||
/** Determine if `T` meets the requirements of @b Writer for `M`.
|
||||
/** Determine if a @b Body type has a writer which meets requirements.
|
||||
|
||||
@tparam T The type to test.
|
||||
|
||||
@tparam M The message type to test with, which must be of
|
||||
type `message`.
|
||||
@tparam T The body type to test.
|
||||
*/
|
||||
template<class T, class M>
|
||||
#if BEAST_DOXYGEN
|
||||
template<class T>
|
||||
struct is_Writer : std::integral_constant<bool, ...> {};
|
||||
#else
|
||||
using is_Writer = typename detail::is_Writer<T, M>::type;
|
||||
template<class T, class = void>
|
||||
struct is_Writer : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_Writer<T, beast::detail::void_t<
|
||||
typename T::writer,
|
||||
typename T::writer::const_buffers_type,
|
||||
decltype(
|
||||
std::declval<typename T::writer&>().init(std::declval<error_code&>()),
|
||||
std::declval<boost::optional<std::pair<
|
||||
typename T::writer::const_buffers_type, bool>>&>() =
|
||||
std::declval<typename T::writer>().get(std::declval<error_code&>()),
|
||||
(void)0)>> : std::integral_constant<bool,
|
||||
is_const_buffer_sequence<
|
||||
typename T::writer::const_buffers_type>::value &&
|
||||
std::is_constructible<typename T::writer,
|
||||
message<true, T, detail::fields_model> const& >::value
|
||||
>
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
} // http
|
||||
|
||||
@@ -17,20 +17,22 @@ namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
class chunk_encode_delim
|
||||
/** A buffer sequence containing a chunk-encoding header
|
||||
*/
|
||||
class chunk_header
|
||||
{
|
||||
boost::asio::const_buffer cb_;
|
||||
|
||||
// Storage for the longest hex string we might need, plus delimiters.
|
||||
std::array<char, 2 * sizeof(std::size_t) + 2> buf_;
|
||||
// Storage for the longest hex string we might need
|
||||
char buf_[2 * sizeof(std::size_t)];
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
copy(chunk_encode_delim const& other);
|
||||
copy(chunk_header const& other);
|
||||
|
||||
template<class = void>
|
||||
void
|
||||
setup(std::size_t n);
|
||||
prepare_impl(std::size_t n);
|
||||
|
||||
template<class OutIter>
|
||||
static
|
||||
@@ -55,15 +57,27 @@ public:
|
||||
|
||||
using const_iterator = value_type const*;
|
||||
|
||||
chunk_encode_delim(chunk_encode_delim const& other)
|
||||
/** Constructor (default)
|
||||
|
||||
Default-constructed chunk headers are in an
|
||||
undefined state.
|
||||
*/
|
||||
chunk_header() = default;
|
||||
|
||||
/// Copy constructor
|
||||
chunk_header(chunk_header const& other)
|
||||
{
|
||||
copy(other);
|
||||
}
|
||||
|
||||
/** Construct a chunk header
|
||||
|
||||
@param n The number of octets in this chunk.
|
||||
*/
|
||||
explicit
|
||||
chunk_encode_delim(std::size_t n)
|
||||
chunk_header(std::size_t n)
|
||||
{
|
||||
setup(n);
|
||||
prepare_impl(n);
|
||||
}
|
||||
|
||||
const_iterator
|
||||
@@ -77,31 +91,63 @@ public:
|
||||
{
|
||||
return begin() + 1;
|
||||
}
|
||||
|
||||
void
|
||||
prepare(std::size_t n)
|
||||
{
|
||||
prepare_impl(n);
|
||||
}
|
||||
};
|
||||
|
||||
template<class>
|
||||
void
|
||||
chunk_encode_delim::
|
||||
copy(chunk_encode_delim const& other)
|
||||
chunk_header::
|
||||
copy(chunk_header const& other)
|
||||
{
|
||||
using boost::asio::buffer_copy;
|
||||
auto const n =
|
||||
boost::asio::buffer_size(other.cb_);
|
||||
buf_ = other.buf_;
|
||||
cb_ = boost::asio::const_buffer(
|
||||
&buf_[buf_.size() - n], n);
|
||||
auto const mb = boost::asio::mutable_buffers_1(
|
||||
&buf_[sizeof(buf_) - n], n);
|
||||
cb_ = *mb.begin();
|
||||
buffer_copy(mb,
|
||||
boost::asio::const_buffers_1(other.cb_));
|
||||
}
|
||||
|
||||
template<class>
|
||||
void
|
||||
chunk_encode_delim::
|
||||
setup(std::size_t n)
|
||||
chunk_header::
|
||||
prepare_impl(std::size_t n)
|
||||
{
|
||||
buf_[buf_.size() - 2] = '\r';
|
||||
buf_[buf_.size() - 1] = '\n';
|
||||
auto it = to_hex(buf_.end() - 2, n);
|
||||
auto const end = &buf_[sizeof(buf_)];
|
||||
auto it = to_hex(end, n);
|
||||
cb_ = boost::asio::const_buffer{&*it,
|
||||
static_cast<std::size_t>(
|
||||
std::distance(it, buf_.end()))};
|
||||
std::distance(it, end))};
|
||||
}
|
||||
|
||||
/// Returns a buffer sequence holding a CRLF for chunk encoding
|
||||
inline
|
||||
boost::asio::const_buffers_1
|
||||
chunk_crlf()
|
||||
{
|
||||
return {"\r\n", 2};
|
||||
}
|
||||
|
||||
/// Returns a buffer sequence holding a CRLF then final chunk
|
||||
inline
|
||||
boost::asio::const_buffers_1
|
||||
chunk_crlf_final()
|
||||
{
|
||||
return {"\r\n0\r\n\r\n", 7};
|
||||
}
|
||||
|
||||
/// Returns a buffer sequence holding a final chunk header
|
||||
inline
|
||||
boost::asio::const_buffers_1
|
||||
chunk_final()
|
||||
{
|
||||
return {"0\r\n", 3};
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 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_TYPE_TRAITS_HPP
|
||||
#define BEAST_HTTP_DETAIL_TYPE_TRAITS_HPP
|
||||
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
template<bool isRequest, class Fields>
|
||||
struct header;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class T>
|
||||
class is_header_impl
|
||||
{
|
||||
template<bool b, class F>
|
||||
static std::true_type check(
|
||||
header<b, F> const*);
|
||||
static std::false_type check(...);
|
||||
public:
|
||||
using type = decltype(check((T*)0));
|
||||
};
|
||||
|
||||
template<class T>
|
||||
using is_header = typename is_header_impl<T>::type;
|
||||
|
||||
} // detail
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -12,24 +12,26 @@
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** A message body represented by a @b DynamicBuffer
|
||||
/** An HTTP message body represented by a @b DynamicBuffer.
|
||||
|
||||
Meets the requirements of @b Body.
|
||||
*/
|
||||
template<class DynamicBuffer>
|
||||
struct basic_dynamic_body
|
||||
{
|
||||
/// The type of the `message::body` member
|
||||
/// The type of the body member when used in a message.
|
||||
using value_type = DynamicBuffer;
|
||||
|
||||
#if BEAST_DOXYGEN
|
||||
private:
|
||||
#endif
|
||||
|
||||
/// The algorithm used when parsing this body.
|
||||
using reader = implementation_defined;
|
||||
#else
|
||||
class reader
|
||||
{
|
||||
value_type& body_;
|
||||
@@ -75,40 +77,48 @@ private:
|
||||
{
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if BEAST_DOXYGEN
|
||||
/// The algorithm used when serializing this body.
|
||||
using writer = implementation_defined;
|
||||
#else
|
||||
class writer
|
||||
{
|
||||
DynamicBuffer const& body_;
|
||||
|
||||
public:
|
||||
using is_deferred = std::false_type;
|
||||
|
||||
using const_buffers_type =
|
||||
typename DynamicBuffer::const_buffers_type;
|
||||
|
||||
template<bool isRequest, class Fields>
|
||||
explicit
|
||||
writer(message<
|
||||
isRequest, basic_dynamic_body, Fields> const& m) noexcept
|
||||
isRequest, basic_dynamic_body, Fields> const& m)
|
||||
: body_(m.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec) noexcept
|
||||
init(error_code&)
|
||||
{
|
||||
beast::detail::ignore_unused(ec);
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const noexcept
|
||||
content_length() const
|
||||
{
|
||||
return body_.size();
|
||||
}
|
||||
|
||||
template<class WriteFunction>
|
||||
bool
|
||||
write(error_code&, WriteFunction&& wf) noexcept
|
||||
boost::optional<std::pair<const_buffers_type, bool>>
|
||||
get(error_code& ec)
|
||||
{
|
||||
wf(body_.data());
|
||||
return true;
|
||||
return {{body_.data(), false}};
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
/** A dynamic message body represented by a @ref multi_buffer
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// Copyright (c) 2013-2017 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_EMPTY_BODY_HPP
|
||||
#define BEAST_HTTP_EMPTY_BODY_HPP
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** An empty message body
|
||||
|
||||
Meets the requirements of @b Body.
|
||||
|
||||
@note This body type may only be written, not read.
|
||||
*/
|
||||
struct empty_body
|
||||
{
|
||||
/// The type of the body member when used in a message.
|
||||
struct value_type
|
||||
{
|
||||
};
|
||||
|
||||
#if BEAST_DOXYGEN
|
||||
/// The algorithm used when serializing this body.
|
||||
using writer = implementation_defined;
|
||||
#else
|
||||
struct writer
|
||||
{
|
||||
using is_deferred = std::false_type;
|
||||
|
||||
using const_buffers_type =
|
||||
boost::asio::null_buffers;
|
||||
|
||||
template<bool isRequest, class Fields>
|
||||
explicit
|
||||
writer(message<
|
||||
isRequest, empty_body, Fields> const&)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code&)
|
||||
{
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
boost::optional<std::pair<const_buffers_type, bool>>
|
||||
get(error_code& ec)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
#endif
|
||||
@@ -33,6 +33,17 @@ enum class error
|
||||
*/
|
||||
partial_message,
|
||||
|
||||
/** Additional buffers are required.
|
||||
|
||||
This error is generated during serialization of HTTP
|
||||
messages using the @ref buffer_body representation.
|
||||
It indicates to the caller that an additional buffer
|
||||
sequence should be placed into the body, or that the
|
||||
caller should indicate that there are no more bytes
|
||||
remaining in the body to serialize.
|
||||
*/
|
||||
need_more,
|
||||
|
||||
/** Buffer maximum exceeded.
|
||||
|
||||
This error is returned when reading HTTP content
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
default:
|
||||
case error::end_of_stream: return "end of stream";
|
||||
case error::partial_message: return "partial message";
|
||||
case error::need_more: return "need more";
|
||||
case error::buffer_overflow: return "buffer overflow";
|
||||
case error::bad_line_ending: return "bad line ending";
|
||||
case error::bad_method: return "bad method";
|
||||
|
||||
@@ -163,8 +163,7 @@ prepare(message<isRequest, Body, Fields>& msg,
|
||||
"Body requirements not met");
|
||||
static_assert(has_writer<Body>::value,
|
||||
"Body has no writer");
|
||||
static_assert(is_Writer<typename Body::writer,
|
||||
message<isRequest, Body, Fields>>::value,
|
||||
static_assert(is_Writer<Body>::value,
|
||||
"Writer requirements not met");
|
||||
detail::prepare_info pi;
|
||||
detail::prepare_content_length(pi, msg,
|
||||
|
||||
+766
-391
File diff suppressed because it is too large
Load Diff
@@ -13,25 +13,27 @@
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/core/detail/type_traits.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** A Body represented by a std::string.
|
||||
/** An HTTP message body represented by a `std::string`.
|
||||
|
||||
Meets the requirements of @b Body.
|
||||
*/
|
||||
struct string_body
|
||||
{
|
||||
/// The type of the `message::body` member
|
||||
/// The type of the body member when used in a message.
|
||||
using value_type = std::string;
|
||||
|
||||
#if BEAST_DOXYGEN
|
||||
private:
|
||||
#endif
|
||||
|
||||
/// The algorithm used when parsing this body.
|
||||
using reader = implementation_defined;
|
||||
#else
|
||||
class reader
|
||||
{
|
||||
value_type& body_;
|
||||
@@ -88,40 +90,50 @@ private:
|
||||
body_.resize(len_);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if BEAST_DOXYGEN
|
||||
/// The algorithm used when serializing this body.
|
||||
using writer = implementation_defined;
|
||||
#else
|
||||
class writer
|
||||
{
|
||||
value_type const& body_;
|
||||
|
||||
public:
|
||||
using is_deferred = std::false_type;
|
||||
|
||||
using const_buffers_type =
|
||||
boost::asio::const_buffers_1;
|
||||
|
||||
template<bool isRequest, class Fields>
|
||||
explicit
|
||||
writer(message<
|
||||
isRequest, string_body, Fields> const& msg) noexcept
|
||||
isRequest, string_body, Fields> const& msg)
|
||||
: body_(msg.body)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
init(error_code& ec) noexcept
|
||||
init(error_code& ec)
|
||||
{
|
||||
beast::detail::ignore_unused(ec);
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
content_length() const noexcept
|
||||
content_length() const
|
||||
{
|
||||
return body_.size();
|
||||
}
|
||||
|
||||
template<class WriteFunction>
|
||||
bool
|
||||
write(error_code&, WriteFunction&& wf) noexcept
|
||||
boost::optional<std::pair<const_buffers_type, bool>>
|
||||
get(error_code& ec)
|
||||
{
|
||||
wf(boost::asio::buffer(body_));
|
||||
return true;
|
||||
return {{const_buffers_type{
|
||||
body_.data(), body_.size()}, false}};
|
||||
}
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // http
|
||||
|
||||
+380
-83
@@ -9,127 +9,424 @@
|
||||
#define BEAST_HTTP_WRITE_HPP
|
||||
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/core/buffer_cat.hpp>
|
||||
#include <beast/core/consuming_buffers.hpp>
|
||||
#include <beast/core/multi_buffer.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/detail/chunk_encode.hpp>
|
||||
#include <beast/core/error.hpp>
|
||||
#include <beast/core/async_result.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
/** Write a HTTP/1 header to a stream.
|
||||
/** A chunk decorator which does nothing.
|
||||
|
||||
This function is used to synchronously write a header to
|
||||
a stream. The call will block until one of the following
|
||||
conditions is true:
|
||||
When selected as a chunk decorator, objects of this type
|
||||
affect the output of messages specifying chunked
|
||||
transfer encodings as follows:
|
||||
|
||||
@li The entire header is written.
|
||||
@li chunk headers will have empty chunk extensions, and
|
||||
|
||||
@li An error occurs.
|
||||
@li final chunks will have an empty set of trailers.
|
||||
|
||||
This operation is implemented in terms of one or more calls
|
||||
to the stream's `write_some` function.
|
||||
|
||||
Regardless of the semantic meaning of the header (for example,
|
||||
specifying "Content-Length: 0" and "Connection: close"),
|
||||
this function will not return `boost::asio::error::eof`.
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b SyncWriteStream concept.
|
||||
|
||||
@param msg The header to write.
|
||||
|
||||
@throws system_error Thrown on failure.
|
||||
@see @ref serializer
|
||||
*/
|
||||
template<class SyncWriteStream,
|
||||
bool isRequest, class Fields>
|
||||
void
|
||||
write(SyncWriteStream& stream,
|
||||
header<isRequest, Fields> const& msg);
|
||||
struct empty_decorator
|
||||
{
|
||||
template<class ConstBufferSequence>
|
||||
string_view
|
||||
operator()(ConstBufferSequence const&) const
|
||||
{
|
||||
return {"\r\n"};
|
||||
}
|
||||
|
||||
/** Write a HTTP/1 header to a stream.
|
||||
string_view
|
||||
operator()(boost::asio::null_buffers) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
This function is used to synchronously write a header to
|
||||
a stream. The call will block until one of the following
|
||||
conditions is true:
|
||||
/** Provides stream-oriented HTTP message serialization functionality.
|
||||
|
||||
@li The entire header is written.
|
||||
Objects of this type may be used to perform synchronous or
|
||||
asynchronous serialization of an HTTP message on a stream.
|
||||
Unlike functions such as @ref write or @ref async_write,
|
||||
the stream operations provided here guarantee that bounded
|
||||
work will be performed. This is accomplished by making one
|
||||
or more calls to the underlying stream's `write_some` or
|
||||
`async_write_some` member functions. In order to fully
|
||||
serialize the message, multiple calls are required.
|
||||
|
||||
@li An error occurs.
|
||||
The ability to incrementally serialize a message, peforming
|
||||
bounded work at each iteration is useful in many scenarios,
|
||||
such as:
|
||||
|
||||
This operation is implemented in terms of one or more calls
|
||||
to the stream's `write_some` function.
|
||||
@li Setting consistent, per-call timeouts
|
||||
|
||||
Regardless of the semantic meaning of the header (for example,
|
||||
specifying "Content-Length: 0" and "Connection: close"),
|
||||
this function will not return `boost::asio::error::eof`.
|
||||
@li Efficiently relaying body content from another stream
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b SyncWriteStream concept.
|
||||
@li Performing application-layer flow control
|
||||
|
||||
@param msg The header to write.
|
||||
To use this class, construct an instance with the message
|
||||
to be sent. To make it easier to declare the type, the
|
||||
helper function @ref make_write_stream is provided:
|
||||
|
||||
@param ec Set to the error, if any occurred.
|
||||
The implementation will automatically perform chunk encoding
|
||||
if the contents of the message indicate that chunk encoding
|
||||
is required. If the semantics of the message indicate that
|
||||
the connection should be closed after the message is sent,
|
||||
the error delivered from stream operations will be
|
||||
`boost::asio::error::eof`.
|
||||
|
||||
@code
|
||||
template<class Stream>
|
||||
void send(Stream& stream, request<string_body> const& msg)
|
||||
{
|
||||
serializer<true, string_body, fields> w{msg};
|
||||
do
|
||||
{
|
||||
w.write_some();
|
||||
}
|
||||
while(! w.is_done());
|
||||
}
|
||||
@endcode
|
||||
|
||||
Upon construction, an optional chunk decorator may be
|
||||
specified. This decorator is a function object called with
|
||||
each buffer sequence of the body when the chunked transfer
|
||||
encoding is indicate in the message header. The decorator
|
||||
will be called with an empty buffer sequence (actually
|
||||
the type `boost::asio::null_buffers`) to indicate the
|
||||
final chunk. The decorator may return a string which forms
|
||||
the chunk extension for chunks, and the field trailers
|
||||
for the final chunk.
|
||||
|
||||
In C++11 the decorator must be declared as a class or
|
||||
struct with a templated operator() thusly:
|
||||
|
||||
@code
|
||||
// The implementation guarantees that operator()
|
||||
// will be called only after the view returned by
|
||||
// any previous calls to operator() are no longer
|
||||
// needed. The decorator instance is intended to
|
||||
// manage the lifetime of the storage for all returned
|
||||
// views.
|
||||
//
|
||||
struct decorator
|
||||
{
|
||||
// Returns the chunk-extension for each chunk.
|
||||
// The buffer returned must include a trailing "\r\n",
|
||||
// and the leading semicolon (";") if one or more
|
||||
// chunk extensions are specified.
|
||||
//
|
||||
template<class ConstBufferSequence>
|
||||
string_view
|
||||
operator()(ConstBufferSequence const&) const;
|
||||
|
||||
// Returns a set of field trailers for the final chunk.
|
||||
// Each field should be formatted according to rfc7230
|
||||
// including the trailing "\r\n" for each field. If
|
||||
// no trailers are indicated, an empty string is returned.
|
||||
//
|
||||
string_view
|
||||
operator()(boost::asio::null_buffers) const;
|
||||
};
|
||||
@endcode
|
||||
|
||||
@par Thread Safety
|
||||
@e Distinct @e objects: Safe.@n
|
||||
@e Shared @e objects: Unsafe.
|
||||
|
||||
@tparam isRequest `true` if the message is a request.
|
||||
|
||||
@tparam Body The body type of the message.
|
||||
|
||||
@tparam Fields The type of fields in the message.
|
||||
|
||||
@tparam Decorator The type of chunk decorator to use.
|
||||
|
||||
@tparam Allocator The type of allocator to use.
|
||||
|
||||
@see @ref make_write_stream
|
||||
*/
|
||||
template<class SyncWriteStream,
|
||||
bool isRequest, class Fields>
|
||||
void
|
||||
write(SyncWriteStream& stream,
|
||||
header<isRequest, Fields> const& msg,
|
||||
error_code& ec);
|
||||
template<
|
||||
bool isRequest, class Body, class Fields,
|
||||
class Decorator = empty_decorator,
|
||||
class Allocator = std::allocator<char>
|
||||
>
|
||||
class serializer
|
||||
{
|
||||
template<class Stream, class Handler>
|
||||
class async_op;
|
||||
|
||||
/** Write a HTTP/1 header asynchronously to a stream.
|
||||
enum
|
||||
{
|
||||
do_init = 0,
|
||||
do_header_only = 10,
|
||||
do_header = 20,
|
||||
do_body = 40,
|
||||
|
||||
do_init_c = 50,
|
||||
do_header_only_c = 60,
|
||||
do_header_c = 70,
|
||||
do_body_c = 90,
|
||||
do_final_c = 100,
|
||||
|
||||
This function is used to asynchronously write a header to
|
||||
a stream. The function call always returns immediately. The
|
||||
asynchronous operation will continue until one of the following
|
||||
conditions is true:
|
||||
do_complete = 110
|
||||
};
|
||||
|
||||
@li The entire header is written.
|
||||
void split(bool, std::true_type) {}
|
||||
void split(bool v, std::false_type) { split_ = v; }
|
||||
|
||||
@li An error occurs.
|
||||
using buffer_type =
|
||||
basic_multi_buffer<Allocator>;
|
||||
|
||||
This operation is implemented in terms of one or more calls to
|
||||
the stream's `async_write_some` functions, and is known as a
|
||||
<em>composed operation</em>. The program must ensure that the
|
||||
stream performs no other write operations until this operation
|
||||
completes.
|
||||
using is_deferred =
|
||||
typename Body::writer::is_deferred;
|
||||
|
||||
Regardless of the semantic meaning of the header (for example,
|
||||
specifying "Content-Length: 0" and "Connection: close"),
|
||||
this function will not return `boost::asio::error::eof`.
|
||||
using cb0_t = consuming_buffers<buffers_view<
|
||||
typename buffer_type::const_buffers_type, // header
|
||||
typename Body::writer::const_buffers_type>>;// body
|
||||
|
||||
@param stream The stream to which the data is to be written.
|
||||
The type must support the @b AsyncWriteStream concept.
|
||||
using cb1_t = consuming_buffers<
|
||||
typename Body::writer::const_buffers_type>; // body
|
||||
|
||||
@param msg The header to write. The object must remain valid
|
||||
at least until the completion handler is called; ownership is
|
||||
not transferred.
|
||||
using ch0_t = consuming_buffers<buffers_view<
|
||||
typename buffer_type::const_buffers_type, // header
|
||||
detail::chunk_header, // chunk-header
|
||||
boost::asio::const_buffers_1, // chunk-ext+\r\n
|
||||
typename Body::writer::const_buffers_type, // body
|
||||
boost::asio::const_buffers_1>>; // crlf
|
||||
|
||||
using ch1_t = consuming_buffers<buffers_view<
|
||||
detail::chunk_header, // chunk-header
|
||||
boost::asio::const_buffers_1, // chunk-ext+\r\n
|
||||
typename Body::writer::const_buffers_type, // body
|
||||
boost::asio::const_buffers_1>>; // crlf
|
||||
|
||||
@param handler The handler to be called when the operation
|
||||
completes. Copies will be made of the handler as required.
|
||||
The equivalent function signature of the handler must be:
|
||||
@code void handler(
|
||||
error_code const& error // result of operation
|
||||
); @endcode
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class AsyncWriteStream,
|
||||
bool isRequest, class Fields,
|
||||
class WriteHandler>
|
||||
using ch2_t = consuming_buffers<buffers_view<
|
||||
boost::asio::const_buffers_1, // chunk-final
|
||||
boost::asio::const_buffers_1, // trailers
|
||||
boost::asio::const_buffers_1>>; // crlf
|
||||
|
||||
message<isRequest, Body, Fields> const& m_;
|
||||
Decorator d_;
|
||||
std::size_t limit_ =
|
||||
(std::numeric_limits<std::size_t>::max)();
|
||||
boost::optional<typename Body::writer> wr_;
|
||||
buffer_type b_;
|
||||
boost::variant<boost::blank,
|
||||
cb0_t, cb1_t, ch0_t, ch1_t, ch2_t> v_;
|
||||
int s_;
|
||||
bool split_ = is_deferred::value;
|
||||
bool header_done_ = false;
|
||||
bool chunked_;
|
||||
bool close_;
|
||||
bool more_;
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
|
||||
@param msg The message to serialize. The message object
|
||||
must remain valid for the lifetime of the write stream.
|
||||
|
||||
@param decorator An optional decorator to use.
|
||||
|
||||
@param alloc An optional allocator to use.
|
||||
*/
|
||||
explicit
|
||||
serializer(message<isRequest, Body, Fields> const& msg,
|
||||
Decorator const& decorator = Decorator{},
|
||||
Allocator const& alloc = Allocator{});
|
||||
|
||||
/// Returns the maximum number of bytes that will be written in each operation
|
||||
std::size_t
|
||||
limit() const
|
||||
{
|
||||
return limit_;
|
||||
}
|
||||
|
||||
/** Returns `true` if we will pause after writing the header.
|
||||
*/
|
||||
bool
|
||||
split() const
|
||||
{
|
||||
return split_;
|
||||
}
|
||||
|
||||
/** Set whether the header and body are written separately.
|
||||
|
||||
When the split feature is enabled, the implementation will
|
||||
write only the octets corresponding to the serialized header
|
||||
first. If the header has already been written, this function
|
||||
will have no effect on output. This function should be called
|
||||
before any writes take place, otherwise the behavior is
|
||||
undefined.
|
||||
*/
|
||||
void
|
||||
split(bool v)
|
||||
{
|
||||
split(v, is_deferred{});
|
||||
}
|
||||
|
||||
/** Set the maximum number of bytes that will be written in each operation.
|
||||
|
||||
By default, there is no limit on the size of writes.
|
||||
|
||||
@param n The byte limit. This must be greater than zero.
|
||||
*/
|
||||
void
|
||||
limit(std::size_t n)
|
||||
{
|
||||
limit_ = n;
|
||||
}
|
||||
|
||||
/** Return `true` if serialization of the header is complete.
|
||||
|
||||
This function indicates whether or not all octets
|
||||
corresponding to the serialized representation of the
|
||||
header have been successfully delivered to the stream.
|
||||
*/
|
||||
bool
|
||||
is_header_done() const
|
||||
{
|
||||
return header_done_;
|
||||
}
|
||||
|
||||
/** Return `true` if serialization is complete
|
||||
|
||||
The operation is complete when all octets corresponding
|
||||
to the serialized representation of the message have been
|
||||
successfully delivered to the stream.
|
||||
*/
|
||||
bool
|
||||
is_done() const
|
||||
{
|
||||
return s_ == do_complete;
|
||||
}
|
||||
|
||||
/** Write some serialized message data to the stream.
|
||||
|
||||
This function is used to write serialized message data to the
|
||||
stream. The function call will block until one of the following
|
||||
conditions is true:
|
||||
|
||||
@li One or more bytes have been transferred.
|
||||
|
||||
@li An error occurs on the stream.
|
||||
|
||||
In order to completely serialize a message, this function
|
||||
should be called until @ref is_done returns `true`. If the
|
||||
semantics of the message indicate that the connection should
|
||||
be closed after the message is sent, the error delivered from
|
||||
this call will be `boost::asio::error::eof`.
|
||||
|
||||
@param stream The stream to write to. This type must
|
||||
satisfy the requirements of @b SyncWriteStream.
|
||||
|
||||
@throws system_error Thrown on failure.
|
||||
*/
|
||||
template<class SyncWriteStream>
|
||||
void
|
||||
write_some(SyncWriteStream& stream);
|
||||
|
||||
/** Write some serialized message data to the stream.
|
||||
|
||||
This function is used to write serialized message data to the
|
||||
stream. The function call will block until one of the following
|
||||
conditions is true:
|
||||
|
||||
@li One or more bytes have been transferred.
|
||||
|
||||
@li An error occurs on the stream.
|
||||
|
||||
In order to completely serialize a message, this function
|
||||
should be called until @ref is_done returns `true`. If the
|
||||
semantics of the message indicate that the connection should
|
||||
be closed after the message is sent, the error delivered from
|
||||
this call will be `boost::asio::error::eof`.
|
||||
|
||||
@param stream The stream to write to. This type must
|
||||
satisfy the requirements of @b SyncWriteStream.
|
||||
|
||||
@param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
template<class SyncWriteStream>
|
||||
void
|
||||
write_some(SyncWriteStream& stream, error_code &ec);
|
||||
|
||||
/** Start an asynchronous write of some serialized message data.
|
||||
|
||||
This function is used to asynchronously write serialized
|
||||
message data to the stream. The function call always returns
|
||||
immediately. The asynchronous operation will continue until
|
||||
one of the following conditions is true:
|
||||
|
||||
@li One or more bytes have been transferred.
|
||||
|
||||
@li An error occurs on the stream.
|
||||
|
||||
In order to completely serialize a message, this function
|
||||
should be called until @ref is_done returns `true`. If the
|
||||
semantics of the message indicate that the connection should
|
||||
be closed after the message is sent, the error delivered from
|
||||
this call will be `boost::asio::error::eof`.
|
||||
|
||||
@param stream The stream to write to. This type must
|
||||
satisfy the requirements of @b SyncWriteStream.
|
||||
|
||||
@param handler The handler to be called when the request
|
||||
completes. Copies will be made of the handler as required. The
|
||||
equivalent function signature of the handler must be:
|
||||
@code void handler(
|
||||
error_code const& ec // Result of operation
|
||||
); @endcode
|
||||
Regardless of whether the asynchronous operation completes
|
||||
immediately or not, the handler will not be invoked from within
|
||||
this function. Invocation of the handler will be performed in a
|
||||
manner equivalent to using `boost::asio::io_service::post`.
|
||||
*/
|
||||
template<class AsyncWriteStream, class WriteHandler>
|
||||
#if BEAST_DOXYGEN
|
||||
void_or_deduced
|
||||
#else
|
||||
async_return_type<
|
||||
WriteHandler, void(error_code)>
|
||||
async_return_type<WriteHandler, void(error_code)>
|
||||
#endif
|
||||
async_write(AsyncWriteStream& stream,
|
||||
header<isRequest, Fields> const& msg,
|
||||
async_write_some(AsyncWriteStream& stream,
|
||||
WriteHandler&& handler);
|
||||
};
|
||||
|
||||
/** Return a stateful object to serialize an HTTP message.
|
||||
|
||||
This convenience function makes it easier to declare
|
||||
the variable for a given message.
|
||||
*/
|
||||
template<
|
||||
bool isRequest, class Body, class Fields,
|
||||
class Decorator = empty_decorator,
|
||||
class Allocator = std::allocator<char>>
|
||||
inline
|
||||
serializer<isRequest, Body, Fields,
|
||||
typename std::decay<Decorator>::type,
|
||||
typename std::decay<Allocator>::type>
|
||||
make_write_stream(message<isRequest, Body, Fields> const& m,
|
||||
Decorator const& decorator = Decorator{},
|
||||
Allocator const& allocator = Allocator{})
|
||||
{
|
||||
return serializer<isRequest, Body, Fields,
|
||||
typename std::decay<Decorator>::type,
|
||||
typename std::decay<Allocator>::type>{
|
||||
m, decorator, allocator};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define BEAST_WEBSOCKET_IMPL_ACCEPT_IPP
|
||||
|
||||
#include <beast/websocket/detail/type_traits.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/header_parser.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
@@ -39,7 +40,8 @@ class stream<NextLayer>::response_op
|
||||
{
|
||||
bool cont;
|
||||
stream<NextLayer>& ws;
|
||||
http::header<false, http::fields> res;
|
||||
http::message<false,
|
||||
http::empty_body, http::fields> res;
|
||||
int state = 0;
|
||||
|
||||
template<class Fields, class Decorator>
|
||||
@@ -188,8 +190,8 @@ class stream<NextLayer>::accept_op
|
||||
|
||||
template<class Buffers>
|
||||
data(Handler& handler, stream<NextLayer>& ws_,
|
||||
Buffers const& buffers,
|
||||
Decorator const& decorator_)
|
||||
Buffers const& buffers,
|
||||
Decorator const& decorator_)
|
||||
: ws(ws_)
|
||||
, decorator(decorator_)
|
||||
{
|
||||
@@ -365,7 +367,8 @@ accept_ex(ResponseDecorator const& decorator, error_code& ec)
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
accept(ConstBufferSequence const& buffers)
|
||||
{
|
||||
@@ -383,7 +386,8 @@ accept(ConstBufferSequence const& buffers)
|
||||
template<class NextLayer>
|
||||
template<
|
||||
class ConstBufferSequence, class ResponseDecorator>
|
||||
void
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const &decorator)
|
||||
@@ -404,7 +408,8 @@ accept_ex(ConstBufferSequence const& buffers,
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ConstBufferSequence>
|
||||
void
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
accept(ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
@@ -425,7 +430,8 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
|
||||
template<class NextLayer>
|
||||
template<
|
||||
class ConstBufferSequence, class ResponseDecorator>
|
||||
void
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
stream<NextLayer>::
|
||||
accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator, error_code& ec)
|
||||
@@ -641,8 +647,9 @@ async_accept_ex(ResponseDecorator const& decorator,
|
||||
|
||||
template<class NextLayer>
|
||||
template<class ConstBufferSequence, class AcceptHandler>
|
||||
async_return_type<
|
||||
AcceptHandler, void(error_code)>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<ConstBufferSequence>::value,
|
||||
async_return_type<AcceptHandler, void(error_code)>>::type
|
||||
stream<NextLayer>::
|
||||
async_accept(ConstBufferSequence const& buffers,
|
||||
AcceptHandler&& handler)
|
||||
@@ -664,8 +671,9 @@ async_accept(ConstBufferSequence const& buffers,
|
||||
template<class NextLayer>
|
||||
template<class ConstBufferSequence,
|
||||
class ResponseDecorator, class AcceptHandler>
|
||||
async_return_type<
|
||||
AcceptHandler, void(error_code)>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<ConstBufferSequence>::value,
|
||||
async_return_type<AcceptHandler, void(error_code)>>::type
|
||||
stream<NextLayer>::
|
||||
async_accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#define BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP
|
||||
|
||||
#include <beast/websocket/detail/type_traits.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/read.hpp>
|
||||
#include <beast/http/write.hpp>
|
||||
@@ -38,7 +39,8 @@ class stream<NextLayer>::handshake_op
|
||||
stream<NextLayer>& ws;
|
||||
response_type* res_p;
|
||||
detail::sec_ws_key_type key;
|
||||
request_type req;
|
||||
http::message<true,
|
||||
http::empty_body, http::fields> req;
|
||||
response_type res;
|
||||
int state = 0;
|
||||
|
||||
|
||||
@@ -196,10 +196,10 @@ build_request(detail::sec_ws_key_type& key,
|
||||
}
|
||||
|
||||
template<class NextLayer>
|
||||
template<class Decorator>
|
||||
template<class Fields, class Decorator>
|
||||
response_type
|
||||
stream<NextLayer>::
|
||||
build_response(request_type const& req,
|
||||
build_response(http::header<true, Fields> const& req,
|
||||
Decorator const& decorator)
|
||||
{
|
||||
auto const decorate =
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
#include <beast/websocket/option.hpp>
|
||||
#include <beast/websocket/detail/hybi13.hpp>
|
||||
#include <beast/websocket/detail/stream_base.hpp>
|
||||
#include <beast/http/empty_body.hpp>
|
||||
#include <beast/http/message.hpp>
|
||||
#include <beast/http/string_body.hpp>
|
||||
#include <beast/http/detail/type_traits.hpp>
|
||||
#include <beast/core/async_result.hpp>
|
||||
#include <beast/core/buffered_read_stream.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
@@ -28,12 +30,12 @@ namespace beast {
|
||||
namespace websocket {
|
||||
|
||||
/// The type of object holding HTTP Upgrade requests
|
||||
using request_type = http::header<true, http::fields>;
|
||||
using request_type =
|
||||
http::message<true, http::empty_body, http::fields>;
|
||||
|
||||
/// The type of object holding HTTP Upgrade responses
|
||||
using response_type =
|
||||
//http::response_header;
|
||||
http::response<http::string_body, http::fields>;
|
||||
http::message<false, http::string_body, http::fields>;
|
||||
|
||||
/** Information about a WebSocket frame.
|
||||
|
||||
@@ -473,7 +475,12 @@ public:
|
||||
@throws system_error Thrown on failure.
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
#if BEAST_DOXYGEN
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
#endif
|
||||
accept(ConstBufferSequence const& buffers);
|
||||
|
||||
/** Read and respond to a WebSocket HTTP Upgrade request.
|
||||
@@ -516,7 +523,12 @@ public:
|
||||
*/
|
||||
template<class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
#if BEAST_DOXYGEN
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
#endif
|
||||
accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator);
|
||||
|
||||
@@ -550,7 +562,12 @@ public:
|
||||
@param ec Set to indicate what error occurred, if any.
|
||||
*/
|
||||
template<class ConstBufferSequence>
|
||||
#if BEAST_DOXYGEN
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
#endif
|
||||
accept(ConstBufferSequence const& buffers, error_code& ec);
|
||||
|
||||
/** Read and respond to a WebSocket HTTP Upgrade request.
|
||||
@@ -593,7 +610,12 @@ public:
|
||||
*/
|
||||
template<class ConstBufferSequence,
|
||||
class ResponseDecorator>
|
||||
#if BEAST_DOXYGEN
|
||||
void
|
||||
#else
|
||||
typename std::enable_if<! http::detail::is_header<
|
||||
ConstBufferSequence>::value>::type
|
||||
#endif
|
||||
accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
error_code& ec);
|
||||
@@ -1085,8 +1107,9 @@ public:
|
||||
#if BEAST_DOXYGEN
|
||||
void_or_deduced
|
||||
#else
|
||||
async_return_type<
|
||||
AcceptHandler, void(error_code)>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<ConstBufferSequence>::value,
|
||||
async_return_type<AcceptHandler, void(error_code)>>::type
|
||||
#endif
|
||||
async_accept(ConstBufferSequence const& buffers,
|
||||
AcceptHandler&& handler);
|
||||
@@ -1153,8 +1176,9 @@ public:
|
||||
#if BEAST_DOXYGEN
|
||||
void_or_deduced
|
||||
#else
|
||||
async_return_type<
|
||||
AcceptHandler, void(error_code)>
|
||||
typename std::enable_if<
|
||||
! http::detail::is_header<ConstBufferSequence>::value,
|
||||
async_return_type<AcceptHandler, void(error_code)>>::type
|
||||
#endif
|
||||
async_accept_ex(ConstBufferSequence const& buffers,
|
||||
ResponseDecorator const& decorator,
|
||||
@@ -2975,9 +2999,9 @@ private:
|
||||
string_view const& target,
|
||||
Decorator const& decorator);
|
||||
|
||||
template<class Decorator>
|
||||
template<class Fields, class Decorator>
|
||||
response_type
|
||||
build_response(request_type const& req,
|
||||
build_response(http::header<true, Fields> const& req,
|
||||
Decorator const& decorator);
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user