summaryrefslogtreecommitdiff
path: root/boost/beast
diff options
context:
space:
mode:
Diffstat (limited to 'boost/beast')
-rw-r--r--boost/beast/core/bind_handler.hpp20
-rw-r--r--boost/beast/core/buffered_read_stream.hpp11
-rw-r--r--boost/beast/core/buffers_prefix.hpp2
-rw-r--r--boost/beast/core/buffers_suffix.hpp1
-rw-r--r--boost/beast/core/detail/allocator.hpp4
-rw-r--r--boost/beast/core/detail/base64.hpp4
-rw-r--r--boost/beast/core/detail/bind_handler.hpp42
-rw-r--r--boost/beast/core/detail/config.hpp17
-rw-r--r--boost/beast/core/detail/in_place_init.hpp43
-rw-r--r--boost/beast/core/detail/type_traits.hpp193
-rw-r--r--boost/beast/core/detail/variant.hpp144
-rw-r--r--boost/beast/core/flat_buffer.hpp2
-rw-r--r--boost/beast/core/flat_static_buffer.hpp2
-rw-r--r--boost/beast/core/handler_ptr.hpp152
-rw-r--r--boost/beast/core/impl/buffered_read_stream.ipp23
-rw-r--r--boost/beast/core/impl/buffers_cat.ipp327
-rw-r--r--boost/beast/core/impl/buffers_prefix.ipp2
-rw-r--r--boost/beast/core/impl/buffers_suffix.ipp3
-rw-r--r--boost/beast/core/impl/file_posix.ipp10
-rw-r--r--boost/beast/core/impl/file_stdio.ipp10
-rw-r--r--boost/beast/core/impl/file_win32.ipp18
-rw-r--r--boost/beast/core/impl/handler_ptr.ipp149
-rw-r--r--boost/beast/core/impl/multi_buffer.ipp2
-rw-r--r--boost/beast/core/impl/static_buffer.ipp23
-rw-r--r--boost/beast/core/static_buffer.hpp7
-rw-r--r--boost/beast/core/string.hpp51
-rw-r--r--boost/beast/core/type_traits.hpp24
-rw-r--r--boost/beast/http/basic_dynamic_body.hpp10
-rw-r--r--boost/beast/http/basic_file_body.hpp25
-rw-r--r--boost/beast/http/buffer_body.hpp9
-rw-r--r--boost/beast/http/detail/rfc7230.hpp4
-rw-r--r--boost/beast/http/detail/type_traits.hpp16
-rw-r--r--boost/beast/http/empty_body.hpp7
-rw-r--r--boost/beast/http/error.hpp13
-rw-r--r--boost/beast/http/field.hpp1
-rw-r--r--boost/beast/http/fields.hpp44
-rw-r--r--boost/beast/http/impl/basic_parser.ipp10
-rw-r--r--boost/beast/http/impl/field.ipp3
-rw-r--r--boost/beast/http/impl/fields.ipp143
-rw-r--r--boost/beast/http/impl/file_body_win32.ipp79
-rw-r--r--boost/beast/http/impl/parser.ipp88
-rw-r--r--boost/beast/http/impl/read.ipp307
-rw-r--r--boost/beast/http/impl/serializer.ipp88
-rw-r--r--boost/beast/http/impl/status.ipp8
-rw-r--r--boost/beast/http/impl/verb.ipp10
-rw-r--r--boost/beast/http/impl/write.ipp83
-rw-r--r--boost/beast/http/message.hpp10
-rw-r--r--boost/beast/http/parser.hpp59
-rw-r--r--boost/beast/http/read.hpp16
-rw-r--r--boost/beast/http/serializer.hpp56
-rw-r--r--boost/beast/http/span_body.hpp10
-rw-r--r--boost/beast/http/string_body.hpp10
-rw-r--r--boost/beast/http/type_traits.hpp23
-rw-r--r--boost/beast/http/vector_body.hpp10
-rw-r--r--boost/beast/http/write.hpp16
-rw-r--r--boost/beast/version.hpp2
-rw-r--r--boost/beast/websocket.hpp1
-rw-r--r--boost/beast/websocket/detail/error.hpp78
-rw-r--r--boost/beast/websocket/detail/frame.hpp25
-rw-r--r--boost/beast/websocket/detail/mask.hpp177
-rw-r--r--boost/beast/websocket/detail/pausation.hpp203
-rw-r--r--boost/beast/websocket/detail/pmd_extension.hpp80
-rw-r--r--boost/beast/websocket/detail/stream_base.hpp221
-rw-r--r--boost/beast/websocket/detail/type_traits.hpp4
-rw-r--r--boost/beast/websocket/detail/utf8_checker.hpp6
-rw-r--r--boost/beast/websocket/error.hpp225
-rw-r--r--boost/beast/websocket/impl/accept.ipp243
-rw-r--r--boost/beast/websocket/impl/close.ipp133
-rw-r--r--boost/beast/websocket/impl/error.ipp170
-rw-r--r--boost/beast/websocket/impl/handshake.ipp133
-rw-r--r--boost/beast/websocket/impl/ping.ipp92
-rw-r--r--boost/beast/websocket/impl/read.ipp377
-rw-r--r--boost/beast/websocket/impl/rfc6455.ipp4
-rw-r--r--boost/beast/websocket/impl/stream.ipp545
-rw-r--r--boost/beast/websocket/impl/teardown.ipp123
-rw-r--r--boost/beast/websocket/impl/write.ipp231
-rw-r--r--boost/beast/websocket/ssl.hpp6
-rw-r--r--boost/beast/websocket/stream.hpp412
-rw-r--r--boost/beast/websocket/stream_fwd.hpp28
-rw-r--r--boost/beast/websocket/teardown.hpp12
-rw-r--r--boost/beast/zlib/detail/inflate_stream.hpp22
81 files changed, 3559 insertions, 2438 deletions
diff --git a/boost/beast/core/bind_handler.hpp b/boost/beast/core/bind_handler.hpp
index 0756bc5aaa..0fb7b8233b 100644
--- a/boost/beast/core/bind_handler.hpp
+++ b/boost/beast/core/bind_handler.hpp
@@ -23,18 +23,13 @@ namespace beast {
This function creates a new handler which, when invoked, calls
the original handler with the list of bound arguments. Any
- parameters passed in the invocation will be subtituted for
+ parameters passed in the invocation will be substituted for
placeholders present in the list of bound arguments. Parameters
which are not matched to placeholders are silently discarded.
- The passed handler and arguments are forwarded into the returned
- handler, which provides the same `io_context` execution guarantees
- as the original handler.
- Unlike `boost::asio::io_context::wrap`, the returned handler can
- be used in a subsequent call to `boost::asio::io_context::post`
- instead of `boost::asio::io_context::dispatch`, to ensure that
- the handler will not be invoked immediately by the calling
- function.
+ The passed handler and arguments are forwarded into the returned
+ handler, whose associated allocator and associated executor will
+ will be the same as those of the original handler.
Example:
@@ -52,8 +47,10 @@ namespace beast {
@param handler The handler to wrap.
- @param args A list of arguments to bind to the handler. The
- arguments are forwarded into the returned object.
+ @param args A list of arguments to bind to the handler.
+ The arguments are forwarded into the returned object. These
+ arguments may include placeholders, which will operate in
+ a fashion identical to a call to `std::bind`.
*/
template<class Handler, class... Args>
#if BOOST_BEAST_DOXYGEN
@@ -65,6 +62,7 @@ detail::bound_handler<
bind_handler(Handler&& handler, Args&&... args)
{
#if 0
+ // Can't do this because of placeholders
static_assert(is_completion_handler<
Handler, void(Args...)>::value,
"Handler requirements not met");
diff --git a/boost/beast/core/buffered_read_stream.hpp b/boost/beast/core/buffered_read_stream.hpp
index e683a40953..974062309f 100644
--- a/boost/beast/core/buffered_read_stream.hpp
+++ b/boost/beast/core/buffered_read_stream.hpp
@@ -111,8 +111,7 @@ public:
typename std::remove_reference<Stream>::type;
/// The type of the lowest layer.
- using lowest_layer_type =
- typename get_lowest_layer<next_layer_type>::type;
+ using lowest_layer_type = get_lowest_layer<next_layer_type>;
/** Move constructor.
@@ -274,8 +273,8 @@ public:
is retained by the caller, which must guarantee that they
remain valid until the handler is called.
- @param handler The handler to be called when the operation
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation
@@ -346,8 +345,8 @@ public:
retained by the caller, which must guarantee that they
remain valid until the handler is called.
- @param handler The handler to be called when the operation
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation
diff --git a/boost/beast/core/buffers_prefix.hpp b/boost/beast/core/buffers_prefix.hpp
index 67d58b5c58..858723fe7d 100644
--- a/boost/beast/core/buffers_prefix.hpp
+++ b/boost/beast/core/buffers_prefix.hpp
@@ -12,8 +12,8 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/type_traits.hpp>
-#include <boost/beast/core/detail/in_place_init.hpp>
#include <boost/asio/buffer.hpp>
+#include <boost/optional/optional.hpp>
#include <cstdint>
#include <type_traits>
diff --git a/boost/beast/core/buffers_suffix.hpp b/boost/beast/core/buffers_suffix.hpp
index 81eb5a6ba7..3959694577 100644
--- a/boost/beast/core/buffers_suffix.hpp
+++ b/boost/beast/core/buffers_suffix.hpp
@@ -11,7 +11,6 @@
#define BOOST_BEAST_BUFFERS_SUFFIX_HPP
#include <boost/beast/core/detail/config.hpp>
-#include <boost/beast/core/detail/in_place_init.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/optional.hpp>
diff --git a/boost/beast/core/detail/allocator.hpp b/boost/beast/core/detail/allocator.hpp
index 39b2aa5f12..e893f5c274 100644
--- a/boost/beast/core/detail/allocator.hpp
+++ b/boost/beast/core/detail/allocator.hpp
@@ -11,7 +11,7 @@
#define BOOST_BEAST_DETAIL_ALLOCATOR_HPP
#include <boost/config.hpp>
-#if BOOST_NO_CXX11_ALLOCATOR
+#ifdef BOOST_NO_CXX11_ALLOCATOR
#include <boost/container/allocator_traits.hpp>
#else
#include <memory>
@@ -25,7 +25,7 @@ namespace detail {
// implementations which falsely claim C++11
// compatibility.
-#if BOOST_NO_CXX11_ALLOCATOR
+#ifdef BOOST_NO_CXX11_ALLOCATOR
template<class Alloc>
using allocator_traits = boost::container::allocator_traits<Alloc>;
diff --git a/boost/beast/core/detail/base64.hpp b/boost/beast/core/detail/base64.hpp
index ece03dfa34..6cb3f67a77 100644
--- a/boost/beast/core/detail/base64.hpp
+++ b/boost/beast/core/detail/base64.hpp
@@ -13,7 +13,7 @@
base64.cpp and base64.h
- Copyright (C) 2004-2008 René Nyffenegger
+ Copyright (C) 2004-2008 Rene Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
@@ -33,7 +33,7 @@
3. This notice may not be removed or altered from any source distribution.
- René Nyffenegger rene.nyffenegger@adp-gmbh.ch
+ Rene Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
diff --git a/boost/beast/core/detail/bind_handler.hpp b/boost/beast/core/detail/bind_handler.hpp
index 5a9059b8e3..48046df923 100644
--- a/boost/beast/core/detail/bind_handler.hpp
+++ b/boost/beast/core/detail/bind_handler.hpp
@@ -14,7 +14,9 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/core/ignore_unused.hpp>
+#include <boost/is_placeholder.hpp>
#include <functional>
#include <utility>
@@ -45,8 +47,10 @@ class bound_handler
static
typename std::enable_if<
std::is_placeholder<typename
+ std::decay<Arg>::type>::value == 0 &&
+ boost::is_placeholder<typename
std::decay<Arg>::type>::value == 0,
- Arg&&>::type
+ Arg&&>::type
extract(Arg&& arg, Vals& vals)
{
boost::ignore_unused(vals);
@@ -58,10 +62,10 @@ class bound_handler
typename std::enable_if<
std::is_placeholder<typename
std::decay<Arg>::type>::value != 0,
- typename std::tuple_element<
- std::is_placeholder<
- typename std::decay<Arg>::type>::value - 1,
- Vals>::type&&>::type
+ typename std::tuple_element<
+ std::is_placeholder<
+ typename std::decay<Arg>::type>::value - 1,
+ Vals>>::type::type&&
extract(Arg&&, Vals&& vals)
{
return std::get<std::is_placeholder<
@@ -69,6 +73,22 @@ class bound_handler
std::forward<Vals>(vals));
}
+ template<class Arg, class Vals>
+ static
+ typename std::enable_if<
+ boost::is_placeholder<typename
+ std::decay<Arg>::type>::value != 0,
+ typename std::tuple_element<
+ boost::is_placeholder<
+ typename std::decay<Arg>::type>::value - 1,
+ Vals>>::type::type&&
+ extract(Arg&&, Vals&& vals)
+ {
+ return std::get<boost::is_placeholder<
+ typename std::decay<Arg>::type>::value - 1>(
+ std::forward<Vals>(vals));
+ }
+
template<
class ArgsTuple,
std::size_t... S>
@@ -109,7 +129,7 @@ public:
boost::asio::associated_allocator_t<Handler>;
bound_handler(bound_handler&&) = default;
- bound_handler(bound_handler const&) = default;
+ bound_handler(bound_handler const&) = delete;
template<class DeducedHandler>
explicit
@@ -123,7 +143,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
friend
@@ -134,6 +154,14 @@ public:
return asio_handler_is_continuation(std::addressof(h->h_));
}
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, bound_handler* h)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(h->h_));
+ }
+
template<class... Values>
void
operator()(Values&&... values)
diff --git a/boost/beast/core/detail/config.hpp b/boost/beast/core/detail/config.hpp
index 48f97e377f..68e3dda8ee 100644
--- a/boost/beast/core/detail/config.hpp
+++ b/boost/beast/core/detail/config.hpp
@@ -19,12 +19,12 @@
#include <boost/static_assert.hpp>
/*
- _MSC_VER and _MSC_FULL_VER by version:
+ _MSC_VER and _MSC_FULL_VER by version:
- 14.0 (2015) 1900 190023026
- 14.0 (2015 Update 1) 1900 190023506
- 14.0 (2015 Update 2) 1900 190023918
- 14.0 (2015 Update 3) 1900 190024210
+ 14.0 (2015) 1900 190023026
+ 14.0 (2015 Update 1) 1900 190023506
+ 14.0 (2015 Update 2) 1900 190023918
+ 14.0 (2015 Update 3) 1900 190024210
*/
#if defined(BOOST_MSVC)
@@ -48,10 +48,7 @@
#endif
-#if BOOST_VERSION >= 106500 || ! defined(BOOST_GCC) || BOOST_GCC < 70000
-# define BOOST_BEAST_FALLTHROUGH BOOST_FALLTHROUGH
-#else
-# define BOOST_BEAST_FALLTHROUGH __attribute__((fallthrough))
-#endif
+#define BOOST_BEAST_DEPRECATION_STRING \
+ "This is a deprecated interface, #define BOOST_BEAST_ALLOW_DEPRECATED to allow it"
#endif
diff --git a/boost/beast/core/detail/in_place_init.hpp b/boost/beast/core/detail/in_place_init.hpp
deleted file mode 100644
index d3a33becd5..0000000000
--- a/boost/beast/core/detail/in_place_init.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright (c) 2016-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)
-//
-// Official repository: https://github.com/boostorg/beast
-//
-
-#ifndef BOOST_BEAST_DETAIL_IN_PLACE_INIT_HPP
-#define BOOST_BEAST_DETAIL_IN_PLACE_INIT_HPP
-
-#include <boost/version.hpp>
-#include <boost/optional/optional.hpp>
-
-// Provide boost::in_place_init_t and boost::in_place_init
-// for Boost versions earlier than 1.63.0.
-
-#if BOOST_VERSION < 106300
-
-namespace boost {
-
-namespace optional_ns {
-
-// a tag for in-place initialization of contained value
-struct in_place_init_t
-{
- struct init_tag{};
- explicit in_place_init_t(init_tag){}
-};
-const in_place_init_t in_place_init ((in_place_init_t::init_tag()));
-
-} // namespace optional_ns
-
-using optional_ns::in_place_init_t;
-using optional_ns::in_place_init;
-
-}
-
-#endif
-
-#endif
-
diff --git a/boost/beast/core/detail/type_traits.hpp b/boost/beast/core/detail/type_traits.hpp
index 06fbda291d..3692b6222b 100644
--- a/boost/beast/core/detail/type_traits.hpp
+++ b/boost/beast/core/detail/type_traits.hpp
@@ -12,6 +12,7 @@
#include <boost/beast/core/error.hpp>
#include <boost/asio/buffer.hpp>
+#include <boost/type_traits.hpp>
#include <iterator>
#include <tuple>
#include <type_traits>
@@ -22,25 +23,8 @@ namespace boost {
namespace beast {
namespace detail {
-//
-// utilities
-//
-
-template<class... Ts>
-struct make_void
-{
- using type = void;
-};
-
-template<class... Ts>
-using void_t = typename make_void<Ts...>::type;
-
-template<class T>
-inline
-void
-accept_rv(T){}
-
template<class U>
+inline
std::size_t constexpr
max_sizeof()
{
@@ -48,6 +32,7 @@ max_sizeof()
}
template<class U0, class U1, class... Us>
+inline
std::size_t constexpr
max_sizeof()
{
@@ -57,6 +42,7 @@ max_sizeof()
}
template<class U>
+inline
std::size_t constexpr
max_alignof()
{
@@ -72,6 +58,36 @@ max_alignof()
max_alignof<U0>() : max_alignof<U1, Us...>();
}
+// (since C++17)
+template<class... Ts> struct make_void { using type = void; };
+template<class... Ts> using void_t = typename make_void<Ts...>::type;
+
+// (since C++11) missing from g++4.8
+template<std::size_t Len, class... Ts>
+struct aligned_union
+{
+ static
+ std::size_t constexpr alignment_value =
+ max_alignof<Ts...>();
+
+ using type = typename std::aligned_storage<
+ (Len > max_sizeof<Ts...>()) ? Len : (max_sizeof<Ts...>()),
+ alignment_value>::type;
+};
+
+template<std::size_t Len, class... Ts>
+using aligned_union_t =
+ typename aligned_union<Len, Ts...>::type;
+
+//------------------------------------------------------------------------------
+
+template<class T>
+inline
+void
+accept_rv(T){}
+
+//------------------------------------------------------------------------------
+
template<unsigned N, class T, class... Tn>
struct repeat_tuple_impl
{
@@ -98,6 +114,8 @@ struct repeat_tuple<0, T>
using type = std::tuple<>;
};
+//------------------------------------------------------------------------------
+
template<class R, class C, class ...A>
auto
is_invocable_test(C&& c, int, A&& ...a)
@@ -132,6 +150,8 @@ struct is_invocable<C, R(A...)>
};
/** @} */
+//------------------------------------------------------------------------------
+
// for span
template<class T, class E, class = void>
struct is_contiguous_container: std::false_type {};
@@ -154,6 +174,8 @@ struct is_contiguous_container<T, E, void_t<
>::type>>: std::true_type
{};
+//------------------------------------------------------------------------------
+
template<class...>
struct unwidest_unsigned;
@@ -234,6 +256,21 @@ max_all(U0 u0, U1 u1, UN... un)
//------------------------------------------------------------------------------
+template<class T, class = void>
+struct get_lowest_layer_helper
+{
+ using type = T;
+};
+
+template<class T>
+struct get_lowest_layer_helper<T,
+ void_t<typename T::lowest_layer_type>>
+{
+ using type = typename T::lowest_layer_type;
+};
+
+//------------------------------------------------------------------------------
+
//
// buffer concepts
//
@@ -273,7 +310,7 @@ template<class... Bn>
struct common_buffers_type
{
using type = typename std::conditional<
- std::is_convertible<std::tuple<Bn...>,
+ boost::is_convertible<std::tuple<Bn...>,
typename repeat_tuple<sizeof...(Bn),
boost::asio::mutable_buffer>::type>::value,
boost::asio::mutable_buffer,
@@ -299,29 +336,99 @@ using ReadHandler = StreamHandler;
using WriteHandler = StreamHandler;
template<class Buffers>
-class buffers_range_adapter
+class buffers_range_adaptor
{
Buffers const& b_;
public:
using value_type = typename std::conditional<
- std::is_convertible<typename std::iterator_traits<
- typename buffer_sequence_iterator<Buffers>::type>::value_type,
- boost::asio::const_buffer>::value,
- boost::asio::const_buffer,
- boost::asio::mutable_buffer>::type;
-
- /* VFALCO This isn't right, because range-for will pick up the iterator's
- value_type which might not be const_buffer or mutable_buffer. We
- need to declare our own iterator wrapper that converts the underlying
- iterator's value_type to const_buffer or mutable_buffer so that
- range-for sees one of those types.
- */
- using const_iterator = typename
- buffer_sequence_iterator<Buffers>::type;
+ boost::is_convertible<
+ typename std::iterator_traits<
+ typename buffer_sequence_iterator<
+ Buffers>::type>::value_type,
+ boost::asio::mutable_buffer>::value,
+ boost::asio::mutable_buffer,
+ boost::asio::const_buffer>::type;
+
+ class const_iterator
+ {
+ friend class buffers_range_adaptor;
+
+ using iter_type = typename
+ buffer_sequence_iterator<Buffers>::type;
+
+ iter_type it_;
+
+ const_iterator(iter_type const& it)
+ : it_(it)
+ {
+ }
+
+ public:
+ using value_type = typename
+ buffers_range_adaptor::value_type;
+ using pointer = value_type const*;
+ using reference = value_type;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category =
+ std::bidirectional_iterator_tag;
+
+ bool
+ operator==(const_iterator const& other) const
+ {
+ return it_ == other.it_;
+ }
+
+ bool
+ operator!=(const_iterator const& other) const
+ {
+ return ! (*this == other);
+ }
+
+ reference
+ operator*() const
+ {
+ return *it_;
+ }
+
+ pointer
+ operator->() const = delete;
+
+ const_iterator&
+ operator++()
+ {
+ ++it_;
+ return *this;
+ }
+
+ const_iterator
+ operator++(int)
+ {
+ auto temp = *this;
+ ++(*this);
+ return temp;
+ }
+
+ // deprecated
+ const_iterator&
+ operator--()
+ {
+ --it_;
+ return *this;
+ }
+
+ // deprecated
+ const_iterator
+ operator--(int)
+ {
+ auto temp = *this;
+ --(*this);
+ return temp;
+ }
+ };
explicit
- buffers_range_adapter(Buffers const& b)
+ buffers_range_adaptor(Buffers const& b)
: b_(b)
{
}
@@ -340,12 +447,24 @@ public:
};
template<class Buffers>
-buffers_range_adapter<Buffers>
+buffers_range_adaptor<Buffers>
buffers_range(Buffers const& buffers)
{
- return buffers_range_adapter<Buffers>{buffers};
+ return buffers_range_adaptor<Buffers>{buffers};
}
+/* If this static assert goes off, it means that the completion
+ handler you provided to an asynchronous initiating function did
+ not have the right signature. Check the parameter types for your
+ completion handler and make sure they match the list of types
+ expected by the initiating function,
+*/
+#define BOOST_BEAST_HANDLER_INIT(type, sig) \
+ static_assert(is_completion_handler< \
+ BOOST_ASIO_HANDLER_TYPE(type, sig), sig>::value, \
+ "CompletionHandler signature requirements not met"); \
+ boost::asio::async_completion<type, sig> init{handler}
+
} // detail
} // beast
} // boost
diff --git a/boost/beast/core/detail/variant.hpp b/boost/beast/core/detail/variant.hpp
index cba6ba63c0..536cb7593f 100644
--- a/boost/beast/core/detail/variant.hpp
+++ b/boost/beast/core/detail/variant.hpp
@@ -31,15 +31,12 @@ namespace detail {
template<class... TN>
class variant
{
- typename std::aligned_storage<
- max_sizeof<TN...>(),
- max_alignof<TN...>()
- >::type buf_;
+ detail::aligned_union_t<1, TN...> buf_;
unsigned char i_ = 0;
template<std::size_t I>
using type = typename std::tuple_element<
- I , std::tuple<TN...>>::type;
+ I, std::tuple<TN...>>::type;
template<std::size_t I>
using C = std::integral_constant<std::size_t, I>;
@@ -49,8 +46,15 @@ public:
~variant()
{
- if(i_)
- destroy(C<0>{});
+ destroy(C<0>{});
+ }
+
+ bool
+ operator==(variant const& other) const
+ {
+ if(i_ != other.i_)
+ return false;
+ return equal(other, C<0>{});
}
// 0 = empty
@@ -64,6 +68,7 @@ public:
variant(variant&& other)
{
i_ = other.move(&buf_, C<0>{});
+ other.i_ = 0;
}
variant(variant const& other)
@@ -74,17 +79,22 @@ public:
// moved-from object becomes empty
variant& operator=(variant&& other)
{
- if(i_ != 0)
+ if(this != &other)
+ {
destroy(C<0>{});
- i_ = other.move(&buf_, C<0>{});
+ i_ = other.move(&buf_, C<0>{});
+ other.i_ = 0;
+ }
return *this;
}
variant& operator=(variant const& other)
{
- if(i_ != 0)
+ if(this != &other)
+ {
destroy(C<0>{});
- i_ = other.copy(&buf_, C<0>{});
+ i_ = other.copy(&buf_, C<0>{});
+ }
return *this;
}
@@ -92,8 +102,7 @@ public:
void
emplace(Args&&... args)
{
- if(i_ != 0)
- destroy(C<0>{});
+ destroy(C<0>{});
new(&buf_) type<I-1>(
std::forward<Args>(args)...);
i_ = I;
@@ -120,72 +129,135 @@ public:
void
reset()
{
- if(i_ == 0)
- return;
destroy(C<0>{});
}
private:
void
- destroy(C<sizeof...(TN)>)
+ destroy(C<0>)
{
- return;
+ auto const I = 0;
+ if(i_ == I)
+ return;
+ destroy(C<I+1>{});
+ i_ = 0;
}
template<std::size_t I>
void
destroy(C<I>)
{
- if(i_ == I+1)
+ if(i_ == I)
{
- using T = type<I>;
- get<I+1>().~T();
- i_ = 0;
+ using T = type<I-1>;
+ get<I>().~T();
return;
}
destroy(C<I+1>{});
}
+ void
+ destroy(C<sizeof...(TN)>)
+ {
+ auto const I = sizeof...(TN);
+ BOOST_ASSERT(i_ == I);
+ using T = type<I-1>;
+ get<I>().~T();
+ }
+
unsigned char
- move(void*, C<sizeof...(TN)>)
+ move(void* dest, C<0>)
{
- return 0;
+ auto const I = 0;
+ if(i_ == I)
+ return I;
+ return move(dest, C<I+1>{});
}
template<std::size_t I>
unsigned char
move(void* dest, C<I>)
{
- if(i_ == I+1)
+ if(i_ == I)
{
- using T = type<I>;
- new(dest) T{std::move(get<I+1>())};
- get<I+1>().~T();
- i_ = 0;
- return I+1;
+ using T = type<I-1>;
+ new(dest) T(std::move(get<I>()));
+ get<I>().~T();
+ return I;
}
return move(dest, C<I+1>{});
}
unsigned char
- copy(void*, C<sizeof...(TN)>) const
+ move(void* dest, C<sizeof...(TN)>)
+ {
+ auto const I = sizeof...(TN);
+ BOOST_ASSERT(i_ == I);
+ using T = type<I-1>;
+ new(dest) T(std::move(get<I>()));
+ get<I>().~T();
+ return I;
+ }
+
+ unsigned char
+ copy(void* dest, C<0>) const
{
- return 0;
+ auto const I = 0;
+ if(i_ == I)
+ return I;
+ return copy(dest, C<I+1>{});
}
template<std::size_t I>
unsigned char
copy(void* dest, C<I>) const
{
- if(i_ == I+1)
+ if(i_ == I)
{
- using T = type<I>;
- auto const& t = get<I+1>();
- new(dest) T{t};
- return I+1;
+ using T = type<I-1>;
+ auto const& t = get<I>();
+ new(dest) T(t);
+ return I;
}
return copy(dest, C<I+1>{});
}
+
+ unsigned char
+ copy(void* dest, C<sizeof...(TN)>) const
+ {
+ auto const I = sizeof...(TN);
+ BOOST_ASSERT(i_ == I);
+ using T = type<I-1>;
+ auto const& t = get<I>();
+ new(dest) T(t);
+ return I;
+ }
+
+ bool
+ equal(variant const& other, C<0>) const
+ {
+ auto constexpr I = 0;
+ if(i_ == I)
+ return true;
+ return equal(other, C<I+1>{});
+ }
+
+ template<std::size_t I>
+ bool
+ equal(variant const& other, C<I>) const
+ {
+ if(i_ == I)
+ return get<I>() == other.get<I>();
+ return equal(other, C<I+1>{});
+ }
+
+ bool
+ equal(variant const& other, C<sizeof...(TN)>) const
+ {
+ auto constexpr I = sizeof...(TN);
+ BOOST_ASSERT(i_ == I);
+ return get<I>() == other.get<I>();
+ }
};
} // detail
diff --git a/boost/beast/core/flat_buffer.hpp b/boost/beast/core/flat_buffer.hpp
index 0ccd16bc64..11a18fdcb4 100644
--- a/boost/beast/core/flat_buffer.hpp
+++ b/boost/beast/core/flat_buffer.hpp
@@ -84,7 +84,7 @@ public:
using allocator_type = Allocator;
/// The type used to represent the input sequence as a list of buffers.
- using const_buffers_type = boost::asio::mutable_buffer;
+ using const_buffers_type = boost::asio::const_buffer;
/// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type = boost::asio::mutable_buffer;
diff --git a/boost/beast/core/flat_static_buffer.hpp b/boost/beast/core/flat_static_buffer.hpp
index 141ae552c1..c8eae90945 100644
--- a/boost/beast/core/flat_static_buffer.hpp
+++ b/boost/beast/core/flat_static_buffer.hpp
@@ -52,7 +52,7 @@ public:
This buffer sequence is guaranteed to have length 1.
*/
- using const_buffers_type = boost::asio::mutable_buffer;
+ using const_buffers_type = boost::asio::const_buffer;
/** The type used to represent the output sequence as a list of buffers.
diff --git a/boost/beast/core/handler_ptr.hpp b/boost/beast/core/handler_ptr.hpp
index f08a815c16..559c0c1559 100644
--- a/boost/beast/core/handler_ptr.hpp
+++ b/boost/beast/core/handler_ptr.hpp
@@ -10,10 +10,9 @@
#ifndef BOOST_BEAST_HANDLER_PTR_HPP
#define BOOST_BEAST_HANDLER_PTR_HPP
+#include <boost/beast/core/detail/allocator.hpp>
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/type_traits.hpp>
-#include <atomic>
-#include <cstdint>
#include <type_traits>
#include <utility>
@@ -22,69 +21,65 @@ namespace beast {
/** A smart pointer container with associated completion handler.
- This is a smart pointer that retains shared ownership of an
- object through a pointer. Memory is managed using the allocation
- and deallocation functions associated with a completion handler,
- which is also stored in the object. The managed object is
- destroyed and its memory deallocated when one of the following
- happens:
+ This is a smart pointer that retains unique ownership of an
+ object through a pointer. Memory is managed using the allocator
+ associated with a completion handler stored in the object. The
+ managed object is destroyed and its memory deallocated when one
+ of the following occurs:
@li The function @ref invoke is called.
@li The function @ref release_handler is called.
- @li The last remaining container owning the object is destroyed.
+ @li The container is destroyed.
- Objects of this type are used in the implementation of
- composed operations. Typically the composed operation's shared
- state is managed by the @ref handler_ptr and an allocator
- associated with the final handler is used to create the managed
- object.
+ Objects of this type are used in the implementation of composed
+ operations with states that are expensive or impossible to move.
+ This container manages that non-trivial state on behalf of the
+ composed operation.
- @note The reference count is stored using a 16 bit unsigned
- integer. Making more than 2^16 copies of one object results
- in undefined behavior.
+ @par Thread Safety
+ @e Distinct @e objects: Safe.@n
+ @e Shared @e objects: Unsafe.
- @tparam T The type of the owned object.
+ @tparam T The type of the owned object. Must be noexcept destructible.
@tparam Handler The type of the completion handler.
*/
template<class T, class Handler>
class handler_ptr
{
- struct P
- {
- T* t;
- std::atomic<std::uint16_t> n;
-
- // There's no way to put the handler anywhere else
- // without exposing ourselves to race conditions
- // and all sorts of ugliness.
- // See:
- // https://github.com/boostorg/beast/issues/215
- Handler handler;
+ using handler_storage_t = typename detail::aligned_union<1, Handler>::type;
- template<class DeducedHandler, class... Args>
- P(DeducedHandler&& handler, Args&&... args);
- };
+ T* t_ = nullptr;
+ handler_storage_t h_;
- P* p_;
+ void clear();
public:
- /// The type of element this object stores
+ static_assert(std::is_nothrow_destructible<T>::value,
+ "T must be nothrow destructible");
+
+ /// The type of element stored
using element_type = T;
- /// The type of handler this object stores
+ /// The type of handler stored
using handler_type = Handler;
- /// Copy assignment (disallowed).
+ /// Default constructor (deleted).
+ handler_ptr() = delete;
+
+ /// Copy assignment (deleted).
handler_ptr& operator=(handler_ptr const&) = delete;
- /** Destructs the owned object if no more @ref handler_ptr link to it.
+ /// Move assignment (deleted).
+ handler_ptr& operator=(handler_ptr &&) = delete;
+
+ /** Destructor
- If `*this` owns an object and it is the last @ref handler_ptr
- owning it, the object is destroyed and the memory deallocated
- using the associated deallocator.
+ If `*this` owns an object the object is destroyed and
+ the memory deallocated using the allocator associated
+ with the handler.
*/
~handler_ptr();
@@ -95,91 +90,76 @@ public:
*/
handler_ptr(handler_ptr&& other);
- /// Copy constructor
- handler_ptr(handler_ptr const& other);
+ /// Copy constructor (deleted).
+ handler_ptr(handler_ptr const& other) = delete;
- /** Construct a new @ref handler_ptr
+ /** Constructor
- This creates a new @ref handler_ptr with an owned object
- of type `T`. The allocator associated with the handler will
- be used to allocate memory for the owned object. The constructor
- for the owned object will be called thusly:
+ This creates a new container with an owned object of
+ type `T`. The allocator associated with the handler will
+ be used to allocate memory for the owned object. The
+ constructor for the owned object will be called with the
+ following equivalent signature:
@code
- T(handler, std::forward<Args>(args)...)
+ T::T(Handler const&, Args&&...)
@endcode
- @param handler The handler to associate with the owned
- object. The argument will be moved.
-
- @param args Optional arguments forwarded to
- the owned object's constructor.
- */
- template<class... Args>
- handler_ptr(Handler&& handler, Args&&... args);
-
- /** Construct a new @ref handler_ptr
-
- This creates a new @ref handler_ptr with an owned object
- of type `T`. The allocator associated with the handler will
- be used to allocate memory for the owned object. The constructor
- for the owned object will be called thusly:
-
- @code
- T(handler, std::forward<Args>(args)...)
- @endcode
+ @par Exception Safety
+ Strong guarantee.
@param handler The handler to associate with the owned
- object. The argument will be copied.
+ object. The argument will be moved if it is an xvalue.
@param args Optional arguments forwarded to
the owned object's constructor.
*/
- template<class... Args>
- handler_ptr(Handler const& handler, Args&&... args);
+ template<class DeducedHandler, class... Args>
+ explicit handler_ptr(DeducedHandler&& handler, Args&&... args);
- /// Returns a reference to the handler
- handler_type&
+ /// Returns a const reference to the handler
+ handler_type const&
handler() const
{
- return p_->handler;
+ return *reinterpret_cast<Handler const*>(&h_);
}
- /// Returns `true` if `*this` owns an object.
- explicit
- operator bool() const
+ /// Returns a reference to the handler
+ handler_type&
+ handler()
{
- return p_ && p_->t;
+ return *reinterpret_cast<Handler*>(&h_);
}
/** Returns a pointer to the owned object.
-
- If `*this` owns an object, a pointer to the
- object is returned, else `nullptr` is returned.
*/
T*
get() const
{
- return p_ ? p_->t : nullptr;
+ return t_;
}
/// Return a reference to the owned object.
T&
operator*() const
{
- return *p_->t;
+ return *t_;
}
/// Return a pointer to the owned object.
T*
operator->() const
{
- return p_->t;
+ return t_;
}
/** Release ownership of the handler
- If `*this` owns an object, it is first destroyed.
+ Requires: `*this` owns an object
+
+ Before this function returns, the owned object is
+ destroyed, satisfying the deallocation-before-invocation
+ Asio guarantee.
@return The released handler.
*/
@@ -191,9 +171,7 @@ public:
This function invokes the handler in the owned object
with a forwarded argument list. Before the invocation,
the owned object is destroyed, satisfying the
- deallocation-before-invocation Asio guarantee. All
- instances of @ref handler_ptr which refer to the
- same owned object will be reset, including this instance.
+ deallocation-before-invocation Asio guarantee.
@note Care must be taken when the arguments are themselves
stored in the owned object. Such arguments must first be
diff --git a/boost/beast/core/impl/buffered_read_stream.ipp b/boost/beast/core/impl/buffered_read_stream.ipp
index 9e9fa53065..1ae76b4d34 100644
--- a/boost/beast/core/impl/buffered_read_stream.ipp
+++ b/boost/beast/core/impl/buffered_read_stream.ipp
@@ -19,6 +19,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
@@ -37,7 +38,7 @@ class buffered_read_stream<
public:
read_some_op(read_some_op&&) = default;
- read_some_op(read_some_op const&) = default;
+ read_some_op(read_some_op const&) = delete;
template<class DeducedHandler, class... Args>
read_some_op(DeducedHandler&& h,
@@ -55,7 +56,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type =
@@ -65,7 +66,7 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, s_.get_executor());
}
@@ -80,6 +81,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, read_some_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
template<class Stream, class DynamicBuffer>
@@ -121,7 +130,7 @@ read_some_op<MutableBufferSequence, Handler>::operator()(
case 2:
s_.buffer_.commit(bytes_transferred);
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case 3:
bytes_transferred =
@@ -233,11 +242,11 @@ async_read_some(
if(buffer_.size() == 0 && capacity_ == 0)
return next_layer_.async_read_some(buffers,
std::forward<ReadHandler>(handler));
- boost::asio::async_completion<ReadHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler, *this, buffers}(
+ std::move(init.completion_handler), *this, buffers}(
error_code{}, 0);
return init.result.get();
}
diff --git a/boost/beast/core/impl/buffers_cat.ipp b/boost/beast/core/impl/buffers_cat.ipp
index d92d55233a..2e82e887fc 100644
--- a/boost/beast/core/impl/buffers_cat.ipp
+++ b/boost/beast/core/impl/buffers_cat.ipp
@@ -11,9 +11,9 @@
#define BOOST_BEAST_IMPL_BUFFERS_CAT_IPP
#include <boost/beast/core/detail/type_traits.hpp>
+#include <boost/beast/core/detail/variant.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/throw_exception.hpp>
-#include <array>
#include <cstdint>
#include <iterator>
#include <new>
@@ -27,38 +27,28 @@ namespace beast {
template<class... Bn>
class buffers_cat_view<Bn...>::const_iterator
{
- std::size_t n_;
- std::tuple<Bn...> const* bn_;
- std::array<char, detail::max_sizeof<
- typename detail::buffer_sequence_iterator<Bn>::type...>()> buf_;
+ // VFALCO The logic to skip empty sequences fails
+ // if there is just one buffer in the list.
+ static_assert(sizeof...(Bn) >= 2,
+ "A minimum of two sequences are required");
- friend class buffers_cat_view<Bn...>;
-
- template<std::size_t I>
- using C = std::integral_constant<std::size_t, I>;
+ struct past_end
+ {
+ operator bool() const noexcept
+ {
+ return true;
+ }
+ };
- template<std::size_t I>
- using iter_t = typename detail::buffer_sequence_iterator<
- typename std::tuple_element<I, std::tuple<Bn...>>::type>::type;
+ std::tuple<Bn...> const* bn_ = nullptr;
+ detail::variant<typename
+ detail::buffer_sequence_iterator<Bn>::type...,
+ past_end> it_;
- template<std::size_t I>
- iter_t<I>&
- iter()
- {
- // type-pun
- return *reinterpret_cast<
- iter_t<I>*>(static_cast<void*>(buf_.data()));
- }
+ friend class buffers_cat_view<Bn...>;
template<std::size_t I>
- iter_t<I> const&
- iter() const
- {
- // type-pun
- return *reinterpret_cast<
- iter_t<I> const*>(static_cast<
- void const*>(buf_.data()));
- }
+ using C = std::integral_constant<std::size_t, I>;
public:
using value_type = typename
@@ -69,12 +59,11 @@ public:
using iterator_category =
std::bidirectional_iterator_tag;
- ~const_iterator();
- const_iterator();
- const_iterator(const_iterator&& other);
- const_iterator(const_iterator const& other);
- const_iterator& operator=(const_iterator&& other);
- const_iterator& operator=(const_iterator const& other);
+ const_iterator() = default;
+ const_iterator(const_iterator&& other) = default;
+ const_iterator(const_iterator const& other) = default;
+ const_iterator& operator=(const_iterator&& other) = default;
+ const_iterator& operator=(const_iterator const& other) = default;
bool
operator==(const_iterator const& other) const;
@@ -97,9 +86,11 @@ public:
const_iterator
operator++(int);
+ // deprecated
const_iterator&
operator--();
+ // deprecated
const_iterator
operator--(int);
@@ -107,13 +98,6 @@ private:
const_iterator(
std::tuple<Bn...> const& bn, bool at_end);
- void
- construct(C<sizeof...(Bn)> const&)
- {
- auto constexpr I = sizeof...(Bn);
- n_ = I;
- }
-
template<std::size_t I>
void
construct(C<I> const&)
@@ -121,144 +105,90 @@ private:
if(boost::asio::buffer_size(
std::get<I>(*bn_)) != 0)
{
- n_ = I;
- new(&buf_[0]) iter_t<I>{
+ it_.template emplace<I+1>(
boost::asio::buffer_sequence_begin(
- std::get<I>(*bn_))};
+ std::get<I>(*bn_)));
return;
}
construct(C<I+1>{});
}
void
- rconstruct(C<0> const&)
- {
- auto constexpr I = 0;
- if(boost::asio::buffer_size(
- std::get<I>(*bn_)) != 0)
- {
- n_ = I;
- new(&buf_[0]) iter_t<I>{
- boost::asio::buffer_sequence_end(
- std::get<I>(*bn_))};
- return;
- }
- BOOST_THROW_EXCEPTION(std::logic_error{
- "invalid iterator"});
- }
-
- template<std::size_t I>
- void
- rconstruct(C<I> const&)
+ construct(C<sizeof...(Bn)-1> const&)
{
- if(boost::asio::buffer_size(
- std::get<I>(*bn_)) != 0)
- {
- n_ = I;
- new(&buf_[0]) iter_t<I>{
- boost::asio::buffer_sequence_end(
- std::get<I>(*bn_))};
- return;
- }
- rconstruct(C<I-1>{});
+ auto constexpr I = sizeof...(Bn)-1;
+ it_.template emplace<I+1>(
+ boost::asio::buffer_sequence_begin(
+ std::get<I>(*bn_)));
}
void
- destroy(C<sizeof...(Bn)> const&)
+ construct(C<sizeof...(Bn)> const&)
{
- return;
+ // end
+ auto constexpr I = sizeof...(Bn);
+ it_.template emplace<I+1>();
}
template<std::size_t I>
void
- destroy(C<I> const&)
+ next(C<I> const&)
{
- if(n_ == I)
+ if(boost::asio::buffer_size(
+ std::get<I>(*bn_)) != 0)
{
- using Iter = iter_t<I>;
- iter<I>().~Iter();
+ it_.template emplace<I+1>(
+ boost::asio::buffer_sequence_begin(
+ std::get<I>(*bn_)));
return;
}
- destroy(C<I+1>{});
+ next(C<I+1>{});
}
void
- move(const_iterator&&,
- C<sizeof...(Bn)> const&)
+ next(C<sizeof...(Bn)> const&)
{
+ // end
+ auto constexpr I = sizeof...(Bn);
+ it_.template emplace<I+1>();
}
template<std::size_t I>
void
- move(const_iterator&& other,
- C<I> const&)
+ prev(C<I> const&)
{
- if(n_ == I)
+ if(boost::asio::buffer_size(
+ std::get<I>(*bn_)) != 0)
{
- new(&buf_[0]) iter_t<I>{
- std::move(other.iter<I>())};
+ it_.template emplace<I+1>(
+ boost::asio::buffer_sequence_end(
+ std::get<I>(*bn_)));
return;
}
- move(std::move(other), C<I+1>{});
- }
-
- void
- copy(const_iterator const&,
- C<sizeof...(Bn)> const&)
- {
+ prev(C<I-1>{});
}
- template<std::size_t I>
void
- copy(const_iterator const& other,
- C<I> const&)
+ prev(C<0> const&)
{
- if(n_ == I)
- {
- new(&buf_[0]) iter_t<I>{
- other.iter<I>()};
- return;
- }
- copy(other, C<I+1>{});
- }
-
- bool
- equal(const_iterator const&,
- C<sizeof...(Bn)> const&) const
- {
- return true;
- }
-
- template<std::size_t I>
- bool
- equal(const_iterator const& other,
- C<I> const&) const
- {
- if(n_ == I)
- return iter<I>() == other.iter<I>();
- return equal(other, C<I+1>{});
- }
-
- [[noreturn]]
- reference
- dereference(C<sizeof...(Bn)> const&) const
- {
- BOOST_THROW_EXCEPTION(std::logic_error{
- "invalid iterator"});
+ auto constexpr I = 0;
+ it_.template emplace<I+1>(
+ boost::asio::buffer_sequence_end(
+ std::get<I>(*bn_)));
}
template<std::size_t I>
reference
dereference(C<I> const&) const
{
- if(n_ == I)
- return *iter<I>();
+ if(it_.index() == I+1)
+ return *it_.template get<I+1>();
return dereference(C<I+1>{});
}
[[noreturn]]
- void
- increment(C<sizeof...(Bn)> const&)
+ reference
+ dereference(C<sizeof...(Bn)> const&) const
{
BOOST_THROW_EXCEPTION(std::logic_error{
"invalid iterator"});
@@ -268,25 +198,31 @@ private:
void
increment(C<I> const&)
{
- if(n_ == I)
+ if(it_.index() == I+1)
{
- if(++iter<I>() !=
+ if(++it_.template get<I+1>() !=
boost::asio::buffer_sequence_end(
std::get<I>(*bn_)))
return;
- using Iter = iter_t<I>;
- iter<I>().~Iter();
- return construct(C<I+1>{});
+ return next(C<I+1>{});
}
increment(C<I+1>{});
}
+ [[noreturn]]
+ void
+ increment(C<sizeof...(Bn)> const&)
+ {
+ BOOST_THROW_EXCEPTION(std::logic_error{
+ "invalid iterator"});
+ }
+
void
decrement(C<sizeof...(Bn)> const&)
{
auto constexpr I = sizeof...(Bn);
- if(n_ == I)
- rconstruct(C<I-1>{});
+ if(it_.index() == I+1)
+ prev(C<I-1>{});
decrement(C<I-1>{});
}
@@ -294,19 +230,16 @@ private:
void
decrement(C<I> const&)
{
- if(n_ == I)
+ if(it_.index() == I+1)
{
- if(iter<I>() !=
+ if(it_.template get<I+1>() !=
boost::asio::buffer_sequence_begin(
std::get<I>(*bn_)))
{
- --iter<I>();
+ --it_.template get<I+1>();
return;
}
- --n_;
- using Iter = iter_t<I>;
- iter<I>().~Iter();
- rconstruct(C<I-1>{});
+ prev(C<I-1>{});
}
decrement(C<I-1>{});
}
@@ -315,11 +248,11 @@ private:
decrement(C<0> const&)
{
auto constexpr I = 0;
- if(iter<I>() !=
+ if(it_.template get<I+1>() !=
boost::asio::buffer_sequence_begin(
std::get<I>(*bn_)))
{
- --iter<I>();
+ --it_.template get<I+1>();
return;
}
BOOST_THROW_EXCEPTION(std::logic_error{
@@ -331,97 +264,33 @@ private:
template<class... Bn>
buffers_cat_view<Bn...>::
-const_iterator::~const_iterator()
-{
- destroy(C<0>{});
-}
-
-template<class... Bn>
-buffers_cat_view<Bn...>::
-const_iterator::const_iterator()
- : n_(sizeof...(Bn))
- , bn_(nullptr)
-{
-}
-
-template<class... Bn>
-buffers_cat_view<Bn...>::
-const_iterator::const_iterator(
+const_iterator::
+const_iterator(
std::tuple<Bn...> const& bn, bool at_end)
: bn_(&bn)
{
- if(at_end)
- n_ = sizeof...(Bn);
- else
+ if(! at_end)
construct(C<0>{});
-}
-
-template<class... Bn>
-buffers_cat_view<Bn...>::
-const_iterator::const_iterator(const_iterator&& other)
- : n_(other.n_)
- , bn_(other.bn_)
-{
- move(std::move(other), C<0>{});
-}
-
-template<class... Bn>
-buffers_cat_view<Bn...>::
-const_iterator::const_iterator(const_iterator const& other)
- : n_(other.n_)
- , bn_(other.bn_)
-{
- copy(other, C<0>{});
-}
-
-template<class... Bn>
-auto
-buffers_cat_view<Bn...>::
-const_iterator::operator=(const_iterator&& other) ->
- const_iterator&
-{
- if(&other == this)
- return *this;
- destroy(C<0>{});
- n_ = other.n_;
- bn_ = other.bn_;
- // VFALCO What about exceptions?
- move(std::move(other), C<0>{});
- return *this;
-}
-
-template<class... Bn>
-auto
-buffers_cat_view<Bn...>::
-const_iterator::operator=(const_iterator const& other) ->
-const_iterator&
-{
- if(&other == this)
- return *this;
- destroy(C<0>{});
- n_ = other.n_;
- bn_ = other.bn_;
- // VFALCO What about exceptions?
- copy(other, C<0>{});
- return *this;
+ else
+ construct(C<sizeof...(Bn)>{});
}
template<class... Bn>
bool
buffers_cat_view<Bn...>::
-const_iterator::operator==(const_iterator const& other) const
+const_iterator::
+operator==(const_iterator const& other) const
{
if(bn_ != other.bn_)
return false;
- if(n_ != other.n_)
- return false;
- return equal(other, C<0>{});
+ return it_ == other.it_;
}
template<class... Bn>
auto
buffers_cat_view<Bn...>::
-const_iterator::operator*() const ->
+const_iterator::
+operator*() const ->
reference
{
return dereference(C<0>{});
@@ -430,7 +299,8 @@ const_iterator::operator*() const ->
template<class... Bn>
auto
buffers_cat_view<Bn...>::
-const_iterator::operator++() ->
+const_iterator::
+operator++() ->
const_iterator&
{
increment(C<0>{});
@@ -440,7 +310,8 @@ const_iterator::operator++() ->
template<class... Bn>
auto
buffers_cat_view<Bn...>::
-const_iterator::operator++(int) ->
+const_iterator::
+operator++(int) ->
const_iterator
{
auto temp = *this;
@@ -451,7 +322,8 @@ const_iterator::operator++(int) ->
template<class... Bn>
auto
buffers_cat_view<Bn...>::
-const_iterator::operator--() ->
+const_iterator::
+operator--() ->
const_iterator&
{
decrement(C<sizeof...(Bn)>{});
@@ -461,7 +333,8 @@ const_iterator::operator--() ->
template<class... Bn>
auto
buffers_cat_view<Bn...>::
-const_iterator::operator--(int) ->
+const_iterator::
+operator--(int) ->
const_iterator
{
auto temp = *this;
diff --git a/boost/beast/core/impl/buffers_prefix.ipp b/boost/beast/core/impl/buffers_prefix.ipp
index 0bb92cc3ae..a45483854f 100644
--- a/boost/beast/core/impl/buffers_prefix.ipp
+++ b/boost/beast/core/impl/buffers_prefix.ipp
@@ -53,7 +53,7 @@ class buffers_prefix_view<BufferSequence>::const_iterator
public:
using value_type = typename std::conditional<
- std::is_convertible<typename
+ boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
boost::asio::mutable_buffer>::value,
boost::asio::mutable_buffer,
diff --git a/boost/beast/core/impl/buffers_suffix.ipp b/boost/beast/core/impl/buffers_suffix.ipp
index 6356d63e0c..4385fe500d 100644
--- a/boost/beast/core/impl/buffers_suffix.ipp
+++ b/boost/beast/core/impl/buffers_suffix.ipp
@@ -11,6 +11,7 @@
#define BOOST_BEAST_IMPL_BUFFERS_SUFFIX_IPP
#include <boost/beast/core/type_traits.hpp>
+#include <boost/type_traits.hpp>
#include <algorithm>
#include <cstdint>
#include <iterator>
@@ -33,7 +34,7 @@ class buffers_suffix<Buffers>::const_iterator
public:
using value_type = typename std::conditional<
- std::is_convertible<typename
+ boost::is_convertible<typename
std::iterator_traits<iter_type>::value_type,
boost::asio::mutable_buffer>::value,
boost::asio::mutable_buffer,
diff --git a/boost/beast/core/impl/file_posix.ipp b/boost/beast/core/impl/file_posix.ipp
index 96ccdc3bbe..c30a7d020f 100644
--- a/boost/beast/core/impl/file_posix.ipp
+++ b/boost/beast/core/impl/file_posix.ipp
@@ -224,7 +224,7 @@ size(error_code& ec) const
{
if(fd_ == -1)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
struct stat st;
@@ -244,7 +244,7 @@ pos(error_code& ec) const
{
if(fd_ == -1)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
auto const result = ::lseek(fd_, 0, SEEK_CUR);
@@ -264,7 +264,7 @@ seek(std::uint64_t offset, error_code& ec)
{
if(fd_ == -1)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return;
}
auto const result = ::lseek(fd_, offset, SEEK_SET);
@@ -283,7 +283,7 @@ read(void* buffer, std::size_t n, error_code& ec) const
{
if(fd_ == -1)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
std::size_t nread = 0;
@@ -319,7 +319,7 @@ write(void const* buffer, std::size_t n, error_code& ec)
{
if(fd_ == -1)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
std::size_t nwritten = 0;
diff --git a/boost/beast/core/impl/file_stdio.ipp b/boost/beast/core/impl/file_stdio.ipp
index ca5cb0cbde..60a0f3fc0e 100644
--- a/boost/beast/core/impl/file_stdio.ipp
+++ b/boost/beast/core/impl/file_stdio.ipp
@@ -122,7 +122,7 @@ size(error_code& ec) const
{
if(! f_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
long pos = std::ftell(f_);
@@ -159,7 +159,7 @@ pos(error_code& ec) const
{
if(! f_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
long pos = std::ftell(f_);
@@ -179,7 +179,7 @@ seek(std::uint64_t offset, error_code& ec)
{
if(! f_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return;
}
if(offset > (std::numeric_limits<long>::max)())
@@ -202,7 +202,7 @@ read(void* buffer, std::size_t n, error_code& ec) const
{
if(! f_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
auto nread = std::fread(buffer, 1, n, f_);
@@ -221,7 +221,7 @@ write(void const* buffer, std::size_t n, error_code& ec)
{
if(! f_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
auto nwritten = std::fwrite(buffer, 1, n, f_);
diff --git a/boost/beast/core/impl/file_win32.ipp b/boost/beast/core/impl/file_win32.ipp
index de4abae41f..c1b4cc6c7d 100644
--- a/boost/beast/core/impl/file_win32.ipp
+++ b/boost/beast/core/impl/file_win32.ipp
@@ -216,7 +216,7 @@ size(error_code& ec) const
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
boost::winapi::LARGE_INTEGER_ fileSize;
@@ -237,7 +237,7 @@ pos(error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
boost::winapi::LARGE_INTEGER_ in;
@@ -261,7 +261,7 @@ seek(std::uint64_t offset, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return;
}
boost::winapi::LARGE_INTEGER_ in;
@@ -283,7 +283,7 @@ read(void* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
std::size_t nread = 0;
@@ -300,9 +300,9 @@ read(void* buffer, std::size_t n, error_code& ec)
boost::winapi::DWORD_ bytesRead;
if(! ::ReadFile(h_, buffer, amount, &bytesRead, 0))
{
- auto const dwError = ::GetLastError();
+ auto const dwError = boost::winapi::GetLastError();
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
- ec.assign(::GetLastError(), system_category());
+ ec.assign(dwError, system_category());
else
ec.assign(0, ec.category());
return nread;
@@ -324,7 +324,7 @@ write(void const* buffer, std::size_t n, error_code& ec)
{
if(h_ == boost::winapi::INVALID_HANDLE_VALUE_)
{
- ec.assign(errc::invalid_argument, generic_category());
+ ec = make_error_code(errc::invalid_argument);
return 0;
}
std::size_t nwritten = 0;
@@ -341,9 +341,9 @@ write(void const* buffer, std::size_t n, error_code& ec)
boost::winapi::DWORD_ bytesWritten;
if(! ::WriteFile(h_, buffer, amount, &bytesWritten, 0))
{
- auto const dwError = ::GetLastError();
+ auto const dwError = boost::winapi::GetLastError();
if(dwError != boost::winapi::ERROR_HANDLE_EOF_)
- ec.assign(::GetLastError(), system_category());
+ ec.assign(dwError, system_category());
else
ec.assign(0, ec.category());
return nwritten;
diff --git a/boost/beast/core/impl/handler_ptr.ipp b/boost/beast/core/impl/handler_ptr.ipp
index 15a159a8fd..99d1a894d5 100644
--- a/boost/beast/core/impl/handler_ptr.ipp
+++ b/boost/beast/core/impl/handler_ptr.ipp
@@ -18,87 +18,72 @@ namespace boost {
namespace beast {
template<class T, class Handler>
-template<class DeducedHandler, class... Args>
-inline
-handler_ptr<T, Handler>::P::
-P(DeducedHandler&& h, Args&&... args)
- : n(1)
- , handler(std::forward<DeducedHandler>(h))
+void
+handler_ptr<T, Handler>::
+clear()
{
- typename std::allocator_traits<
- boost::asio::associated_allocator_t<Handler>>::
- template rebind_alloc<T> alloc{
- boost::asio::get_associated_allocator(handler)};
- t = std::allocator_traits<decltype(alloc)>::allocate(alloc, 1);
- try
- {
- t = new(t) T{handler,
- std::forward<Args>(args)...};
- }
- catch(...)
- {
- std::allocator_traits<
- decltype(alloc)>::deallocate(alloc, t, 1);
- throw;
- }
+ typename beast::detail::allocator_traits<
+ boost::asio::associated_allocator_t<
+ Handler>>::template rebind_alloc<T> alloc(
+ boost::asio::get_associated_allocator(
+ handler()));
+ beast::detail::allocator_traits<
+ decltype(alloc)>::destroy(alloc, t_);
+ beast::detail::allocator_traits<
+ decltype(alloc)>::deallocate(alloc, t_, 1);
+ t_ = nullptr;
}
template<class T, class Handler>
handler_ptr<T, Handler>::
~handler_ptr()
{
- if(! p_)
- return;
- if(--p_->n)
- return;
- if(p_->t)
+ if(t_)
{
- p_->t->~T();
- typename std::allocator_traits<
- boost::asio::associated_allocator_t<Handler>>::
- template rebind_alloc<T> alloc{
- boost::asio::get_associated_allocator(
- p_->handler)};
- std::allocator_traits<
- decltype(alloc)>::deallocate(alloc, p_->t, 1);
+ clear();
+ handler().~Handler();
}
- delete p_;
}
template<class T, class Handler>
handler_ptr<T, Handler>::
handler_ptr(handler_ptr&& other)
- : p_(other.p_)
+ : t_(other.t_)
{
- other.p_ = nullptr;
-}
-
-template<class T, class Handler>
-handler_ptr<T, Handler>::
-handler_ptr(handler_ptr const& other)
- : p_(other.p_)
-{
- if(p_)
- ++p_->n;
-}
-
-template<class T, class Handler>
-template<class... Args>
-handler_ptr<T, Handler>::
-handler_ptr(Handler&& handler, Args&&... args)
- : p_(new P{std::move(handler),
- std::forward<Args>(args)...})
-{
- BOOST_STATIC_ASSERT(! std::is_array<T>::value);
+ if(other.t_)
+ {
+ new(&h_) Handler(std::move(other.handler()));
+ other.handler().~Handler();
+ other.t_ = nullptr;
+ }
}
template<class T, class Handler>
-template<class... Args>
+template<class DeducedHandler, class... Args>
handler_ptr<T, Handler>::
-handler_ptr(Handler const& handler, Args&&... args)
- : p_(new P{handler, std::forward<Args>(args)...})
+handler_ptr(DeducedHandler&& h, Args&&... args)
{
BOOST_STATIC_ASSERT(! std::is_array<T>::value);
+ typename beast::detail::allocator_traits<
+ boost::asio::associated_allocator_t<
+ Handler>>::template rebind_alloc<T> alloc{
+ boost::asio::get_associated_allocator(h)};
+ using A = decltype(alloc);
+ bool destroy = false;
+ auto deleter = [&alloc, &destroy](T* p)
+ {
+ if(destroy)
+ beast::detail::allocator_traits<A>::destroy(alloc, p);
+ beast::detail::allocator_traits<A>::deallocate(alloc, p, 1);
+ };
+ std::unique_ptr<T, decltype(deleter)> t{
+ beast::detail::allocator_traits<A>::allocate(alloc, 1), deleter};
+ beast::detail::allocator_traits<A>::construct(alloc, t.get(),
+ static_cast<DeducedHandler const&>(h),
+ std::forward<Args>(args)...);
+ destroy = true;
+ new(&h_) Handler(std::forward<DeducedHandler>(h));
+ t_ = t.release();
}
template<class T, class Handler>
@@ -107,18 +92,16 @@ handler_ptr<T, Handler>::
release_handler() ->
handler_type
{
- BOOST_ASSERT(p_);
- BOOST_ASSERT(p_->t);
- p_->t->~T();
- typename std::allocator_traits<
- boost::asio::associated_allocator_t<Handler>>::
- template rebind_alloc<T> alloc{
- boost::asio::get_associated_allocator(
- p_->handler)};
- std::allocator_traits<
- decltype(alloc)>::deallocate(alloc, p_->t, 1);
- p_->t = nullptr;
- return std::move(p_->handler);
+ BOOST_ASSERT(t_);
+ clear();
+ auto deleter = [](Handler* h)
+ {
+ h->~Handler();
+ };
+ std::unique_ptr<
+ Handler, decltype(deleter)> destroyer{
+ &handler(), deleter};
+ return std::move(handler());
}
template<class T, class Handler>
@@ -127,18 +110,16 @@ void
handler_ptr<T, Handler>::
invoke(Args&&... args)
{
- BOOST_ASSERT(p_);
- BOOST_ASSERT(p_->t);
- p_->t->~T();
- typename std::allocator_traits<
- boost::asio::associated_allocator_t<Handler>>::
- template rebind_alloc<T> alloc{
- boost::asio::get_associated_allocator(
- p_->handler)};
- std::allocator_traits<
- decltype(alloc)>::deallocate(alloc, p_->t, 1);
- p_->t = nullptr;
- p_->handler(std::forward<Args>(args)...);
+ BOOST_ASSERT(t_);
+ clear();
+ auto deleter = [](Handler* h)
+ {
+ h->~Handler();
+ };
+ std::unique_ptr<
+ Handler, decltype(deleter)> destroyer{
+ &handler(), deleter};
+ handler()(std::forward<Args>(args)...);
}
} // beast
diff --git a/boost/beast/core/impl/multi_buffer.ipp b/boost/beast/core/impl/multi_buffer.ipp
index 7b66694cb3..e7ae541f9c 100644
--- a/boost/beast/core/impl/multi_buffer.ipp
+++ b/boost/beast/core/impl/multi_buffer.ipp
@@ -132,7 +132,7 @@ class basic_multi_buffer<Allocator>::const_buffers_type
const_buffers_type(basic_multi_buffer const& b);
public:
- using value_type = boost::asio::mutable_buffer;
+ using value_type = boost::asio::const_buffer;
class const_iterator;
diff --git a/boost/beast/core/impl/static_buffer.ipp b/boost/beast/core/impl/static_buffer.ipp
index d93a1e6911..2fdb2d9a8a 100644
--- a/boost/beast/core/impl/static_buffer.ipp
+++ b/boost/beast/core/impl/static_buffer.ipp
@@ -35,10 +35,31 @@ static_buffer_base::
data() const ->
const_buffers_type
{
- using boost::asio::mutable_buffer;
+ using boost::asio::const_buffer;
const_buffers_type result;
if(in_off_ + in_size_ <= capacity_)
{
+ result[0] = const_buffer{begin_ + in_off_, in_size_};
+ result[1] = const_buffer{begin_, 0};
+ }
+ else
+ {
+ result[0] = const_buffer{begin_ + in_off_, capacity_ - in_off_};
+ result[1] = const_buffer{begin_, in_size_ - (capacity_ - in_off_)};
+ }
+ return result;
+}
+
+inline
+auto
+static_buffer_base::
+mutable_data() ->
+ mutable_buffers_type
+{
+ using boost::asio::mutable_buffer;
+ mutable_buffers_type result;
+ if(in_off_ + in_size_ <= capacity_)
+ {
result[0] = mutable_buffer{begin_ + in_off_, in_size_};
result[1] = mutable_buffer{begin_, 0};
}
diff --git a/boost/beast/core/static_buffer.hpp b/boost/beast/core/static_buffer.hpp
index 05496c4018..86f06b1efd 100644
--- a/boost/beast/core/static_buffer.hpp
+++ b/boost/beast/core/static_buffer.hpp
@@ -52,7 +52,7 @@ class static_buffer_base
public:
/// The type used to represent the input sequence as a list of buffers.
using const_buffers_type =
- std::array<boost::asio::mutable_buffer, 2>;
+ std::array<boost::asio::const_buffer, 2>;
/// The type used to represent the output sequence as a list of buffers.
using mutable_buffers_type =
@@ -94,6 +94,11 @@ public:
const_buffers_type
data() const;
+ /** Get a mutable list of buffers that represent the input sequence.
+ */
+ mutable_buffers_type
+ mutable_data();
+
/** Get a list of buffers that represent the output sequence, with the given size.
@param size The number of bytes to request.
diff --git a/boost/beast/core/string.hpp b/boost/beast/core/string.hpp
index f262b565da..27bfa57165 100644
--- a/boost/beast/core/string.hpp
+++ b/boost/beast/core/string.hpp
@@ -12,34 +12,12 @@
#include <boost/beast/core/detail/config.hpp>
#include <boost/version.hpp>
-#ifndef BOOST_BEAST_NO_BOOST_STRING_VIEW
-# if BOOST_VERSION >= 106400
-# define BOOST_BEAST_NO_BOOST_STRING_VIEW 0
-# else
-# define BOOST_BEAST_NO_BOOST_STRING_VIEW 1
-# endif
-#endif
-
-#if BOOST_BEAST_NO_BOOST_STRING_VIEW
-#include <boost/utility/string_ref.hpp>
-#else
#include <boost/utility/string_view.hpp>
-#endif
-
#include <algorithm>
namespace boost {
namespace beast {
-#if BOOST_BEAST_NO_BOOST_STRING_VIEW
-/// The type of string view used by the library
-using string_view = boost::string_ref;
-
-/// The type of basic string view used by the library
-template<class CharT, class Traits>
-using basic_string_view =
- boost::basic_string_ref<CharT, Traits>;
-#else
/// The type of string view used by the library
using string_view = boost::string_view;
@@ -47,7 +25,6 @@ using string_view = boost::string_view;
template<class CharT, class Traits>
using basic_string_view =
boost::basic_string_view<CharT, Traits>;
-#endif
namespace detail {
@@ -55,9 +32,8 @@ inline
char
ascii_tolower(char c)
{
- if(c >= 'A' && c <= 'Z')
- c += 'a' - 'A';
- return c;
+ return ((static_cast<unsigned>(c) - 65U) < 26) ?
+ c + 'a' - 'A' : c;
}
template<class = void>
@@ -77,17 +53,18 @@ iequals(
a = *p1++;
b = *p2++;
if(a != b)
- goto slow;
- }
- return true;
-
- while(n--)
- {
- slow:
- if(ascii_tolower(a) != ascii_tolower(b))
- return false;
- a = *p1++;
- b = *p2++;
+ {
+ // slow loop
+ do
+ {
+ if(ascii_tolower(a) != ascii_tolower(b))
+ return false;
+ a = *p1++;
+ b = *p2++;
+ }
+ while(n--);
+ return true;
+ }
}
return true;
}
diff --git a/boost/beast/core/type_traits.hpp b/boost/beast/core/type_traits.hpp
index d622e0e8ec..f5e466a759 100644
--- a/boost/beast/core/type_traits.hpp
+++ b/boost/beast/core/type_traits.hpp
@@ -52,7 +52,7 @@ template<class T, class Signature>
using is_completion_handler = std::integral_constant<bool, ...>;
#else
using is_completion_handler = std::integral_constant<bool,
- std::is_copy_constructible<typename std::decay<T>::type>::value &&
+ std::is_move_constructible<typename std::decay<T>::type>::value &&
detail::is_invocable<T, Signature>::value>;
#endif
@@ -122,10 +122,10 @@ struct has_get_executor<T, beast::detail::void_t<decltype(
(void)0)>> : std::true_type {};
#endif
-/** Returns `T::lowest_layer_type` if it exists, else `T`
+/** Alias for `T::lowest_layer_type` if it exists, else `T`
- This will contain a nested `type` equal to `T::lowest_layer_type`
- if it exists, else `type` will be equal to `T`.
+ This will be a type alias for `T::lowest_layer_type`
+ if it exists, else it will be an alias for `T`.
@par Example
@@ -136,7 +136,7 @@ struct has_get_executor<T, beast::detail::void_t<decltype(
struct stream_wrapper
{
using next_layer_type = typename std::remove_reference<Stream>::type;
- using lowest_layer_type = typename get_lowest_layer<stream_type>::type;
+ using lowest_layer_type = get_lowest_layer<stream_type>;
};
@endcode
@@ -146,25 +146,15 @@ struct has_get_executor<T, beast::detail::void_t<decltype(
/// Alias for `std::true_type` if `T` wraps another stream
template<class T>
using is_stream_wrapper : std::integral_constant<bool,
- ! std::is_same<T, typename get_lowest_layer<T>::type>::value> {};
+ ! std::is_same<T, get_lowest_layer<T>>::value> {};
@endcode
*/
#if BOOST_BEAST_DOXYGEN
template<class T>
struct get_lowest_layer;
#else
-template<class T, class = void>
-struct get_lowest_layer
-{
- using type = T;
-};
-
template<class T>
-struct get_lowest_layer<T, detail::void_t<
- typename T::lowest_layer_type>>
-{
- using type = typename T::lowest_layer_type;
-};
+using get_lowest_layer = typename detail::get_lowest_layer_helper<T>::type;
#endif
/** Determine if `T` meets the requirements of @b AsyncReadStream.
diff --git a/boost/beast/http/basic_dynamic_body.hpp b/boost/beast/http/basic_dynamic_body.hpp
index 76c499c554..7d850d76f3 100644
--- a/boost/beast/http/basic_dynamic_body.hpp
+++ b/boost/beast/http/basic_dynamic_body.hpp
@@ -70,9 +70,8 @@ struct basic_dynamic_body
public:
template<bool isRequest, class Fields>
explicit
- reader(message<isRequest,
- basic_dynamic_body, Fields>& msg)
- : body_(msg.body())
+ reader(header<isRequest, Fields>&, value_type& b)
+ : body_(b)
{
}
@@ -140,9 +139,8 @@ struct basic_dynamic_body
template<bool isRequest, class Fields>
explicit
- writer(message<isRequest,
- basic_dynamic_body, Fields> const& m)
- : body_(m.body())
+ writer(header<isRequest, Fields> const&, value_type const& b)
+ : body_(b)
{
}
diff --git a/boost/beast/http/basic_file_body.hpp b/boost/beast/http/basic_file_body.hpp
index cec72a8f54..6d1de9a3b8 100644
--- a/boost/beast/http/basic_file_body.hpp
+++ b/boost/beast/http/basic_file_body.hpp
@@ -239,8 +239,8 @@ public:
// Constructor.
//
- // `m` holds the message we are serializing, which will
- // always have the `basic_file_body` as the body type.
+ // `h` holds the headers of the message we are
+ // serializing, while `b` holds the body.
//
// Note that the message is passed by non-const reference.
// This is intentional, because reading from the file
@@ -262,8 +262,7 @@ public:
// a time.
//
template<bool isRequest, class Fields>
- writer(message<
- isRequest, basic_file_body, Fields>& m);
+ writer(header<isRequest, Fields>& h, value_type& b);
// Initializer
//
@@ -296,9 +295,11 @@ template<class File>
template<bool isRequest, class Fields>
basic_file_body<File>::
writer::
-writer(message<isRequest, basic_file_body, Fields>& m)
- : body_(m.body())
+writer(header<isRequest, Fields>& h, value_type& b)
+ : body_(b)
{
+ boost::ignore_unused(h);
+
// The file must already be open
BOOST_ASSERT(body_.file_.is_open());
@@ -398,13 +399,12 @@ public:
//
// This is called after the header is parsed and
// indicates that a non-zero sized body may be present.
- // `m` holds the message we are receiving, which will
- // always have the `basic_file_body` as the body type.
+ // `h` holds the received message headers.
+ // `b` is an instance of `basic_file_body`.
//
template<bool isRequest, class Fields>
explicit
- reader(
- message<isRequest, basic_file_body, Fields>& m);
+ reader(header<isRequest, Fields>&h, value_type& b);
// Initializer
//
@@ -447,9 +447,10 @@ template<class File>
template<bool isRequest, class Fields>
basic_file_body<File>::
reader::
-reader(message<isRequest, basic_file_body, Fields>& m)
- : body_(m.body())
+reader(header<isRequest, Fields>& h, value_type& body)
+ : body_(body)
{
+ boost::ignore_unused(h);
}
template<class File>
diff --git a/boost/beast/http/buffer_body.hpp b/boost/beast/http/buffer_body.hpp
index 675ea9475a..3ffe0a002a 100644
--- a/boost/beast/http/buffer_body.hpp
+++ b/boost/beast/http/buffer_body.hpp
@@ -105,8 +105,8 @@ struct buffer_body
public:
template<bool isRequest, class Fields>
explicit
- reader(message<isRequest, buffer_body, Fields>& m)
- : body_(m.body())
+ reader(header<isRequest, Fields>&, value_type& b)
+ : body_(b)
{
}
@@ -167,9 +167,8 @@ struct buffer_body
template<bool isRequest, class Fields>
explicit
- writer(message<isRequest,
- buffer_body, Fields> const& msg)
- : body_(msg.body())
+ writer(header<isRequest, Fields> const&, value_type const& b)
+ : body_(b)
{
}
diff --git a/boost/beast/http/detail/rfc7230.hpp b/boost/beast/http/detail/rfc7230.hpp
index fdabc1a4d6..fac6790579 100644
--- a/boost/beast/http/detail/rfc7230.hpp
+++ b/boost/beast/http/detail/rfc7230.hpp
@@ -352,8 +352,8 @@ increment()
{
it = first;
};
- v.first.clear();
- v.second.clear();
+ v.first = {};
+ v.second = {};
detail::skip_ows(it, last);
first = it;
if(it == last)
diff --git a/boost/beast/http/detail/type_traits.hpp b/boost/beast/http/detail/type_traits.hpp
index c9a06f9784..1d0c991826 100644
--- a/boost/beast/http/detail/type_traits.hpp
+++ b/boost/beast/http/detail/type_traits.hpp
@@ -194,6 +194,22 @@ struct is_fields_helper : T
t10::value && t11::value && t12::value>;
};
+template<class T>
+using has_deprecated_body_writer =
+ std::integral_constant<bool,
+ std::is_constructible<typename T::writer,
+ message<true, T, detail::fields_model>&>::value &&
+ std::is_constructible<typename T::writer,
+ message<false, T, detail::fields_model>&>::value>;
+
+template<class T>
+using has_deprecated_body_reader =
+ std::integral_constant<bool,
+ std::is_constructible<typename T::reader,
+ message<true, T, detail::fields_model>&>::value &&
+ std::is_constructible<typename T::reader,
+ message<false, T, detail::fields_model>&>::value>;
+
} // detail
} // http
} // beast
diff --git a/boost/beast/http/empty_body.hpp b/boost/beast/http/empty_body.hpp
index 1845a22992..d56c14b4ef 100644
--- a/boost/beast/http/empty_body.hpp
+++ b/boost/beast/http/empty_body.hpp
@@ -63,7 +63,7 @@ struct empty_body
{
template<bool isRequest, class Fields>
explicit
- reader(message<isRequest, empty_body, Fields>&)
+ reader(header<isRequest, Fields>&, value_type&)
{
}
@@ -100,12 +100,11 @@ struct empty_body
struct writer
{
using const_buffers_type =
- boost::asio::null_buffers;
+ boost::asio::const_buffer;
template<bool isRequest, class Fields>
explicit
- writer(message<isRequest,
- empty_body, Fields> const&)
+ writer(header<isRequest, Fields> const&, value_type const&)
{
}
diff --git a/boost/beast/http/error.hpp b/boost/beast/http/error.hpp
index 841a99de25..b3d9fb1188 100644
--- a/boost/beast/http/error.hpp
+++ b/boost/beast/http/error.hpp
@@ -22,15 +22,10 @@ enum class error
{
/** The end of the stream was reached.
- This error is returned under the following conditions:
-
- @li When attempting to read HTTP data from a stream and the stream
- read returns the error `boost::asio::error::eof` before any new octets
- have been received.
-
- @li When sending a complete HTTP message at once and the semantics of
- the message are that the connection should be closed to indicate the
- end of the message.
+ This error is returned when attempting to read HTTP data,
+ and the stream returns the error `boost::asio::error::eof`
+ before any octets corresponding to a new HTTP message have
+ been received.
*/
end_of_stream = 1,
diff --git a/boost/beast/http/field.hpp b/boost/beast/http/field.hpp
index 3d1446addc..09d9dfffdf 100644
--- a/boost/beast/http/field.hpp
+++ b/boost/beast/http/field.hpp
@@ -38,6 +38,7 @@ enum class field : unsigned short
access_control_allow_headers,
access_control_allow_methods,
access_control_allow_origin,
+ access_control_expose_headers,
access_control_max_age,
access_control_request_headers,
access_control_request_method,
diff --git a/boost/beast/http/fields.hpp b/boost/beast/http/fields.hpp
index 06c950ee5a..59cb338b83 100644
--- a/boost/beast/http/fields.hpp
+++ b/boost/beast/http/fields.hpp
@@ -14,6 +14,7 @@
#include <boost/beast/core/string_param.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/beast/core/detail/allocator.hpp>
+#include <boost/beast/core/detail/empty_base_optimization.hpp>
#include <boost/beast/http/field.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/intrusive/list.hpp>
@@ -51,7 +52,15 @@ namespace http {
*/
template<class Allocator>
class basic_fields
+#ifndef BOOST_BEAST_DOXYGEN
+ : private beast::detail::empty_base_optimization<Allocator>
+#endif
{
+ // Fancy pointers are not supported
+ static_assert(std::is_pointer<typename
+ std::allocator_traits<Allocator>::pointer>::value,
+ "Allocator must use regular pointers");
+
friend class fields_test; // for `header`
static std::size_t constexpr max_static_buffer = 4096;
@@ -93,7 +102,7 @@ public:
value_type& operator=(value_type const&) = delete;
/// Returns the field enum, which can be @ref field::unknown
- field const
+ field
name() const;
/// Returns the field name as a string
@@ -179,6 +188,19 @@ private:
boost::intrusive::constant_time_size<true>,
boost::intrusive::compare<key_compare>>::type;
+ using align_type = typename
+ boost::type_with_alignment<alignof(value_type)>::type;
+
+ using rebind_type = typename
+ beast::detail::allocator_traits<Allocator>::
+ template rebind_alloc<align_type>;
+
+ using alloc_traits =
+ beast::detail::allocator_traits<rebind_type>;
+
+ using size_type = typename
+ beast::detail::allocator_traits<Allocator>::size_type;
+
public:
/// Destructor
@@ -192,14 +214,14 @@ public:
@param alloc The allocator to use.
*/
explicit
- basic_fields(Allocator const& alloc);
+ basic_fields(Allocator const& alloc) noexcept;
/** Move constructor.
The state of the moved-from object is
as if constructed using the same allocator.
*/
- basic_fields(basic_fields&&);
+ basic_fields(basic_fields&&) noexcept;
/** Move constructor.
@@ -236,7 +258,8 @@ public:
The state of the moved-from object is
as if constructed using the same allocator.
*/
- basic_fields& operator=(basic_fields&&);
+ basic_fields& operator=(basic_fields&&) noexcept(
+ alloc_traits::propagate_on_container_move_assignment::value);
/// Copy assignment.
basic_fields& operator=(basic_fields const&);
@@ -260,7 +283,7 @@ public:
allocator_type
get_allocator() const
{
- return alloc_;
+ return this->member();
}
//--------------------------------------------------------------------------
@@ -681,16 +704,6 @@ private:
template<class OtherAlloc>
friend class basic_fields;
- using base_alloc_type = typename
- beast::detail::allocator_traits<Allocator>::
- template rebind_alloc<value_type>;
-
- using alloc_traits =
- beast::detail::allocator_traits<base_alloc_type>;
-
- using size_type = typename
- beast::detail::allocator_traits<Allocator>::size_type;
-
value_type&
new_element(field name,
string_view sname, string_view value);
@@ -736,7 +749,6 @@ private:
void
swap(basic_fields& other, std::false_type);
- base_alloc_type alloc_;
set_t set_;
list_t list_;
string_view method_;
diff --git a/boost/beast/http/impl/basic_parser.ipp b/boost/beast/http/impl/basic_parser.ipp
index 355a76fb16..39ad3cc68e 100644
--- a/boost/beast/http/impl/basic_parser.ipp
+++ b/boost/beast/http/impl/basic_parser.ipp
@@ -148,7 +148,7 @@ loop:
return 0;
}
state_ = state::start_line;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case state::start_line:
{
@@ -179,7 +179,7 @@ loop:
ec = error::need_more;
goto done;
}
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case state::fields:
@@ -212,7 +212,7 @@ loop:
if(ec)
goto done;
state_ = state::body;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case state::body:
BOOST_ASSERT(! skip_);
@@ -227,7 +227,7 @@ loop:
if(ec)
goto done;
state_ = state::body_to_eof;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case state::body_to_eof:
BOOST_ASSERT(! skip_);
@@ -241,7 +241,7 @@ loop:
if(ec)
goto done;
state_ = state::chunk_header;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case state::chunk_header:
parse_chunk_header(p, n, ec);
diff --git a/boost/beast/http/impl/field.ipp b/boost/beast/http/impl/field.ipp
index 8da470ff24..467a40aeee 100644
--- a/boost/beast/http/impl/field.ipp
+++ b/boost/beast/http/impl/field.ipp
@@ -26,7 +26,7 @@ namespace detail {
struct field_table
{
using array_type =
- std::array<string_view, 352>;
+ std::array<string_view, 353>;
struct hash
{
@@ -104,6 +104,7 @@ struct field_table
"Access-Control-Allow-Headers",
"Access-Control-Allow-Methods",
"Access-Control-Allow-Origin",
+ "Access-Control-Expose-Headers",
"Access-Control-Max-Age",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
diff --git a/boost/beast/http/impl/fields.ipp b/boost/beast/http/impl/fields.ipp
index 67d7cc45b4..a07fd0fa30 100644
--- a/boost/beast/http/impl/fields.ipp
+++ b/boost/beast/http/impl/fields.ipp
@@ -272,8 +272,10 @@ writer(basic_fields const& f,
template<class Allocator>
basic_fields<Allocator>::
value_type::
-value_type(field name,
- string_view sname, string_view value)
+value_type(
+ field name,
+ string_view sname,
+ string_view value)
: off_(static_cast<off_t>(sname.size() + 2))
, len_(static_cast<off_t>(value.size()))
, f_(name)
@@ -285,13 +287,13 @@ value_type(field name,
p[off_-1] = ' ';
p[off_ + len_] = '\r';
p[off_ + len_ + 1] = '\n';
- std::memcpy(p, sname.data(), sname.size());
- std::memcpy(p + off_, value.data(), value.size());
+ sname.copy(p, sname.size());
+ value.copy(p + off_, value.size());
}
template<class Allocator>
inline
-field const
+field
basic_fields<Allocator>::
value_type::
name() const
@@ -349,30 +351,31 @@ basic_fields<Allocator>::
template<class Allocator>
basic_fields<Allocator>::
-basic_fields(Allocator const& alloc)
- : alloc_(alloc)
+basic_fields(Allocator const& alloc) noexcept
+ : beast::detail::empty_base_optimization<Allocator>(alloc)
{
}
template<class Allocator>
basic_fields<Allocator>::
-basic_fields(basic_fields&& other)
- : alloc_(std::move(other.alloc_))
+basic_fields(basic_fields&& other) noexcept
+ : beast::detail::empty_base_optimization<Allocator>(
+ std::move(other.member()))
, set_(std::move(other.set_))
, list_(std::move(other.list_))
, method_(other.method_)
, target_or_reason_(other.target_or_reason_)
{
- other.method_.clear();
- other.target_or_reason_.clear();
+ other.method_ = {};
+ other.target_or_reason_ = {};
}
template<class Allocator>
basic_fields<Allocator>::
basic_fields(basic_fields&& other, Allocator const& alloc)
- : alloc_(alloc)
+ : beast::detail::empty_base_optimization<Allocator>(alloc)
{
- if(alloc_ != other.alloc_)
+ if(this->member() != other.member())
{
copy_all(other);
other.clear_all();
@@ -389,8 +392,8 @@ basic_fields(basic_fields&& other, Allocator const& alloc)
template<class Allocator>
basic_fields<Allocator>::
basic_fields(basic_fields const& other)
- : alloc_(alloc_traits::
- select_on_container_copy_construction(other.alloc_))
+ : beast::detail::empty_base_optimization<Allocator>(alloc_traits::
+ select_on_container_copy_construction(other.member()))
{
copy_all(other);
}
@@ -399,7 +402,7 @@ template<class Allocator>
basic_fields<Allocator>::
basic_fields(basic_fields const& other,
Allocator const& alloc)
- : alloc_(alloc)
+ : beast::detail::empty_base_optimization<Allocator>(alloc)
{
copy_all(other);
}
@@ -417,7 +420,7 @@ template<class OtherAlloc>
basic_fields<Allocator>::
basic_fields(basic_fields<OtherAlloc> const& other,
Allocator const& alloc)
- : alloc_(alloc)
+ : beast::detail::empty_base_optimization<Allocator>(alloc)
{
copy_all(other);
}
@@ -425,9 +428,12 @@ basic_fields(basic_fields<OtherAlloc> const& other,
template<class Allocator>
auto
basic_fields<Allocator>::
-operator=(basic_fields&& other) ->
- basic_fields&
+operator=(basic_fields&& other) noexcept(
+ alloc_traits::propagate_on_container_move_assignment::value)
+ -> basic_fields&
{
+ static_assert(is_nothrow_move_assignable<Allocator>::value,
+ "Allocator must be noexcept assignable.");
if(this == &other)
return *this;
move_assign(other, std::integral_constant<bool,
@@ -605,11 +611,11 @@ basic_fields<Allocator>::
erase(const_iterator pos) ->
const_iterator
{
- auto next = pos.iter();
+ auto next = pos;
auto& e = *next++;
set_.erase(e);
- list_.erase(e);
- delete_element(e);
+ list_.erase(pos);
+ delete_element(const_cast<value_type&>(e));
return next;
}
@@ -1014,13 +1020,13 @@ set_chunked_impl(bool value)
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
std::string s;
#else
- using rebind_type =
+ using A =
typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>;
std::basic_string<
char,
std::char_traits<char>,
- rebind_type> s{rebind_type{alloc_}};
+ A> s{A{this->member()}};
#endif
s.reserve(it->value().size() + 9);
s.append(it->value().data(), it->value().size());
@@ -1051,13 +1057,13 @@ set_chunked_impl(bool value)
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
std::string s;
#else
- using rebind_type =
+ using A =
typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>;
std::basic_string<
char,
std::char_traits<char>,
- rebind_type> s{rebind_type{alloc_}};
+ A> s{A{this->member()}};
#endif
s.reserve(it->value().size());
detail::filter_token_list_last(s, it->value(),
@@ -1108,13 +1114,13 @@ set_keep_alive_impl(
// Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
std::string s;
#else
- using rebind_type =
+ using A =
typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>;
std::basic_string<
char,
std::char_traits<char>,
- rebind_type> s{rebind_type{alloc_}};
+ A> s{A{this->member()}};
#endif
s.reserve(value.size());
detail::keep_alive_impl(
@@ -1148,13 +1154,14 @@ new_element(field name,
static_cast<off_t>(sname.size() + 2);
std::uint16_t const len =
static_cast<off_t>(value.size());
- auto const p = alloc_traits::allocate(alloc_,
- 1 + (off + len + 2 + sizeof(value_type) - 1) /
- sizeof(value_type));
+ auto a = rebind_type{this->member()};
+ auto const p = alloc_traits::allocate(a,
+ (sizeof(value_type) + off + len + 2 + sizeof(align_type) - 1) /
+ sizeof(align_type));
// VFALCO allocator can't call the constructor because its private
- //alloc_traits::construct(alloc_, p, name, sname, value);
+ //alloc_traits::construct(a, p, name, sname, value);
new(p) value_type{name, sname, value};
- return *p;
+ return *reinterpret_cast<value_type*>(p);
}
template<class Allocator>
@@ -1162,10 +1169,14 @@ void
basic_fields<Allocator>::
delete_element(value_type& e)
{
- auto const n = 1 + (e.off_ + e.len_ + 2 +
- sizeof(value_type) - 1) / sizeof(value_type);
- alloc_traits::destroy(alloc_, &e);
- alloc_traits::deallocate(alloc_, &e, n);
+ auto a = rebind_type{this->member()};
+ auto const n =
+ (sizeof(value_type) + e.off_ + e.len_ + 2 + sizeof(align_type) - 1) /
+ sizeof(align_type);
+ //alloc_traits::destroy(a, &e);
+ e.~value_type();
+ alloc_traits::deallocate(a,
+ reinterpret_cast<align_type*>(&e), n);
}
template<class Allocator>
@@ -1207,19 +1218,20 @@ realloc_string(string_view& dest, string_view s)
return;
auto a = typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<
- char>(alloc_);
- if(! dest.empty())
+ char>(this->member());
+ char* p = nullptr;
+ if(! s.empty())
{
+ p = a.allocate(s.size());
+ s.copy(p, s.size());
+ }
+ if(! dest.empty())
a.deallocate(const_cast<char*>(
dest.data()), dest.size());
- dest.clear();
- }
- if(! s.empty())
- {
- auto const p = a.allocate(s.size());
- std::memcpy(p, s.data(), s.size());
+ if(p)
dest = {p, s.size()};
- }
+ else
+ dest = {};
}
template<class Allocator>
@@ -1235,20 +1247,21 @@ realloc_target(
return;
auto a = typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<
- char>(alloc_);
- if(! dest.empty())
- {
- a.deallocate(const_cast<char*>(
- dest.data()), dest.size());
- dest.clear();
- }
+ char>(this->member());
+ char* p = nullptr;
if(! s.empty())
{
- auto const p = a.allocate(1 + s.size());
+ p = a.allocate(1 + s.size());
p[0] = ' ';
- std::memcpy(p + 1, s.data(), s.size());
- dest = {p, 1 + s.size()};
+ s.copy(p + 1, s.size());
}
+ if(! dest.empty())
+ a.deallocate(const_cast<char*>(
+ dest.data()), dest.size());
+ if(p)
+ dest = {p, 1 + s.size()};
+ else
+ dest = {};
}
template<class Allocator>
@@ -1296,9 +1309,9 @@ move_assign(basic_fields& other, std::true_type)
list_ = std::move(other.list_);
method_ = other.method_;
target_or_reason_ = other.target_or_reason_;
- other.method_.clear();
- other.target_or_reason_.clear();
- alloc_ = other.alloc_;
+ other.method_ = {};
+ other.target_or_reason_ = {};
+ this->member() = other.member();
}
template<class Allocator>
@@ -1308,7 +1321,7 @@ basic_fields<Allocator>::
move_assign(basic_fields& other, std::false_type)
{
clear_all();
- if(alloc_ != other.alloc_)
+ if(this->member() != other.member())
{
copy_all(other);
other.clear_all();
@@ -1319,8 +1332,8 @@ move_assign(basic_fields& other, std::false_type)
list_ = std::move(other.list_);
method_ = other.method_;
target_or_reason_ = other.target_or_reason_;
- other.method_.clear();
- other.target_or_reason_.clear();
+ other.method_ = {};
+ other.target_or_reason_ = {};
}
}
@@ -1331,7 +1344,7 @@ basic_fields<Allocator>::
copy_assign(basic_fields const& other, std::true_type)
{
clear_all();
- alloc_ = other.alloc_;
+ this->member() = other.member();
copy_all(other);
}
@@ -1352,7 +1365,7 @@ basic_fields<Allocator>::
swap(basic_fields& other, std::true_type)
{
using std::swap;
- swap(alloc_, other.alloc_);
+ swap(this->member(), other.member());
swap(set_, other.set_);
swap(list_, other.list_);
swap(method_, other.method_);
@@ -1365,7 +1378,7 @@ void
basic_fields<Allocator>::
swap(basic_fields& other, std::false_type)
{
- BOOST_ASSERT(alloc_ == other.alloc_);
+ BOOST_ASSERT(this->member() == other.member());
using std::swap;
swap(set_, other.set_);
swap(list_, other.list_);
diff --git a/boost/beast/http/impl/file_body_win32.ipp b/boost/beast/http/impl/file_body_win32.ipp
index e11c443ed2..627401f531 100644
--- a/boost/beast/http/impl/file_body_win32.ipp
+++ b/boost/beast/http/impl/file_body_win32.ipp
@@ -21,10 +21,12 @@
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/windows/overlapped_ptr.hpp>
#include <boost/make_unique.hpp>
#include <boost/smart_ptr/make_shared_array.hpp>
#include <boost/winapi/basic_types.hpp>
+#include <boost/winapi/get_last_error.hpp>
#include <algorithm>
#include <cstring>
@@ -123,9 +125,8 @@ struct basic_file_body<file_win32>
boost::asio::const_buffer;
template<bool isRequest, class Fields>
- writer(message<isRequest,
- basic_file_body<file_win32>, Fields>& m)
- : body_(m.body())
+ writer(header<isRequest, Fields>&, value_type& b)
+ : body_(b)
{
}
@@ -167,8 +168,8 @@ struct basic_file_body<file_win32>
public:
template<bool isRequest, class Fields>
explicit
- reader(message<isRequest, basic_file_body, Fields>& m)
- : body_(m.body())
+ reader(header<isRequest, Fields>&, value_type& b)
+ : body_(b)
{
}
@@ -344,7 +345,7 @@ class write_some_win32_op
public:
write_some_win32_op(write_some_win32_op&&) = default;
- write_some_win32_op(write_some_win32_op const&) = default;
+ write_some_win32_op(write_some_win32_op const&) = delete;
template<class DeducedHandler>
write_some_win32_op(
@@ -364,7 +365,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type =
@@ -374,7 +375,7 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, sock_.get_executor());
}
@@ -393,6 +394,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, write_some_win32_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
template<
@@ -407,25 +416,28 @@ operator()()
{
header_ = true;
sr_.split(true);
- return detail::async_write_some(
+ return detail::async_write_some_impl(
sock_, sr_, std::move(*this));
}
if(sr_.get().chunked())
{
- return detail::async_write_some(
+ return detail::async_write_some_impl(
sock_, sr_, std::move(*this));
}
- auto& r = sr_.reader_impl();
+ auto& w = sr_.writer_impl();
boost::winapi::DWORD_ const nNumberOfBytesToWrite =
static_cast<boost::winapi::DWORD_>(
(std::min<std::uint64_t>)(
- (std::min<std::uint64_t>)(r.body_.last_ - r.pos_, sr_.limit()),
+ (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr_.limit()),
(std::numeric_limits<boost::winapi::DWORD_>::max)()));
boost::asio::windows::overlapped_ptr overlapped{
- sock_.get_executor().context(), *this};
+ sock_.get_executor().context(), std::move(*this)};
+ // Note that we have moved *this, so we cannot access
+ // the handler since it is now moved-from. We can still
+ // access simple things like references and built-in types.
auto& ov = *overlapped.get();
- ov.Offset = lowPart(r.pos_);
- ov.OffsetHigh = highPart(r.pos_);
+ ov.Offset = lowPart(w.pos_);
+ ov.OffsetHigh = highPart(w.pos_);
auto const bSuccess = ::TransmitFile(
sock_.native_handle(),
sr_.get().body().file_.native_handle(),
@@ -434,14 +446,13 @@ operator()()
overlapped.get(),
nullptr,
0);
- auto const dwError = ::GetLastError();
+ auto const dwError = boost::winapi::GetLastError();
if(! bSuccess && dwError !=
boost::winapi::ERROR_IO_PENDING_)
{
// VFALCO This needs review, is 0 the right number?
// completed immediately (with error?)
- overlapped.complete(error_code{static_cast<int>(
- boost::winapi::GetLastError()),
+ overlapped.complete(error_code{static_cast<int>(dwError),
system_category()}, 0);
return;
}
@@ -465,10 +476,10 @@ operator()(
header_ = false;
return (*this)();
}
- auto& r = sr_.reader_impl();
- r.pos_ += bytes_transferred;
- BOOST_ASSERT(r.pos_ <= r.body_.last_);
- if(r.pos_ >= r.body_.last_)
+ auto& w = sr_.writer_impl();
+ w.pos_ += bytes_transferred;
+ BOOST_ASSERT(w.pos_ <= w.body_.last_);
+ if(w.pos_ >= w.body_.last_)
{
sr_.next(ec, null_lambda{});
BOOST_ASSERT(! ec);
@@ -496,7 +507,7 @@ write_some(
{
sr.split(true);
auto const bytes_transferred =
- detail::write_some(sock, sr, ec);
+ detail::write_some_impl(sock, sr, ec);
if(ec)
return bytes_transferred;
return bytes_transferred;
@@ -504,23 +515,23 @@ write_some(
if(sr.get().chunked())
{
auto const bytes_transferred =
- detail::write_some(sock, sr, ec);
+ detail::write_some_impl(sock, sr, ec);
if(ec)
return bytes_transferred;
return bytes_transferred;
}
- auto& r = sr.reader_impl();
- r.body_.file_.seek(r.pos_, ec);
+ auto& w = sr.writer_impl();
+ w.body_.file_.seek(w.pos_, ec);
if(ec)
return 0;
boost::winapi::DWORD_ const nNumberOfBytesToWrite =
static_cast<boost::winapi::DWORD_>(
(std::min<std::uint64_t>)(
- (std::min<std::uint64_t>)(r.body_.last_ - r.pos_, sr.limit()),
+ (std::min<std::uint64_t>)(w.body_.last_ - w.pos_, sr.limit()),
(std::numeric_limits<boost::winapi::DWORD_>::max)()));
auto const bSuccess = ::TransmitFile(
sock.native_handle(),
- r.body_.file_.native_handle(),
+ w.body_.file_.native_handle(),
nNumberOfBytesToWrite,
0,
nullptr,
@@ -533,9 +544,9 @@ write_some(
system_category());
return 0;
}
- r.pos_ += nNumberOfBytesToWrite;
- BOOST_ASSERT(r.pos_ <= r.body_.last_);
- if(r.pos_ < r.body_.last_)
+ w.pos_ += nNumberOfBytesToWrite;
+ BOOST_ASSERT(w.pos_ <= w.body_.last_);
+ if(w.pos_ < w.body_.last_)
{
ec.assign(0, ec.category());
}
@@ -562,14 +573,14 @@ async_write_some(
basic_file_body<file_win32>, Fields>& sr,
WriteHandler&& handler)
{
- boost::asio::async_completion<WriteHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
detail::write_some_win32_op<
Protocol,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
isRequest, Fields>{
- init.completion_handler, sock, sr}();
+ std::move(init.completion_handler), sock, sr}();
return init.result.get();
}
diff --git a/boost/beast/http/impl/parser.ipp b/boost/beast/http/impl/parser.ipp
index 99745da3f0..8a6cab30af 100644
--- a/boost/beast/http/impl/parser.ipp
+++ b/boost/beast/http/impl/parser.ipp
@@ -20,7 +20,26 @@ namespace http {
template<bool isRequest, class Body, class Allocator>
parser<isRequest, Body, Allocator>::
parser()
- : wr_(m_)
+ : parser{detail::has_deprecated_body_reader<Body>{}}
+{
+}
+
+template<bool isRequest, class Body, class Allocator>
+parser<isRequest, Body, Allocator>::
+parser(std::true_type)
+ : rd_(m_)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ // Deprecated BodyReader Concept (v1.66)
+ static_assert(sizeof(Body) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+}
+
+template<bool isRequest, class Body, class Allocator>
+parser<isRequest, Body, Allocator>::
+parser(std::false_type)
+ : rd_(m_.base(), m_.body())
{
}
@@ -28,21 +47,82 @@ template<bool isRequest, class Body, class Allocator>
template<class Arg1, class... ArgN, class>
parser<isRequest, Body, Allocator>::
parser(Arg1&& arg1, ArgN&&... argn)
+ : parser(std::forward<Arg1>(arg1),
+ detail::has_deprecated_body_reader<Body>{},
+ std::forward<ArgN>(argn)...)
+{
+}
+
+// VFALCO arg1 comes before `true_type` to make
+// the signature unambiguous.
+template<bool isRequest, class Body, class Allocator>
+template<class Arg1, class... ArgN, class>
+parser<isRequest, Body, Allocator>::
+parser(Arg1&& arg1, std::true_type, ArgN&&... argn)
: m_(std::forward<Arg1>(arg1),
std::forward<ArgN>(argn)...)
- , wr_(m_)
+ , rd_(m_)
{
m_.clear();
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ /* Deprecated BodyWriter Concept (v1.66) */
+ static_assert(sizeof(Body) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif // BOOST_BEAST_ALLOW_DEPRECATED
+}
+
+// VFALCO arg1 comes before `false_type` to make
+// the signature unambiguous.
+template<bool isRequest, class Body, class Allocator>
+template<class Arg1, class... ArgN, class>
+parser<isRequest, Body, Allocator>::
+parser(Arg1&& arg1, std::false_type, ArgN&&... argn)
+ : m_(std::forward<Arg1>(arg1),
+ std::forward<ArgN>(argn)...)
+ , rd_(m_.base(), m_.body())
+{
+ m_.clear();
+}
+
+template<bool isRequest, class Body, class Allocator>
+template<class OtherBody, class... Args, class>
+parser<isRequest, Body, Allocator>::
+parser(
+ parser<isRequest, OtherBody, Allocator>&& other,
+ Args&&... args)
+ : parser(detail::has_deprecated_body_reader<Body>{},
+ std::move(other), std::forward<Args>(args)...)
+{
+}
+
+template<bool isRequest, class Body, class Allocator>
+template<class OtherBody, class... Args, class>
+parser<isRequest, Body, Allocator>::
+parser(std::true_type,
+ parser<isRequest, OtherBody, Allocator>&& other,
+ Args&&... args)
+ : base_type(std::move(other))
+ , m_(other.release(), std::forward<Args>(args)...)
+ , rd_(m_)
+{
+ if(other.rd_inited_)
+ BOOST_THROW_EXCEPTION(std::invalid_argument{
+ "moved-from parser has a body"});
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ // Deprecated BodyReader Concept (v1.66)
+ static_assert(sizeof(Body) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
}
template<bool isRequest, class Body, class Allocator>
template<class OtherBody, class... Args, class>
parser<isRequest, Body, Allocator>::
-parser(parser<isRequest, OtherBody, Allocator>&& other,
+parser(std::false_type, parser<isRequest, OtherBody, Allocator>&& other,
Args&&... args)
: base_type(std::move(other))
, m_(other.release(), std::forward<Args>(args)...)
- , wr_(m_)
+ , rd_(m_.base(), m_.body())
{
if(other.rd_inited_)
BOOST_THROW_EXCEPTION(std::invalid_argument{
diff --git a/boost/beast/http/impl/read.ipp b/boost/beast/http/impl/read.ipp
index 5ecfae7d8b..28ff0a3c44 100644
--- a/boost/beast/http/impl/read.ipp
+++ b/boost/beast/http/impl/read.ipp
@@ -20,7 +20,9 @@
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
@@ -38,19 +40,18 @@ namespace detail {
template<class Stream, class DynamicBuffer,
bool isRequest, class Derived, class Handler>
class read_some_op
+ : public boost::asio::coroutine
{
- int state_ = 0;
Stream& s_;
DynamicBuffer& b_;
basic_parser<isRequest, Derived>& p_;
- boost::optional<typename
- DynamicBuffer::mutable_buffers_type> mb_;
std::size_t bytes_transferred_ = 0;
Handler h_;
+ bool cont_ = false;
public:
read_some_op(read_some_op&&) = default;
- read_some_op(read_some_op const&) = default;
+ read_some_op(read_some_op const&) = delete;
template<class DeducedHandler>
read_some_op(DeducedHandler&& h, Stream& s,
@@ -68,7 +69,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
@@ -77,23 +78,32 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, s_.get_executor());
}
void
operator()(
- error_code ec = {},
- std::size_t bytes_transferred = 0);
+ error_code ec,
+ std::size_t bytes_transferred = 0,
+ bool cont = true);
friend
bool asio_handler_is_continuation(read_some_op* op)
{
using boost::asio::asio_handler_is_continuation;
- return op->state_ >= 2 ? true :
+ return op->cont_ ? true :
asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, read_some_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
template<class Stream, class DynamicBuffer,
@@ -103,75 +113,69 @@ read_some_op<Stream, DynamicBuffer,
isRequest, Derived, Handler>::
operator()(
error_code ec,
- std::size_t bytes_transferred)
+ std::size_t bytes_transferred,
+ bool cont)
{
- switch(state_)
+ cont_ = cont;
+ boost::optional<typename
+ DynamicBuffer::mutable_buffers_type> mb;
+ BOOST_ASIO_CORO_REENTER(*this)
{
- case 0:
- state_ = 1;
if(b_.size() == 0)
goto do_read;
- goto do_parse;
-
- case 1:
- state_ = 2;
- case 2:
- if(ec == boost::asio::error::eof)
+ for(;;)
{
- BOOST_ASSERT(bytes_transferred == 0);
- if(p_.got_some())
+ // parse
{
- // caller sees EOF on next read
- ec.assign(0, ec.category());
- p_.put_eof(ec);
- if(ec)
- goto upcall;
- BOOST_ASSERT(p_.is_done());
- goto upcall;
+ auto const used = p_.put(b_.data(), ec);
+ bytes_transferred_ += used;
+ b_.consume(used);
}
- ec = error::end_of_stream;
- goto upcall;
- }
- if(ec)
- goto upcall;
- b_.commit(bytes_transferred);
-
- do_parse:
- {
- auto const used = p_.put(b_.data(), ec);
- bytes_transferred_ += used;
- b_.consume(used);
- if(! ec || ec != http::error::need_more)
- goto do_upcall;
- ec.assign(0, ec.category());
- }
+ if(ec != http::error::need_more)
+ break;
- do_read:
- try
- {
- mb_.emplace(b_.prepare(
- read_size_or_throw(b_, 65536)));
- }
- catch(std::length_error const&)
- {
- ec = error::buffer_overflow;
- goto do_upcall;
+ do_read:
+ try
+ {
+ mb.emplace(b_.prepare(
+ read_size_or_throw(b_, 65536)));
+ }
+ catch(std::length_error const&)
+ {
+ ec = error::buffer_overflow;
+ break;
+ }
+ BOOST_ASIO_CORO_YIELD
+ s_.async_read_some(*mb, std::move(*this));
+ if(ec == boost::asio::error::eof)
+ {
+ BOOST_ASSERT(bytes_transferred == 0);
+ if(p_.got_some())
+ {
+ // caller sees EOF on next read
+ ec.assign(0, ec.category());
+ p_.put_eof(ec);
+ if(ec)
+ goto upcall;
+ BOOST_ASSERT(p_.is_done());
+ goto upcall;
+ }
+ ec = error::end_of_stream;
+ break;
+ }
+ if(ec)
+ break;
+ b_.commit(bytes_transferred);
}
- return s_.async_read_some(*mb_, std::move(*this));
- do_upcall:
- if(state_ >= 2)
- goto upcall;
- state_ = 3;
- return boost::asio::post(
- s_.get_executor(),
- bind_handler(std::move(*this), ec, 0));
-
- case 3:
- break;
+ upcall:
+ if(! cont_)
+ return boost::asio::post(
+ s_.get_executor(),
+ bind_handler(std::move(h_),
+ ec, bytes_transferred_));
+ h_(ec, bytes_transferred_);
}
-upcall:
- h_(ec, bytes_transferred_);
}
//------------------------------------------------------------------------------
@@ -202,17 +206,18 @@ template<class Stream, class DynamicBuffer,
bool isRequest, class Derived, class Condition,
class Handler>
class read_op
+ : public boost::asio::coroutine
{
- int state_ = 0;
Stream& s_;
DynamicBuffer& b_;
basic_parser<isRequest, Derived>& p_;
std::size_t bytes_transferred_ = 0;
Handler h_;
+ bool cont_ = false;
public:
read_op(read_op&&) = default;
- read_op(read_op const&) = default;
+ read_op(read_op const&) = delete;
template<class DeducedHandler>
read_op(DeducedHandler&& h, Stream& s,
@@ -231,7 +236,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
@@ -240,23 +245,32 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, s_.get_executor());
}
void
operator()(
- error_code ec = {},
- std::size_t bytes_transferred = 0);
+ error_code ec,
+ std::size_t bytes_transferred = 0,
+ bool cont = true);
friend
bool asio_handler_is_continuation(read_op* op)
{
using boost::asio::asio_handler_is_continuation;
- return op->state_ >= 3 ? true :
+ return op->cont_ ? true :
asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, read_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
template<class Stream, class DynamicBuffer,
@@ -267,39 +281,33 @@ read_op<Stream, DynamicBuffer,
isRequest, Derived, Condition, Handler>::
operator()(
error_code ec,
- std::size_t bytes_transferred)
+ std::size_t bytes_transferred,
+ bool cont)
{
- switch(state_)
+ cont_ = cont;
+ BOOST_ASIO_CORO_REENTER(*this)
{
- case 0:
if(Condition{}(p_))
{
- state_ = 1;
- return boost::asio::post(
- s_.get_executor(),
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(s_.get_executor(),
bind_handler(std::move(*this), ec));
- }
- state_ = 2;
-
- do_read:
- return async_read_some(
- s_, b_, p_, std::move(*this));
-
- case 1:
- goto upcall;
-
- case 2:
- case 3:
- if(ec)
- goto upcall;
- bytes_transferred_ += bytes_transferred;
- if(Condition{}(p_))
goto upcall;
- state_ = 3;
- goto do_read;
+ }
+ for(;;)
+ {
+ BOOST_ASIO_CORO_YIELD
+ async_read_some(
+ s_, b_, p_, std::move(*this));
+ if(ec)
+ goto upcall;
+ bytes_transferred_ += bytes_transferred;
+ if(Condition{}(p_))
+ goto upcall;
+ }
+ upcall:
+ h_(ec, bytes_transferred_);
}
-upcall:
- h_(ec, bytes_transferred_);
}
//------------------------------------------------------------------------------
@@ -308,6 +316,7 @@ template<class Stream, class DynamicBuffer,
bool isRequest, class Body, class Allocator,
class Handler>
class read_msg_op
+ : public boost::asio::coroutine
{
using parser_type =
parser<isRequest, Body, Allocator>;
@@ -317,14 +326,14 @@ class read_msg_op
struct data
{
- int state = 0;
Stream& s;
DynamicBuffer& b;
message_type& m;
parser_type p;
std::size_t bytes_transferred = 0;
+ bool cont = false;
- data(Handler&, Stream& s_,
+ data(Handler const&, Stream& s_,
DynamicBuffer& b_, message_type& m_)
: s(s_)
, b(b_)
@@ -339,7 +348,7 @@ class read_msg_op
public:
read_msg_op(read_msg_op&&) = default;
- read_msg_op(read_msg_op const&) = default;
+ read_msg_op(read_msg_op const&) = delete;
template<class DeducedHandler, class... Args>
read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args)
@@ -354,7 +363,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(d_.handler());
+ return (boost::asio::get_associated_allocator)(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
@@ -363,23 +372,32 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
d_.handler(), d_->s.get_executor());
}
void
operator()(
- error_code ec = {},
- std::size_t bytes_transferred = 0);
+ error_code ec,
+ std::size_t bytes_transferred = 0,
+ bool cont = true);
friend
bool asio_handler_is_continuation(read_msg_op* op)
{
using boost::asio::asio_handler_is_continuation;
- return op->d_->state >= 2 ? true :
+ return op->d_->cont ? true :
asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, read_msg_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->d_.handler()));
+ }
};
template<class Stream, class DynamicBuffer,
@@ -390,35 +408,32 @@ read_msg_op<Stream, DynamicBuffer,
isRequest, Body, Allocator, Handler>::
operator()(
error_code ec,
- std::size_t bytes_transferred)
+ std::size_t bytes_transferred,
+ bool cont)
{
auto& d = *d_;
- switch(d.state)
+ d.cont = cont;
+ BOOST_ASIO_CORO_REENTER(*this)
{
- case 0:
- d.state = 1;
-
- do_read:
- return async_read_some(
- d.s, d.b, d.p, std::move(*this));
-
- case 1:
- case 2:
- if(ec)
- goto upcall;
- d.bytes_transferred +=
- bytes_transferred;
- if(d.p.is_done())
+ for(;;)
{
- d.m = d.p.release();
- goto upcall;
+ BOOST_ASIO_CORO_YIELD
+ async_read_some(
+ d.s, d.b, d.p, std::move(*this));
+ if(ec)
+ goto upcall;
+ d.bytes_transferred +=
+ bytes_transferred;
+ if(d.p.is_done())
+ {
+ d.m = d.p.release();
+ goto upcall;
+ }
}
- d.state = 2;
- goto do_read;
+ upcall:
+ bytes_transferred = d.bytes_transferred;
+ d_.invoke(ec, bytes_transferred);
}
-upcall:
- bytes_transferred = d.bytes_transferred;
- d_.invoke(ec, bytes_transferred);
}
} // detail
@@ -536,12 +551,13 @@ async_read_some(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
BOOST_ASSERT(! parser.is_done());
- boost::asio::async_completion<ReadHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
detail::read_some_op<AsyncReadStream,
DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler, stream, buffer, parser}();
+ std::move(init.completion_handler), stream, buffer, parser}(
+ {}, 0, false);
return init.result.get();
}
@@ -623,12 +639,13 @@ async_read_header(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
parser.eager(false);
- boost::asio::async_completion<ReadHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
detail::read_op<AsyncReadStream, DynamicBuffer,
isRequest, Derived, detail::parser_is_header_done,
BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler, stream, buffer, parser}();
+ std::move(init.completion_handler), stream,
+ buffer, parser}({}, 0, false);
return init.result.get();
}
@@ -710,13 +727,13 @@ async_read(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
parser.eager(true);
- boost::asio::async_completion<
- ReadHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
detail::read_op<AsyncReadStream, DynamicBuffer,
isRequest, Derived, detail::parser_is_done,
BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler, stream, buffer, parser}();
+ std::move(init.completion_handler), stream, buffer, parser}(
+ {}, 0, false);
return init.result.get();
}
@@ -801,16 +818,16 @@ async_read(
"Body requirements not met");
static_assert(is_body_reader<Body>::value,
"BodyReader requirements not met");
- boost::asio::async_completion<
- ReadHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
detail::read_msg_op<
AsyncReadStream,
DynamicBuffer,
isRequest, Body, Allocator,
BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler, stream, buffer, msg}();
+ std::move(init.completion_handler), stream, buffer, msg}(
+ {}, 0, false);
return init.result.get();
}
diff --git a/boost/beast/http/impl/serializer.ipp b/boost/beast/http/impl/serializer.ipp
index 11cf857845..b37856567f 100644
--- a/boost/beast/http/impl/serializer.ipp
+++ b/boost/beast/http/impl/serializer.ipp
@@ -25,18 +25,18 @@ template<
bool isRequest, class Body, class Fields>
void
serializer<isRequest, Body, Fields>::
-frdinit(std::true_type)
+fwrinit(std::true_type)
{
- frd_.emplace(m_, m_.version(), m_.method());
+ fwr_.emplace(m_, m_.version(), m_.method());
}
template<
bool isRequest, class Body, class Fields>
void
serializer<isRequest, Body, Fields>::
-frdinit(std::false_type)
+fwrinit(std::false_type)
{
- frd_.emplace(m_, m_.version(), m_.result_int());
+ fwr_.emplace(m_, m_.version(), m_.result_int());
}
template<
@@ -57,9 +57,31 @@ do_visit(error_code& ec, Visit& visit)
template<
bool isRequest, class Body, class Fields>
serializer<isRequest, Body, Fields>::
-serializer(value_type& m)
+serializer(value_type& m, std::true_type)
+ : m_(m)
+ , wr_(m_)
+{
+#ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ // Deprecated BodyWriter Concept (v1.66)
+ static_assert(sizeof(Body) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+#endif
+}
+
+template<
+ bool isRequest, class Body, class Fields>
+serializer<isRequest, Body, Fields>::
+serializer(value_type& m, std::false_type)
: m_(m)
- , rd_(m_)
+ , wr_(m_.base(), m_.body())
+{
+}
+
+template<
+ bool isRequest, class Body, class Fields>
+serializer<isRequest, Body, Fields>::
+serializer(value_type& m)
+ : serializer(m, detail::has_deprecated_body_writer<Body>{})
{
}
@@ -75,22 +97,22 @@ next(error_code& ec, Visit&& visit)
{
case do_construct:
{
- frdinit(std::integral_constant<bool,
+ fwrinit(std::integral_constant<bool,
isRequest>{});
if(m_.chunked())
goto go_init_c;
s_ = do_init;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case do_init:
{
- rd_.init(ec);
+ wr_.init(ec);
if(ec)
return;
if(split_)
goto go_header_only;
- auto result = rd_.get(ec);
+ auto result = wr_.get(ec);
if(ec == error::need_more)
goto go_header_only;
if(ec)
@@ -100,10 +122,10 @@ next(error_code& ec, Visit&& visit)
more_ = result->second;
v_.template emplace<2>(
boost::in_place_init,
- frd_->get(),
+ fwr_->get(),
result->first);
s_ = do_header;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case do_header:
@@ -111,20 +133,20 @@ next(error_code& ec, Visit&& visit)
break;
go_header_only:
- v_.template emplace<1>(frd_->get());
+ v_.template emplace<1>(fwr_->get());
s_ = do_header_only;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case do_header_only:
do_visit<1>(ec, visit);
break;
case do_body:
s_ = do_body + 1;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case do_body + 1:
{
- auto result = rd_.get(ec);
+ auto result = wr_.get(ec);
if(ec)
return;
if(! result)
@@ -132,7 +154,7 @@ next(error_code& ec, Visit&& visit)
more_ = result->second;
v_.template emplace<3>(result->first);
s_ = do_body + 2;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case do_body + 2:
@@ -143,15 +165,15 @@ next(error_code& ec, Visit&& visit)
go_init_c:
s_ = do_init_c;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case do_init_c:
{
- rd_.init(ec);
+ wr_.init(ec);
if(ec)
return;
if(split_)
goto go_header_only_c;
- auto result = rd_.get(ec);
+ auto result = wr_.get(ec);
if(ec == error::need_more)
goto go_header_only_c;
if(ec)
@@ -164,7 +186,7 @@ next(error_code& ec, Visit&& visit)
// do it all in one buffer
v_.template emplace<7>(
boost::in_place_init,
- frd_->get(),
+ fwr_->get(),
buffer_size(result->first),
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{},
@@ -177,14 +199,14 @@ next(error_code& ec, Visit&& visit)
}
v_.template emplace<4>(
boost::in_place_init,
- frd_->get(),
+ fwr_->get(),
buffer_size(result->first),
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{},
result->first,
chunk_crlf{});
s_ = do_header_c;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case do_header_c:
@@ -192,19 +214,21 @@ next(error_code& ec, Visit&& visit)
break;
go_header_only_c:
- v_.template emplace<1>(frd_->get());
+ v_.template emplace<1>(fwr_->get());
s_ = do_header_only_c;
+ BOOST_FALLTHROUGH;
+
case do_header_only_c:
do_visit<1>(ec, visit);
break;
case do_body_c:
s_ = do_body_c + 1;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case do_body_c + 1:
{
- auto result = rd_.get(ec);
+ auto result = wr_.get(ec);
if(ec)
return;
if(! result)
@@ -233,7 +257,7 @@ next(error_code& ec, Visit&& visit)
result->first,
chunk_crlf{});
s_ = do_body_c + 2;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case do_body_c + 2:
@@ -242,14 +266,14 @@ next(error_code& ec, Visit&& visit)
go_body_final_c:
s_ = do_body_final_c;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case do_body_final_c:
do_visit<6>(ec, visit);
break;
go_all_c:
s_ = do_all_c;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case do_all_c:
do_visit<7>(ec, visit);
break;
@@ -262,7 +286,7 @@ next(error_code& ec, Visit&& visit)
boost::asio::const_buffer{nullptr, 0},
chunk_crlf{});
s_ = do_final_c + 1;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case do_final_c + 1:
do_visit<8>(ec, visit);
@@ -309,7 +333,7 @@ consume(std::size_t n)
v_.template get<1>().consume(n);
if(buffer_size(v_.template get<1>()) > 0)
break;
- frd_ = boost::none;
+ fwr_ = boost::none;
header_done_ = true;
if(! split_)
goto go_complete;
@@ -353,7 +377,7 @@ consume(std::size_t n)
v_.template get<1>().consume(n);
if(buffer_size(v_.template get<1>()) > 0)
break;
- frd_ = boost::none;
+ fwr_ = boost::none;
header_done_ = true;
if(! split_)
{
diff --git a/boost/beast/http/impl/status.ipp b/boost/beast/http/impl/status.ipp
index 1cc8f34b63..7d37919423 100644
--- a/boost/beast/http/impl/status.ipp
+++ b/boost/beast/http/impl/status.ipp
@@ -28,7 +28,7 @@ int_to_status(unsigned v)
case status::continue_:
case status::switching_protocols:
case status::processing:
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
// 2xx
case status::ok:
@@ -41,7 +41,7 @@ int_to_status(unsigned v)
case status::multi_status:
case status::already_reported:
case status::im_used:
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
// 3xx
case status::multiple_choices:
@@ -52,7 +52,7 @@ int_to_status(unsigned v)
case status::use_proxy:
case status::temporary_redirect:
case status::permanent_redirect:
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
// 4xx
case status::bad_request:
@@ -84,7 +84,7 @@ int_to_status(unsigned v)
case status::connection_closed_without_response:
case status::unavailable_for_legal_reasons:
case status::client_closed_request:
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
// 5xx
case status::internal_server_error:
diff --git a/boost/beast/http/impl/verb.ipp b/boost/beast/http/impl/verb.ipp
index 820609165b..8f8b2e33bf 100644
--- a/boost/beast/http/impl/verb.ipp
+++ b/boost/beast/http/impl/verb.ipp
@@ -72,6 +72,10 @@ verb_to_string(verb v)
}
BOOST_THROW_EXCEPTION(std::invalid_argument{"unknown verb"});
+
+ // Help some compilers which don't know the next line is
+ // unreachable, otherwise spurious warnings are generated.
+ return "<unknown>";
}
template<class = void>
@@ -159,7 +163,7 @@ string_to_verb(string_view v)
return verb::connect;
if(eq(v, "PY"))
return verb::copy;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
default:
break;
@@ -220,7 +224,7 @@ string_to_verb(string_view v)
case 'O':
if(eq(v, "VE"))
return verb::move;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
default:
break;
@@ -264,7 +268,7 @@ string_to_verb(string_view v)
return verb::purge;
if(eq(v, "T"))
return verb::put;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
default:
break;
diff --git a/boost/beast/http/impl/write.ipp b/boost/beast/http/impl/write.ipp
index 9d5be277ec..af31cd9be9 100644
--- a/boost/beast/http/impl/write.ipp
+++ b/boost/beast/http/impl/write.ipp
@@ -19,6 +19,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/write.hpp>
#include <boost/optional.hpp>
@@ -67,7 +68,7 @@ class write_some_op
public:
write_some_op(write_some_op&&) = default;
- write_some_op(write_some_op const&) = default;
+ write_some_op(write_some_op const&) = delete;
template<class DeducedHandler>
write_some_op(DeducedHandler&& h, Stream& s,
@@ -84,7 +85,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
@@ -93,7 +94,7 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, s_.get_executor());
}
@@ -112,6 +113,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, write_some_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
template<
@@ -203,7 +212,7 @@ class write_op
public:
write_op(write_op&&) = default;
- write_op(write_op const&) = default;
+ write_op(write_op const&) = delete;
template<class DeducedHandler>
write_op(DeducedHandler&& h, Stream& s,
@@ -220,7 +229,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
@@ -229,7 +238,7 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, s_.get_executor());
}
@@ -246,6 +255,14 @@ public:
asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, write_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
template<
@@ -280,7 +297,7 @@ operator()(
case 2:
state_ = 3;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case 3:
{
@@ -306,7 +323,7 @@ class write_msg_op
Stream& s;
serializer<isRequest, Body, Fields> sr;
- data(Handler&, Stream& s_, message<
+ data(Handler const&, Stream& s_, message<
isRequest, Body, Fields>& m_)
: s(s_)
, sr(m_)
@@ -318,7 +335,7 @@ class write_msg_op
public:
write_msg_op(write_msg_op&&) = default;
- write_msg_op(write_msg_op const&) = default;
+ write_msg_op(write_msg_op const&) = delete;
template<class DeducedHandler, class... Args>
write_msg_op(DeducedHandler&& h, Stream& s, Args&&... args)
@@ -333,7 +350,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(d_.handler());
+ return (boost::asio::get_associated_allocator)(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
@@ -342,7 +359,7 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
d_.handler(), d_->s.get_executor());
}
@@ -360,6 +377,14 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, write_msg_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->d_.handler()));
+ }
};
template<class Stream, class Handler,
@@ -441,7 +466,7 @@ template<
class SyncWriteStream,
bool isRequest, class Body, class Fields>
std::size_t
-write_some(
+write_some_impl(
SyncWriteStream& stream,
serializer<isRequest, Body, Fields>& sr,
error_code& ec)
@@ -466,20 +491,19 @@ template<
class WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
-async_write_some(
+async_write_some_impl(
AsyncWriteStream& stream,
serializer<isRequest, Body, Fields>& sr,
WriteHandler&& handler)
{
- boost::asio::async_completion<
- WriteHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
detail::write_some_op<
AsyncWriteStream,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
isRequest, Body, Fields>{
- init.completion_handler, stream, sr}();
+ std::move(init.completion_handler), stream, sr}();
return init.result.get();
}
@@ -524,7 +548,7 @@ write_some(
"Body requirements not met");
static_assert(is_body_writer<Body>::value,
"BodyWriter requirements not met");
- return detail::write_some(stream, sr, ec);
+ return detail::write_some_impl(stream, sr, ec);
}
template<
@@ -545,7 +569,7 @@ async_write_some(
"Body requirements not met");
static_assert(is_body_writer<Body>::value,
"BodyWriter requirements not met");
- return detail::async_write_some(stream, sr,
+ return detail::async_write_some_impl(stream, sr,
std::forward<WriteHandler>(handler));
}
@@ -629,16 +653,15 @@ async_write_header(
static_assert(is_body_writer<Body>::value,
"BodyWriter requirements not met");
sr.split(true);
- boost::asio::async_completion<
- WriteHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
detail::write_op<
AsyncWriteStream,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
detail::serializer_is_header_done,
isRequest, Body, Fields>{
- init.completion_handler, stream, sr}();
+ std::move(init.completion_handler), stream, sr}();
return init.result.get();
}
@@ -706,16 +729,15 @@ async_write(
static_assert(is_body_writer<Body>::value,
"BodyWriter requirements not met");
sr.split(false);
- boost::asio::async_completion<
- WriteHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
detail::write_op<
AsyncWriteStream,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
detail::serializer_is_done,
isRequest, Body, Fields>{
- init.completion_handler, stream, sr}();
+ std::move(init.completion_handler), stream, sr}();
return init.result.get();
}
@@ -780,15 +802,14 @@ async_write(
"Body requirements not met");
static_assert(is_body_writer<Body>::value,
"BodyWriter requirements not met");
- boost::asio::async_completion<
- WriteHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
detail::write_msg_op<
AsyncWriteStream,
BOOST_ASIO_HANDLER_TYPE(WriteHandler,
void(error_code, std::size_t)),
isRequest, Body, Fields>{
- init.completion_handler, stream, msg}();
+ std::move(init.completion_handler), stream, msg}();
return init.result.get();
}
diff --git a/boost/beast/http/message.hpp b/boost/beast/http/message.hpp
index 5cf5d94dc9..0455042786 100644
--- a/boost/beast/http/message.hpp
+++ b/boost/beast/http/message.hpp
@@ -862,7 +862,8 @@ struct message
#endif
body()& noexcept
{
- return this->member();
+ return this->beast::detail::empty_base_optimization<
+ typename Body::value_type>::member();
}
/// Returns the body
@@ -873,7 +874,9 @@ struct message
#endif
body()&& noexcept
{
- return std::move(this->member());
+ return std::move(
+ this->beast::detail::empty_base_optimization<
+ typename Body::value_type>::member());
}
/// Returns the body
@@ -884,7 +887,8 @@ struct message
#endif
body() const& noexcept
{
- return this->member();
+ return this->beast::detail::empty_base_optimization<
+ typename Body::value_type>::member();
}
private:
diff --git a/boost/beast/http/parser.hpp b/boost/beast/http/parser.hpp
index 47e1003533..69d93cf03c 100644
--- a/boost/beast/http/parser.hpp
+++ b/boost/beast/http/parser.hpp
@@ -63,7 +63,7 @@ class parser
parser<isRequest, Body, Allocator>>;
message<isRequest, Body, basic_fields<Allocator>> m_;
- typename Body::reader wr_;
+ typename Body::reader rd_;
bool rd_inited_ = false;
std::function<void(
@@ -84,21 +84,17 @@ public:
/// Destructor
~parser() = default;
- /// Constructor
- parser();
-
- /// Constructor
+ /// Constructor (disallowed)
parser(parser const&) = delete;
- /// Assignment
+ /// Assignment (disallowed)
parser& operator=(parser const&) = delete;
- /** Constructor
+ /// Constructor (disallowed)
+ parser(parser&& other) = delete;
- After the move, the only valid operation
- on the moved-from object is destruction.
- */
- parser(parser&& other) = default;
+ /// Constructor
+ parser();
/** Constructor
@@ -303,6 +299,39 @@ public:
private:
friend class basic_parser<isRequest, parser>;
+ parser(std::true_type);
+ parser(std::false_type);
+
+ template<class OtherBody, class... Args,
+ class = typename std::enable_if<
+ ! std::is_same<Body, OtherBody>::value>::type>
+ parser(
+ std::true_type,
+ parser<isRequest, OtherBody, Allocator>&& parser,
+ Args&&... args);
+
+ template<class OtherBody, class... Args,
+ class = typename std::enable_if<
+ ! std::is_same<Body, OtherBody>::value>::type>
+ parser(
+ std::false_type,
+ parser<isRequest, OtherBody, Allocator>&& parser,
+ Args&&... args);
+
+ template<class Arg1, class... ArgN,
+ class = typename std::enable_if<
+ ! detail::is_parser<typename
+ std::decay<Arg1>::type>::value>::type>
+ explicit
+ parser(Arg1&& arg1, std::true_type, ArgN&&... argn);
+
+ template<class Arg1, class... ArgN,
+ class = typename std::enable_if<
+ ! detail::is_parser<typename
+ std::decay<Arg1>::type>::value>::type>
+ explicit
+ parser(Arg1&& arg1, std::false_type, ArgN&&... argn);
+
void
on_request_impl(
verb method,
@@ -376,7 +405,7 @@ private:
boost::optional<std::uint64_t> const& content_length,
error_code& ec)
{
- wr_.init(content_length, ec);
+ rd_.init(content_length, ec);
rd_inited_ = true;
}
@@ -385,7 +414,7 @@ private:
string_view body,
error_code& ec)
{
- return wr_.put(boost::asio::buffer(
+ return rd_.put(boost::asio::buffer(
body.data(), body.size()), ec);
}
@@ -408,14 +437,14 @@ private:
{
if(cb_b_)
return cb_b_(remain, body, ec);
- return wr_.put(boost::asio::buffer(
+ return rd_.put(boost::asio::buffer(
body.data(), body.size()), ec);
}
void
on_finish_impl(error_code& ec)
{
- wr_.finish(ec);
+ rd_.finish(ec);
}
};
diff --git a/boost/beast/http/read.hpp b/boost/beast/http/read.hpp
index 4f159aec2b..a4f0efe400 100644
--- a/boost/beast/http/read.hpp
+++ b/boost/beast/http/read.hpp
@@ -175,8 +175,8 @@ read_some(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the request
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation
@@ -361,8 +361,8 @@ read_header(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the request
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation,
@@ -545,8 +545,8 @@ read(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the request
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation,
@@ -731,8 +731,8 @@ read(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the operation
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation,
diff --git a/boost/beast/http/serializer.hpp b/boost/beast/http/serializer.hpp
index 50e58185a9..bbb562a620 100644
--- a/boost/beast/http/serializer.hpp
+++ b/boost/beast/http/serializer.hpp
@@ -71,14 +71,20 @@ public:
#if BOOST_BEAST_DOXYGEN
using value_type = implementation_defined;
#else
- using value_type =
- typename std::conditional<
- std::is_constructible<typename Body::writer,
- message<isRequest, Body, Fields>&>::value &&
- ! std::is_constructible<typename Body::writer,
- message<isRequest, Body, Fields> const&>::value,
- message<isRequest, Body, Fields>,
- message<isRequest, Body, Fields> const>::type;
+ using value_type = typename std::conditional<
+ (std::is_constructible<typename Body::writer,
+ header<isRequest, Fields>&,
+ typename Body::value_type&>::value &&
+ ! std::is_constructible<typename Body::writer,
+ header<isRequest, Fields> const&,
+ typename Body::value_type const&>::value) ||
+ // Deprecated BodyWriter Concept (v1.66)
+ (std::is_constructible<typename Body::writer,
+ message<isRequest, Body, Fields>&>::value &&
+ ! std::is_constructible<typename Body::writer,
+ message<isRequest, Body, Fields> const&>::value),
+ message<isRequest, Body, Fields>,
+ message<isRequest, Body, Fields> const>::type;
#endif
private:
@@ -104,8 +110,8 @@ private:
do_complete = 120
};
- void frdinit(std::true_type);
- void frdinit(std::false_type);
+ void fwrinit(std::true_type);
+ void fwrinit(std::false_type);
template<std::size_t, class Visit>
void
@@ -173,8 +179,8 @@ private:
using pcb8_t = buffers_prefix_view<cb8_t const&>;
value_type& m_;
- writer rd_;
- boost::optional<typename Fields::writer> frd_;
+ writer wr_;
+ boost::optional<typename Fields::writer> fwr_;
beast::detail::variant<
cb1_t, cb2_t, cb3_t, cb4_t,
cb5_t ,cb6_t, cb7_t, cb8_t> v_;
@@ -188,6 +194,8 @@ private:
bool header_done_ = false;
bool more_;
+ serializer(value_type& msg, std::true_type);
+ serializer(value_type& msg, std::false_type);
public:
/// Constructor
serializer(serializer&&) = default;
@@ -336,7 +344,7 @@ public:
void
consume(std::size_t n);
- /** Provides low-level access to the associated @b BodyWriter
+ /** Provides low-level access to the associated @b BodyWriter (DEPRECATED)
This function provides access to the instance of the writer
associated with the body and created by the serializer
@@ -349,7 +357,27 @@ public:
writer&
reader_impl()
{
- return rd_;
+ #ifndef BOOST_BEAST_ALLOW_DEPRECATED
+ BOOST_STATIC_ASSERT_MSG(sizeof(Body) == 0,
+ BOOST_BEAST_DEPRECATION_STRING);
+ #endif
+ return wr_;
+ }
+
+ /** Provides low-level access to the associated @b BodyWriter
+
+ This function provides access to the instance of the writer
+ associated with the body and created by the serializer
+ upon construction. The behavior of accessing this object
+ is defined by the specification of the particular writer
+ and its associated body.
+
+ @return A reference to the writer.
+ */
+ writer&
+ writer_impl()
+ {
+ return wr_;
}
};
diff --git a/boost/beast/http/span_body.hpp b/boost/beast/http/span_body.hpp
index 6282ecc6d9..4688dc8741 100644
--- a/boost/beast/http/span_body.hpp
+++ b/boost/beast/http/span_body.hpp
@@ -73,9 +73,8 @@ public:
public:
template<bool isRequest, class Fields>
explicit
- reader(message<isRequest,
- span_body, Fields>& m)
- : body_(m.body())
+ reader(header<isRequest, Fields>&, value_type& b)
+ : body_(b)
{
}
@@ -138,9 +137,8 @@ public:
template<bool isRequest, class Fields>
explicit
- writer(message<isRequest,
- span_body, Fields> const& msg)
- : body_(msg.body())
+ writer(header<isRequest, Fields> const&, value_type const& b)
+ : body_(b)
{
}
diff --git a/boost/beast/http/string_body.hpp b/boost/beast/http/string_body.hpp
index 18eda414e8..89447e50ff 100644
--- a/boost/beast/http/string_body.hpp
+++ b/boost/beast/http/string_body.hpp
@@ -81,9 +81,8 @@ public:
public:
template<bool isRequest, class Fields>
explicit
- reader(message<isRequest,
- basic_string_body, Fields>& m)
- : body_(m.body())
+ reader(header<isRequest, Fields>&, value_type& b)
+ : body_(b)
{
}
@@ -166,9 +165,8 @@ public:
template<bool isRequest, class Fields>
explicit
- writer(message<isRequest,
- basic_string_body, Fields> const& msg)
- : body_(msg.body())
+ writer(header<isRequest, Fields> const&, value_type const& b)
+ : body_(b)
{
}
diff --git a/boost/beast/http/type_traits.hpp b/boost/beast/http/type_traits.hpp
index f90f16ffef..0c8210443e 100644
--- a/boost/beast/http/type_traits.hpp
+++ b/boost/beast/http/type_traits.hpp
@@ -89,11 +89,19 @@ struct is_body_writer<T, beast::detail::void_t<
std::declval<typename T::writer>().get(std::declval<error_code&>()),
(void)0)>> : std::integral_constant<bool,
boost::asio::is_const_buffer_sequence<
- typename T::writer::const_buffers_type>::value &&
+ typename T::writer::const_buffers_type>::value && (
+ (std::is_constructible<typename T::writer,
+ header<true, detail::fields_model>&,
+ typename T::value_type&>::value &&
std::is_constructible<typename T::writer,
+ header<false, detail::fields_model>&,
+ typename T::value_type&>::value) ||
+ // Deprecated BodyWriter Concept (v1.66)
+ (std::is_constructible<typename T::writer,
message<true, T, detail::fields_model>&>::value &&
std::is_constructible<typename T::writer,
- message<false, T, detail::fields_model>&>::value
+ message<false, T, detail::fields_model>&>::value)
+ )
> {};
#endif
@@ -136,11 +144,18 @@ struct is_body_reader<T, beast::detail::void_t<decltype(
std::declval<typename T::reader&>().finish(
std::declval<error_code&>()),
(void)0)>> : std::integral_constant<bool,
+ (std::is_constructible<typename T::reader,
+ header<true, detail::fields_model>&,
+ typename T::value_type&>::value &&
std::is_constructible<typename T::reader,
+ header<false,detail::fields_model>&,
+ typename T::value_type&>::value) ||
+ // Deprecated BodyReader Concept (v1.66)
+ (std::is_constructible<typename T::reader,
message<true, T, detail::fields_model>&>::value &&
std::is_constructible<typename T::reader,
- message<false, T, detail::fields_model>&>::value
- >
+ message<false, T, detail::fields_model>&>::value)
+ >
{
};
#endif
diff --git a/boost/beast/http/vector_body.hpp b/boost/beast/http/vector_body.hpp
index eb37145d61..40c885e43e 100644
--- a/boost/beast/http/vector_body.hpp
+++ b/boost/beast/http/vector_body.hpp
@@ -76,9 +76,8 @@ public:
public:
template<bool isRequest, class Fields>
explicit
- reader(message<isRequest,
- vector_body, Fields>& m)
- : body_(m.body())
+ reader(header<isRequest, Fields>&, value_type& b)
+ : body_(b)
{
}
@@ -155,9 +154,8 @@ public:
template<bool isRequest, class Fields>
explicit
- writer(message<isRequest,
- vector_body, Fields> const& msg)
- : body_(msg.body())
+ writer(header<isRequest, Fields> const&, value_type const& b)
+ : body_(b)
{
}
diff --git a/boost/beast/http/write.hpp b/boost/beast/http/write.hpp
index 755ed0b94b..3b916b1d7b 100644
--- a/boost/beast/http/write.hpp
+++ b/boost/beast/http/write.hpp
@@ -148,8 +148,8 @@ write_some(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the operation
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation
@@ -269,8 +269,8 @@ write_header(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the operation
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation
@@ -387,8 +387,8 @@ write(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the operation
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation
@@ -502,8 +502,8 @@ write(
The object must remain valid at least until the
handler is called; ownership is not transferred.
- @param handler The handler to be called when the operation
- completes. Copies will be made of the handler as required.
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
The equivalent function signature of the handler must be:
@code void handler(
error_code const& error, // result of operation
diff --git a/boost/beast/version.hpp b/boost/beast/version.hpp
index e8898e66aa..c0c7b6fb06 100644
--- a/boost/beast/version.hpp
+++ b/boost/beast/version.hpp
@@ -20,7 +20,7 @@
This is a simple integer that is incremented by one every
time a set of code changes is merged to the develop branch.
*/
-#define BOOST_BEAST_VERSION 144
+#define BOOST_BEAST_VERSION 167
#define BOOST_BEAST_VERSION_STRING "Boost.Beast/" BOOST_STRINGIZE(BOOST_BEAST_VERSION)
diff --git a/boost/beast/websocket.hpp b/boost/beast/websocket.hpp
index 24b9d25e73..551eaff47b 100644
--- a/boost/beast/websocket.hpp
+++ b/boost/beast/websocket.hpp
@@ -16,6 +16,7 @@
#include <boost/beast/websocket/option.hpp>
#include <boost/beast/websocket/rfc6455.hpp>
#include <boost/beast/websocket/stream.hpp>
+#include <boost/beast/websocket/stream_fwd.hpp>
#include <boost/beast/websocket/teardown.hpp>
#endif
diff --git a/boost/beast/websocket/detail/error.hpp b/boost/beast/websocket/detail/error.hpp
new file mode 100644
index 0000000000..57b837bd4c
--- /dev/null
+++ b/boost/beast/websocket/detail/error.hpp
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2016-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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_ERROR_IPP
+#define BOOST_BEAST_WEBSOCKET_DETAIL_ERROR_IPP
+
+#include <boost/beast/core/error.hpp>
+#include <boost/beast/core/string.hpp>
+
+namespace boost {
+
+namespace beast {
+namespace websocket {
+enum class error;
+enum class condition;
+} // websocket
+} // beast
+
+namespace system {
+template<>
+struct is_error_code_enum<beast::websocket::error>
+{
+ static bool const value = true;
+};
+template<>
+struct is_error_condition_enum<beast::websocket::condition>
+{
+ static bool const value = true;
+};
+} // system
+
+namespace beast {
+namespace websocket {
+namespace detail {
+
+class error_codes : public error_category
+{
+public:
+ const char*
+ name() const noexcept override;
+
+ std::string
+ message(int ev) const override;
+
+ error_condition
+ default_error_condition(int ev) const noexcept override;
+};
+
+class error_conditions : public error_category
+{
+public:
+ const char*
+ name() const noexcept override;
+
+ std::string
+ message(int cv) const override;
+};
+
+} // detail
+
+error_code
+make_error_code(error e);
+
+error_condition
+make_error_condition(condition c);
+
+} // websocket
+} // beast
+
+} // boost
+
+#endif
diff --git a/boost/beast/websocket/detail/frame.hpp b/boost/beast/websocket/detail/frame.hpp
index 95080aeefc..c3bd1690a9 100644
--- a/boost/beast/websocket/detail/frame.hpp
+++ b/boost/beast/websocket/detail/frame.hpp
@@ -10,6 +10,7 @@
#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
#define BOOST_BEAST_WEBSOCKET_DETAIL_FRAME_HPP
+#include <boost/beast/websocket/error.hpp>
#include <boost/beast/websocket/rfc6455.hpp>
#include <boost/beast/websocket/detail/utf8_checker.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
@@ -75,7 +76,7 @@ native_to_little_uint32(std::uint32_t v, void* buf)
p[3] = (v >> 24) & 0xff;
}
-/** WebSocket frame header opcodes. */
+// frame header opcodes
enum class opcode : std::uint8_t
{
cont = 0,
@@ -110,8 +111,7 @@ struct frame_header
};
// holds the largest possible frame header
-using fh_buffer =
- flat_static_buffer<14>;
+using fh_buffer = flat_static_buffer<14>;
// holds the largest possible control frame
using frame_buffer =
@@ -245,8 +245,10 @@ read_ping(ping_data& data, Buffers const& bs)
//
template<class Buffers>
void
-read_close(close_reason& cr,
- Buffers const& bs, close_code& code)
+read_close(
+ close_reason& cr,
+ Buffers const& bs,
+ error_code& ec)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
@@ -257,12 +259,13 @@ read_close(close_reason& cr,
if(n == 0)
{
cr = close_reason{};
- code = close_code::none;
+ ec.assign(0, ec.category());
return;
}
if(n == 1)
{
- code = close_code::protocol_error;
+ // invalid payload size == 1
+ ec = error::bad_close_size;
return;
}
buffers_suffix<Buffers> cb(bs);
@@ -274,7 +277,8 @@ read_close(close_reason& cr,
n -= 2;
if(! is_valid_close_code(cr.code))
{
- code = close_code::protocol_error;
+ // invalid close code
+ ec = error::bad_close_code;
return;
}
}
@@ -285,7 +289,8 @@ read_close(close_reason& cr,
if(! check_utf8(
cr.reason.data(), cr.reason.size()))
{
- code = close_code::protocol_error;
+ // not valid utf-8
+ ec = error::bad_close_payload;
return;
}
}
@@ -293,7 +298,7 @@ read_close(close_reason& cr,
{
cr.reason = "";
}
- code = close_code::none;
+ ec.assign(0, ec.category());
}
} // detail
diff --git a/boost/beast/websocket/detail/mask.hpp b/boost/beast/websocket/detail/mask.hpp
index 92ea0a4238..8958d793b8 100644
--- a/boost/beast/websocket/detail/mask.hpp
+++ b/boost/beast/websocket/detail/mask.hpp
@@ -11,6 +11,7 @@
#define BOOST_BEAST_WEBSOCKET_DETAIL_MASK_HPP
#include <boost/beast/core/detail/config.hpp>
+#include <boost/beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <array>
#include <climits>
@@ -83,179 +84,59 @@ using maskgen = maskgen_t<std::minstd_rand>;
//------------------------------------------------------------------------------
-using prepared_key =
- std::conditional<sizeof(void*) == 8,
- std::uint64_t, std::uint32_t>::type;
+using prepared_key = std::array<unsigned char, 4>;
inline
void
-prepare_key(std::uint32_t& prepared, std::uint32_t key)
+prepare_key(prepared_key& prepared, std::uint32_t key)
{
- prepared = key;
+ prepared[0] = (key >> 0) & 0xff;
+ prepared[1] = (key >> 8) & 0xff;
+ prepared[2] = (key >> 16) & 0xff;
+ prepared[3] = (key >> 24) & 0xff;
}
-inline
+template<std::size_t N>
void
-prepare_key(std::uint64_t& prepared, std::uint32_t key)
-{
- prepared =
- (static_cast<std::uint64_t>(key) << 32) | key;
-}
-
-template<class T>
-inline
-typename std::enable_if<std::is_integral<T>::value, T>::type
-ror(T t, unsigned n = 1)
+rol(std::array<unsigned char, N>& v, std::size_t n)
{
- auto constexpr bits =
- static_cast<unsigned>(
- sizeof(T) * CHAR_BIT);
- n &= bits-1;
- return static_cast<T>((t << (bits - n)) | (
- static_cast<typename std::make_unsigned<T>::type>(t) >> n));
+ auto v0 = v;
+ for(std::size_t i = 0; i < v.size(); ++i )
+ v[i] = v0[(i + n) % v.size()];
}
-// 32-bit optimized
-//
-template<class = void>
-void
-mask_inplace_fast(
- boost::asio::mutable_buffer const& b,
- std::uint32_t& key)
-{
- auto n = b.size();
- auto p = reinterpret_cast<std::uint8_t*>(b.data());
- if(n >= sizeof(key))
- {
- // Bring p to 4-byte alignment
- auto const i = reinterpret_cast<
- std::uintptr_t>(p) & (sizeof(key)-1);
- switch(i)
- {
- case 1: p[2] ^= static_cast<std::uint8_t>(key >> 16); BOOST_BEAST_FALLTHROUGH;
- case 2: p[1] ^= static_cast<std::uint8_t>(key >> 8); BOOST_BEAST_FALLTHROUGH;
- case 3: p[0] ^= static_cast<std::uint8_t>(key);
- {
- auto const d = static_cast<unsigned>(sizeof(key) - i);
- key = ror(key, 8*d);
- n -= d;
- p += d;
- BOOST_BEAST_FALLTHROUGH;
- }
- default:
- break;
- }
- }
-
- // Mask 4 bytes at a time
- for(auto i = n / sizeof(key); i; --i)
- {
- *reinterpret_cast<
- std::uint32_t*>(p) ^= key;
- p += sizeof(key);
- }
-
- // Leftovers
- n &= sizeof(key)-1;
- switch(n)
- {
- case 3: p[2] ^= static_cast<std::uint8_t>(key >> 16); BOOST_BEAST_FALLTHROUGH;
- case 2: p[1] ^= static_cast<std::uint8_t>(key >> 8); BOOST_BEAST_FALLTHROUGH;
- case 1: p[0] ^= static_cast<std::uint8_t>(key);
- key = ror(key, static_cast<unsigned>(8*n));
- BOOST_BEAST_FALLTHROUGH;
- default:
- break;
- }
-}
-
-// 64-bit optimized
+// Apply mask in place
//
-template<class = void>
+inline
void
-mask_inplace_fast(
- boost::asio::mutable_buffer const& b,
- std::uint64_t& key)
+mask_inplace(boost::asio::mutable_buffer& b, prepared_key& key)
{
auto n = b.size();
- auto p = reinterpret_cast<std::uint8_t*>(b.data());
- if(n >= sizeof(key))
+ auto mask = key; // avoid aliasing
+ auto p = reinterpret_cast<unsigned char*>(b.data());
+ while(n >= 4)
{
- // Bring p to 8-byte alignment
- auto const i = reinterpret_cast<
- std::uintptr_t>(p) & (sizeof(key)-1);
- switch(i)
- {
- case 1: p[6] ^= static_cast<std::uint8_t>(key >> 48);
- case 2: p[5] ^= static_cast<std::uint8_t>(key >> 40);
- case 3: p[4] ^= static_cast<std::uint8_t>(key >> 32);
- case 4: p[3] ^= static_cast<std::uint8_t>(key >> 24);
- case 5: p[2] ^= static_cast<std::uint8_t>(key >> 16);
- case 6: p[1] ^= static_cast<std::uint8_t>(key >> 8);
- case 7: p[0] ^= static_cast<std::uint8_t>(key);
- {
- auto const d = static_cast<
- unsigned>(sizeof(key) - i);
- key = ror(key, 8*d);
- n -= d;
- p += d;
- }
- default:
- break;
- }
+ for(int i = 0; i < 4; ++i)
+ p[i] ^= mask[i];
+ p += 4;
+ n -= 4;
}
-
- // Mask 8 bytes at a time
- for(auto i = n / sizeof(key); i; --i)
+ if(n > 0)
{
- *reinterpret_cast<
- std::uint64_t*>(p) ^= key;
- p += sizeof(key);
+ for(std::size_t i = 0; i < n; ++i)
+ p[i] ^= mask[i];
+ rol(key, n);
}
-
- // Leftovers
- n &= sizeof(key)-1;
- switch(n)
- {
- case 7: p[6] ^= static_cast<std::uint8_t>(key >> 48);
- case 6: p[5] ^= static_cast<std::uint8_t>(key >> 40);
- case 5: p[4] ^= static_cast<std::uint8_t>(key >> 32);
- case 4: p[3] ^= static_cast<std::uint8_t>(key >> 24);
- case 3: p[2] ^= static_cast<std::uint8_t>(key >> 16);
- case 2: p[1] ^= static_cast<std::uint8_t>(key >> 8);
- case 1: p[0] ^= static_cast<std::uint8_t>(key);
- key = ror(key, static_cast<unsigned>(8*n));
- default:
- break;
- }
-}
-
-inline
-void
-mask_inplace(
- boost::asio::mutable_buffer const& b,
- std::uint32_t& key)
-{
- mask_inplace_fast(b, key);
-}
-
-inline
-void
-mask_inplace(
- boost::asio::mutable_buffer const& b,
- std::uint64_t& key)
-{
- mask_inplace_fast(b, key);
}
// Apply mask in place
//
template<class MutableBuffers, class KeyType>
void
-mask_inplace(
- MutableBuffers const& bs, KeyType& key)
+mask_inplace(MutableBuffers const& bs, KeyType& key)
{
- for(boost::asio::mutable_buffer b : bs)
+ for(boost::asio::mutable_buffer b :
+ beast::detail::buffers_range(bs))
mask_inplace(b, key);
}
diff --git a/boost/beast/websocket/detail/pausation.hpp b/boost/beast/websocket/detail/pausation.hpp
index f51ee10327..e3870b038a 100644
--- a/boost/beast/websocket/detail/pausation.hpp
+++ b/boost/beast/websocket/detail/pausation.hpp
@@ -10,13 +10,10 @@
#ifndef BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP
#define BOOST_BEAST_WEBSOCKET_DETAIL_PAUSATION_HPP
-#include <boost/beast/core/handler_ptr.hpp>
+#include <boost/beast/core/detail/allocator.hpp>
#include <boost/asio/associated_allocator.hpp>
-#include <boost/asio/coroutine.hpp>
#include <boost/assert.hpp>
-#include <array>
#include <memory>
-#include <new>
#include <utility>
namespace boost {
@@ -30,124 +27,59 @@ namespace detail {
//
class pausation
{
- struct base
+ struct handler
{
- base() = default;
- base(base &&) = delete;
- base(base const&) = delete;
- virtual ~base() = default;
- virtual void operator()() = 0;
+ handler() = default;
+ handler(handler &&) = delete;
+ handler(handler const&) = delete;
+ virtual ~handler() = default;
+ virtual void destroy() = 0;
+ virtual void invoke() = 0;
};
- template<class F>
- struct holder : base
+ template<class Handler>
+ class impl : public handler
{
- F f;
-
- holder(holder&&) = default;
-
- template<class U>
- explicit
- holder(U&& u)
- : f(std::forward<U>(u))
- {
- }
-
- void
- operator()() override
- {
- F f_(std::move(f));
- this->~holder();
- // invocation of f_() can
- // assign a new object to *this.
- f_();
- }
- };
-
- struct exemplar : boost::asio::coroutine
- {
- struct H
- {
- void operator()();
- };
-
- struct T
- {
- using handler_type = H;
- };
-
- handler_ptr<T, H> hp;
-
- void operator()();
- };
-
- template<class Op>
- class saved_op
- {
- Op* op_ = nullptr;
+ Handler h_;
public:
- ~saved_op()
- {
- if(op_)
- {
- Op op(std::move(*op_));
- op_->~Op();
- typename std::allocator_traits<
- boost::asio::associated_allocator_t<Op>>::
- template rebind_alloc<Op> alloc{
- boost::asio::get_associated_allocator(op)};
- std::allocator_traits<
- decltype(alloc)>::deallocate(alloc, op_, 1);
- }
- }
-
- saved_op(saved_op&& other)
- : op_(other.op_)
+ template<class DeducedHandler>
+ impl(DeducedHandler&& h)
+ : h_(std::forward<DeducedHandler>(h))
{
- other.op_ = nullptr;
}
- saved_op& operator=(saved_op&& other)
- {
- BOOST_ASSERT(! op_);
- op_ = other.op_;
- other.op_ = 0;
- return *this;
- }
-
- explicit
- saved_op(Op&& op)
+ void
+ destroy() override
{
- typename std::allocator_traits<
- boost::asio::associated_allocator_t<Op>>::
- template rebind_alloc<Op> alloc{
- boost::asio::get_associated_allocator(op)};
- auto const p = std::allocator_traits<
- decltype(alloc)>::allocate(alloc, 1);
- op_ = new(p) Op{std::move(op)};
+ Handler h(std::move(h_));
+ typename beast::detail::allocator_traits<
+ boost::asio::associated_allocator_t<
+ Handler>>::template rebind_alloc<impl> alloc{
+ boost::asio::get_associated_allocator(h)};
+ beast::detail::allocator_traits<
+ decltype(alloc)>::destroy(alloc, this);
+ beast::detail::allocator_traits<
+ decltype(alloc)>::deallocate(alloc, this, 1);
}
void
- operator()()
+ invoke() override
{
- BOOST_ASSERT(op_);
- Op op{std::move(*op_)};
- typename std::allocator_traits<
- boost::asio::associated_allocator_t<Op>>::
- template rebind_alloc<Op> alloc{
- boost::asio::get_associated_allocator(op)};
- std::allocator_traits<
- decltype(alloc)>::deallocate(alloc, op_, 1);
- op_ = nullptr;
- op();
+ Handler h(std::move(h_));
+ typename beast::detail::allocator_traits<
+ boost::asio::associated_allocator_t<
+ Handler>>::template rebind_alloc<impl> alloc{
+ boost::asio::get_associated_allocator(h)};
+ beast::detail::allocator_traits<
+ decltype(alloc)>::destroy(alloc, this);
+ beast::detail::allocator_traits<
+ decltype(alloc)>::deallocate(alloc, this, 1);
+ h();
}
};
- using buf_type = char[sizeof(holder<exemplar>)];
-
- base* base_ = nullptr;
- alignas(holder<exemplar>) buf_type buf_;
+ handler* h_ = nullptr;
public:
pausation() = default;
@@ -156,69 +88,70 @@ public:
~pausation()
{
- if(base_)
- base_->~base();
+ if(h_)
+ h_->destroy();
}
pausation(pausation&& other)
{
boost::ignore_unused(other);
- BOOST_ASSERT(! other.base_);
+ BOOST_ASSERT(! other.h_);
}
pausation&
operator=(pausation&& other)
{
boost::ignore_unused(other);
- BOOST_ASSERT(! base_);
- BOOST_ASSERT(! other.base_);
+ BOOST_ASSERT(! h_);
+ BOOST_ASSERT(! other.h_);
return *this;
}
- template<class F>
- void
- emplace(F&& f);
-
- template<class F>
+ template<class CompletionHandler>
void
- save(F&& f);
+ emplace(CompletionHandler&& handler);
explicit
operator bool() const
{
- return base_ != nullptr;
+ return h_ != nullptr;
}
bool
maybe_invoke()
{
- if(base_)
+ if(h_)
{
- auto const basep = base_;
- base_ = nullptr;
- (*basep)();
+ auto const h = h_;
+ h_ = nullptr;
+ h->invoke();
return true;
}
return false;
}
};
-template<class F>
+template<class CompletionHandler>
void
-pausation::emplace(F&& f)
+pausation::emplace(CompletionHandler&& handler)
{
- using type = holder<typename std::decay<F>::type>;
- static_assert(sizeof(buf_type) >= sizeof(type),
- "buffer too small");
- BOOST_ASSERT(! base_);
- base_ = ::new(buf_) type{std::forward<F>(f)};
-}
-
-template<class F>
-void
-pausation::save(F&& f)
-{
- emplace(saved_op<F>{std::move(f)});
+ BOOST_ASSERT(! h_);
+ typename beast::detail::allocator_traits<
+ boost::asio::associated_allocator_t<
+ CompletionHandler>>::template rebind_alloc<
+ impl<CompletionHandler>> alloc{
+ boost::asio::get_associated_allocator(handler)};
+ using A = decltype(alloc);
+ auto const d =
+ [&alloc](impl<CompletionHandler>* p)
+ {
+ beast::detail::allocator_traits<A>::deallocate(alloc, p, 1);
+ };
+ std::unique_ptr<impl<CompletionHandler>, decltype(d)> p{
+ beast::detail::allocator_traits<A>::allocate(alloc, 1), d};
+ beast::detail::allocator_traits<A>::construct(
+ alloc, p.get(), std::forward<CompletionHandler>(handler));
+ h_ = p.release();
}
} // detail
diff --git a/boost/beast/websocket/detail/pmd_extension.hpp b/boost/beast/websocket/detail/pmd_extension.hpp
index a28b844cd7..ce4f2425cf 100644
--- a/boost/beast/websocket/detail/pmd_extension.hpp
+++ b/boost/beast/websocket/detail/pmd_extension.hpp
@@ -19,6 +19,7 @@
#include <boost/beast/http/rfc7230.hpp>
#include <boost/asio/buffer.hpp>
#include <utility>
+#include <type_traits>
namespace boost {
namespace beast {
@@ -355,85 +356,6 @@ pmd_normalize(pmd_offer& offer)
}
}
-//--------------------------------------------------------------------
-
-// Compress a buffer sequence
-// Returns: `true` if more calls are needed
-//
-template<class DeflateStream, class ConstBufferSequence>
-bool
-deflate(
- DeflateStream& zo,
- boost::asio::mutable_buffer& out,
- buffers_suffix<ConstBufferSequence>& cb,
- bool fin,
- std::size_t& total_in,
- error_code& ec)
-{
- using boost::asio::buffer;
- BOOST_ASSERT(out.size() >= 6);
- zlib::z_params zs;
- zs.avail_in = 0;
- zs.next_in = nullptr;
- zs.avail_out = out.size();
- zs.next_out = out.data();
- for(auto in : beast::detail::buffers_range(cb))
- {
- zs.avail_in = in.size();
- if(zs.avail_in == 0)
- continue;
- zs.next_in = in.data();
- zo.write(zs, zlib::Flush::none, ec);
- if(ec)
- {
- if(ec != zlib::error::need_buffers)
- return false;
- BOOST_ASSERT(zs.avail_out == 0);
- BOOST_ASSERT(zs.total_out == out.size());
- ec.assign(0, ec.category());
- break;
- }
- if(zs.avail_out == 0)
- {
- BOOST_ASSERT(zs.total_out == out.size());
- break;
- }
- BOOST_ASSERT(zs.avail_in == 0);
- }
- total_in = zs.total_in;
- cb.consume(zs.total_in);
- if(zs.avail_out > 0 && fin)
- {
- auto const remain = boost::asio::buffer_size(cb);
- if(remain == 0)
- {
- // Inspired by Mark Adler
- // https://github.com/madler/zlib/issues/149
- //
- // VFALCO We could do this flush twice depending
- // on how much space is in the output.
- zo.write(zs, zlib::Flush::block, ec);
- BOOST_ASSERT(! ec || ec == zlib::error::need_buffers);
- if(ec == zlib::error::need_buffers)
- ec.assign(0, ec.category());
- if(ec)
- return false;
- if(zs.avail_out >= 6)
- {
- zo.write(zs, zlib::Flush::full, ec);
- BOOST_ASSERT(! ec);
- // remove flush marker
- zs.total_out -= 4;
- out = buffer(out.data(), zs.total_out);
- return false;
- }
- }
- }
- ec.assign(0, ec.category());
- out = buffer(out.data(), zs.total_out);
- return true;
-}
-
} // detail
} // websocket
} // beast
diff --git a/boost/beast/websocket/detail/stream_base.hpp b/boost/beast/websocket/detail/stream_base.hpp
new file mode 100644
index 0000000000..2e93cce3d4
--- /dev/null
+++ b/boost/beast/websocket/detail/stream_base.hpp
@@ -0,0 +1,221 @@
+//
+// Copyright (c) 2016-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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP
+#define BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP
+
+#include <boost/beast/websocket/option.hpp>
+#include <boost/beast/websocket/detail/pmd_extension.hpp>
+#include <boost/beast/zlib/deflate_stream.hpp>
+#include <boost/beast/zlib/inflate_stream.hpp>
+#include <boost/beast/core/buffers_suffix.hpp>
+#include <boost/beast/core/error.hpp>
+#include <boost/asio/buffer.hpp>
+#include <cstdint>
+#include <memory>
+
+namespace boost {
+namespace beast {
+namespace websocket {
+namespace detail {
+
+// used to order reads and writes
+class soft_mutex
+{
+ int id_ = 0;
+
+public:
+ soft_mutex() = default;
+ soft_mutex(soft_mutex const&) = delete;
+ soft_mutex& operator=(soft_mutex const&) = delete;
+
+ soft_mutex(soft_mutex&& other) noexcept
+ : id_(other.id_)
+ {
+ other.id_ = 0;
+ }
+
+ soft_mutex& operator=(soft_mutex&& other) noexcept
+ {
+ id_ = other.id_;
+ other.id_ = 0;
+ return *this;
+ }
+
+ // VFALCO I'm not too happy that this function is needed
+ void reset()
+ {
+ id_ = 0;
+ }
+
+ bool is_locked() const
+ {
+ return id_ != 0;
+ }
+
+ template<class T>
+ bool is_locked(T const*) const
+ {
+ return id_ == T::id;
+ }
+
+ template<class T>
+ void lock(T const*)
+ {
+ BOOST_ASSERT(id_ == 0);
+ id_ = T::id;
+ }
+
+ template<class T>
+ void unlock(T const*)
+ {
+ BOOST_ASSERT(id_ == T::id);
+ id_ = 0;
+ }
+
+ template<class T>
+ bool try_lock(T const*)
+ {
+ // If this assert goes off it means you are attempting to
+ // simultaneously initiate more than one of same asynchronous
+ // operation, which is not allowed. For example, you must wait
+ // for an async_read to complete before performing another
+ // async_read.
+ //
+ BOOST_ASSERT(id_ != T::id);
+ if(id_ != 0)
+ return false;
+ id_ = T::id;
+ return true;
+ }
+
+ template<class T>
+ bool try_unlock(T const*)
+ {
+ if(id_ != T::id)
+ return false;
+ id_ = 0;
+ return true;
+ }
+};
+
+template<bool deflateSupported>
+struct stream_base
+{
+ // State information for the permessage-deflate extension
+ struct pmd_type
+ {
+ // `true` if current read message is compressed
+ bool rd_set = false;
+
+ zlib::deflate_stream zo;
+ zlib::inflate_stream zi;
+ };
+
+ std::unique_ptr<pmd_type> pmd_; // pmd settings or nullptr
+ permessage_deflate pmd_opts_; // local pmd options
+ detail::pmd_offer pmd_config_; // offer (client) or negotiation (server)
+
+ // return `true` if current message is deflated
+ bool
+ rd_deflated() const
+ {
+ return pmd_ && pmd_->rd_set;
+ }
+
+ // set whether current message is deflated
+ // returns `false` on protocol violation
+ bool
+ rd_deflated(bool rsv1)
+ {
+ if(pmd_)
+ {
+ pmd_->rd_set = rsv1;
+ return true;
+ }
+ return ! rsv1; // pmd not negotiated
+ }
+
+ template<class ConstBufferSequence>
+ bool
+ deflate(
+ boost::asio::mutable_buffer& out,
+ buffers_suffix<ConstBufferSequence>& cb,
+ bool fin,
+ std::size_t& total_in,
+ error_code& ec);
+
+ void
+ do_context_takeover_write(role_type role);
+
+ void
+ inflate(
+ zlib::z_params& zs,
+ zlib::Flush flush,
+ error_code& ec);
+
+ void
+ do_context_takeover_read(role_type role);
+};
+
+template<>
+struct stream_base<false>
+{
+ // These stubs are for avoiding linking in the zlib
+ // code when permessage-deflate is not enabled.
+
+ bool
+ rd_deflated() const
+ {
+ return false;
+ }
+
+ bool
+ rd_deflated(bool rsv1)
+ {
+ return ! rsv1;
+ }
+
+ template<class ConstBufferSequence>
+ bool
+ deflate(
+ boost::asio::mutable_buffer&,
+ buffers_suffix<ConstBufferSequence>&,
+ bool,
+ std::size_t&,
+ error_code&)
+ {
+ return false;
+ }
+
+ void
+ do_context_takeover_write(role_type)
+ {
+ }
+
+ void
+ inflate(
+ zlib::z_params&,
+ zlib::Flush,
+ error_code&)
+ {
+ }
+
+ void
+ do_context_takeover_read(role_type)
+ {
+ }
+};
+
+} // detail
+} // websocket
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/websocket/detail/type_traits.hpp b/boost/beast/websocket/detail/type_traits.hpp
index 6c2806146c..6913174fd0 100644
--- a/boost/beast/websocket/detail/type_traits.hpp
+++ b/boost/beast/websocket/detail/type_traits.hpp
@@ -19,12 +19,12 @@ namespace websocket {
namespace detail {
template<class F>
-using is_RequestDecorator =
+using is_request_decorator =
typename beast::detail::is_invocable<F,
void(request_type&)>::type;
template<class F>
-using is_ResponseDecorator =
+using is_response_decorator =
typename beast::detail::is_invocable<F,
void(response_type&)>::type;
diff --git a/boost/beast/websocket/detail/utf8_checker.hpp b/boost/beast/websocket/detail/utf8_checker.hpp
index e86310f051..61c241bc19 100644
--- a/boost/beast/websocket/detail/utf8_checker.hpp
+++ b/boost/beast/websocket/detail/utf8_checker.hpp
@@ -151,13 +151,13 @@ write(std::uint8_t const* in, std::size_t size)
{
default:
BOOST_ASSERT(false);
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case 1:
cp_[1] = 0x81;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case 2:
cp_[2] = 0x81;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case 3:
cp_[3] = 0x81;
break;
diff --git a/boost/beast/websocket/error.hpp b/boost/beast/websocket/error.hpp
index 139a20879d..d4e5197100 100644
--- a/boost/beast/websocket/error.hpp
+++ b/boost/beast/websocket/error.hpp
@@ -10,6 +10,7 @@
#ifndef BOOST_BEAST_WEBSOCKET_ERROR_HPP
#define BOOST_BEAST_WEBSOCKET_ERROR_HPP
+#include <boost/beast/websocket/detail/error.hpp>
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/error.hpp>
@@ -20,22 +21,230 @@ namespace websocket {
/// Error codes returned from @ref beast::websocket::stream operations.
enum class error
{
- /// Both sides performed a WebSocket close
+ /** The WebSocket stream was gracefully closed at both endpoints
+ */
closed = 1,
- /// WebSocket connection failed, protocol violation
- failed,
+/* The error codes error::failed and error::handshake_failed
+ are no longer in use. Please change your code to compare values
+ of type error_code against condition::handshake_failed
+ and condition::protocol_violation instead.
+
+ Apologies for the inconvenience.
- /// Upgrade handshake failed
- handshake_failed,
+ - VFALCO
+*/
+#if ! BOOST_BEAST_DOXYGEN
+ unused1 = 2, // failed
+ unused2 = 3, // handshake_failed
+#endif
- /// buffer overflow
+ /** The WebSocket operation caused a dynamic buffer overflow
+ */
buffer_overflow,
- /// partial deflate block
- partial_deflate_block
+ /** The WebSocket stream produced an incomplete deflate block
+ */
+ partial_deflate_block,
+
+ /** The WebSocket message exceeded the locally configured limit
+ */
+ message_too_big,
+
+ //
+ // Handshake failure errors
+ //
+ // These will compare equal to condition::handshake_failed
+ //
+
+ /** The WebSocket handshake was not HTTP/1.1
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_http_version,
+
+ /** The WebSocket handshake method was not GET
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_method,
+
+ /** The WebSocket handshake Host field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_host,
+
+ /** The WebSocket handshake Connection field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_connection,
+
+ /** The WebSocket handshake Connection field is missing the upgrade token
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_connection_upgrade,
+
+ /** The WebSocket handshake Upgrade field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_upgrade,
+
+ /** The WebSocket handshake Upgrade field is missing the websocket token
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_upgrade_websocket,
+
+ /** The WebSocket handshake Sec-WebSocket-Key field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_sec_key,
+
+ /** The WebSocket handshake Sec-WebSocket-Key field is invalid
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_sec_key,
+
+ /** The WebSocket handshake Sec-WebSocket-Version field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_sec_version,
+
+ /** The WebSocket handshake Sec-WebSocket-Version field is invalid
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_sec_version,
+
+ /** The WebSocket handshake Sec-WebSocket-Accept field is missing
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ no_sec_accept,
+
+ /** The WebSocket handshake Sec-WebSocket-Accept field is invalid
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ bad_sec_accept,
+
+ /** The WebSocket handshake was declined by the remote peer
+
+ Error codes with this value will compare equal to @ref condition::handshake_failed
+ */
+ upgrade_declined,
+
+ //
+ // Protocol errors
+ //
+ // These will compare equal to condition::protocol_violation
+ //
+
+ /** The WebSocket frame contained an illegal opcode
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_opcode,
+
+ /** The WebSocket data frame was unexpected
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_data_frame,
+
+ /** The WebSocket continuation frame was unexpected
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_continuation,
+
+ /** The WebSocket frame contained illegal reserved bits
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_reserved_bits,
+
+ /** The WebSocket control frame was fragmented
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_control_fragment,
+
+ /** The WebSocket control frame size was invalid
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_control_size,
+
+ /** The WebSocket frame was unmasked
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_unmasked_frame,
+
+ /** The WebSocket frame was masked
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_masked_frame,
+
+ /** The WebSocket frame size was not canonical
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_size,
+
+ /** The WebSocket frame payload was not valid utf8
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_frame_payload,
+
+ /** The WebSocket close frame reason code was invalid
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_close_code,
+
+ /** The WebSocket close frame payload size was invalid
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_close_size,
+
+ /** The WebSocket close frame payload was not valid utf8
+
+ Error codes with this value will compare equal to @ref condition::protocol_violation
+ */
+ bad_close_payload
};
+/// Error conditions corresponding to sets of error codes.
+enum class condition
+{
+ /** The WebSocket handshake failed
+
+ This condition indicates that the WebSocket handshake failed. If
+ the corresponding HTTP response indicates the keep-alive behavior,
+ then the handshake may be reattempted.
+ */
+ handshake_failed = 1,
+
+ /** A WebSocket protocol violation occurred
+
+ This condition indicates that the remote peer on the WebSocket
+ connection sent data which violated the protocol.
+ */
+ protocol_violation
+ };
+
} // websocket
} // beast
} // boost
diff --git a/boost/beast/websocket/impl/accept.ipp b/boost/beast/websocket/impl/accept.ipp
index e52a74efa5..9daf7b311b 100644
--- a/boost/beast/websocket/impl/accept.ipp
+++ b/boost/beast/websocket/impl/accept.ipp
@@ -23,6 +23,7 @@
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
@@ -34,22 +35,26 @@ namespace beast {
namespace websocket {
// Respond to an upgrade HTTP request
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
-class stream<NextLayer>::response_op
+class stream<NextLayer, deflateSupported>::response_op
: public boost::asio::coroutine
{
struct data
{
- stream<NextLayer>& ws;
+ stream<NextLayer, deflateSupported>& ws;
+ error_code result;
response_type res;
template<class Body, class Allocator, class Decorator>
- data(Handler&, stream<NextLayer>& ws_, http::request<
- Body, http::basic_fields<Allocator>> const& req,
- Decorator const& decorator)
+ data(
+ Handler const&,
+ stream<NextLayer, deflateSupported>& ws_,
+ http::request<Body,
+ http::basic_fields<Allocator>> const& req,
+ Decorator const& decorator)
: ws(ws_)
- , res(ws_.build_response(req, decorator))
+ , res(ws_.build_response(req, decorator, result))
{
}
};
@@ -58,11 +63,11 @@ class stream<NextLayer>::response_op
public:
response_op(response_op&&) = default;
- response_op(response_op const&) = default;
+ response_op(response_op const&) = delete;
template<class DeducedHandler, class... Args>
response_op(DeducedHandler&& h,
- stream<NextLayer>& ws, Args&&... args)
+ stream<NextLayer, deflateSupported>& ws, Args&&... args)
: d_(std::forward<DeducedHandler>(h),
ws, std::forward<Args>(args)...)
{
@@ -74,16 +79,17 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(d_.handler());
+ return (boost::asio::get_associated_allocator)(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<
+ stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
d_.handler(), d_->ws.get_executor());
}
@@ -98,12 +104,20 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, response_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->d_.handler()));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
response_op<Handler>::
operator()(
error_code ec,
@@ -116,12 +130,11 @@ operator()(
BOOST_ASIO_CORO_YIELD
http::async_write(d.ws.next_layer(),
d.res, std::move(*this));
- if(! ec && d.res.result() !=
- http::status::switching_protocols)
- ec = error::handshake_failed;
+ if(! ec)
+ ec = d.result;
if(! ec)
{
- pmd_read(d.ws.pmd_config_, d.res);
+ d.ws.do_pmd_config(d.res, is_deflate_supported{});
d.ws.open(role_type::server);
}
d_.invoke(ec);
@@ -132,18 +145,20 @@ operator()(
// read and respond to an upgrade request
//
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Decorator, class Handler>
-class stream<NextLayer>::accept_op
+class stream<NextLayer, deflateSupported>::accept_op
: public boost::asio::coroutine
{
struct data
{
- stream<NextLayer>& ws;
+ stream<NextLayer, deflateSupported>& ws;
Decorator decorator;
http::request_parser<http::empty_body> p;
- data(Handler&, stream<NextLayer>& ws_,
- Decorator const& decorator_)
+ data(
+ Handler const&,
+ stream<NextLayer, deflateSupported>& ws_,
+ Decorator const& decorator_)
: ws(ws_)
, decorator(decorator_)
{
@@ -154,11 +169,11 @@ class stream<NextLayer>::accept_op
public:
accept_op(accept_op&&) = default;
- accept_op(accept_op const&) = default;
+ accept_op(accept_op const&) = delete;
template<class DeducedHandler, class... Args>
accept_op(DeducedHandler&& h,
- stream<NextLayer>& ws, Args&&... args)
+ stream<NextLayer, deflateSupported>& ws, Args&&... args)
: d_(std::forward<DeducedHandler>(h),
ws, std::forward<Args>(args)...)
{
@@ -170,16 +185,16 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(d_.handler());
+ return (boost::asio::get_associated_allocator)(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
d_.handler(), d_->ws.get_executor());
}
@@ -197,13 +212,21 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, accept_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->d_.handler()));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Decorator, class Handler>
template<class Buffers>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_op<Decorator, Handler>::
run(Buffers const& buffers)
{
@@ -228,10 +251,10 @@ run(Buffers const& buffers)
(*this)(ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Decorator, class Handler>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_op<Decorator, Handler>::
operator()(error_code ec, std::size_t)
{
@@ -280,9 +303,9 @@ operator()(error_code ec, std::size_t)
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept()
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -293,15 +316,15 @@ accept()
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_ex(ResponseDecorator const& decorator)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
@@ -310,9 +333,9 @@ accept_ex(ResponseDecorator const& decorator)
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept(error_code& ec)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -321,26 +344,26 @@ accept(error_code& ec)
do_accept(&default_decorate_res, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ResponseDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_ex(ResponseDecorator const& decorator, error_code& ec)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
reset();
do_accept(decorator, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept(ConstBufferSequence const& buffers)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -354,13 +377,13 @@ accept(ConstBufferSequence const& buffers)
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const &decorator)
@@ -370,7 +393,7 @@ accept_ex(
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
@@ -379,11 +402,11 @@ accept_ex(
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept(
ConstBufferSequence const& buffers, error_code& ec)
{
@@ -412,13 +435,13 @@ accept(
do_accept(&default_decorate_res, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator>
typename std::enable_if<! http::detail::is_header<
ConstBufferSequence>::value>::type
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
@@ -451,10 +474,10 @@ accept_ex(
do_accept(decorator, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept(
http::request<Body,
http::basic_fields<Allocator>> const& req)
@@ -467,12 +490,12 @@ accept(
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
@@ -480,7 +503,7 @@ accept_ex(
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
error_code ec;
@@ -489,10 +512,10 @@ accept_ex(
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept(
http::request<Body,
http::basic_fields<Allocator>> const& req,
@@ -504,12 +527,12 @@ accept(
do_accept(req, &default_decorate_res, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
accept_ex(
http::request<Body,
http::basic_fields<Allocator>> const& req,
@@ -518,7 +541,7 @@ accept_ex(
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
reset();
@@ -527,60 +550,60 @@ accept_ex(
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class AcceptHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
AcceptHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_accept(
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
- boost::asio::async_completion<AcceptHandler,
- void(error_code)> init{handler};
+ "AsyncStream requirements not met");
+ BOOST_BEAST_HANDLER_INIT(
+ AcceptHandler, void(error_code));
reset();
accept_op<
decltype(&default_decorate_res),
BOOST_ASIO_HANDLER_TYPE(
AcceptHandler, void(error_code))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
&default_decorate_res}({});
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class ResponseDecorator,
class AcceptHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
AcceptHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_accept_ex(
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ "AsyncStream requirements not met");
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
- boost::asio::async_completion<AcceptHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ AcceptHandler, void(error_code));
reset();
accept_op<
ResponseDecorator,
BOOST_ASIO_HANDLER_TYPE(
AcceptHandler, void(error_code))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
decorator}({});
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class AcceptHandler>
@@ -588,30 +611,30 @@ typename std::enable_if<
! http::detail::is_header<ConstBufferSequence>::value,
BOOST_ASIO_INITFN_RESULT_TYPE(
AcceptHandler, void(error_code))>::type
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_accept(
ConstBufferSequence const& buffers,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
+ "AsyncStream requirements not met");
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
- boost::asio::async_completion<AcceptHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ AcceptHandler, void(error_code));
reset();
accept_op<
decltype(&default_decorate_res),
BOOST_ASIO_HANDLER_TYPE(
AcceptHandler, void(error_code))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
&default_decorate_res}.run(buffers);
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class ConstBufferSequence,
class ResponseDecorator,
@@ -620,86 +643,86 @@ typename std::enable_if<
! http::detail::is_header<ConstBufferSequence>::value,
BOOST_ASIO_INITFN_RESULT_TYPE(
AcceptHandler, void(error_code))>::type
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_accept_ex(
ConstBufferSequence const& buffers,
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
+ "AsyncStream requirements not met");
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
- boost::asio::async_completion<AcceptHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ AcceptHandler, void(error_code));
reset();
accept_op<
ResponseDecorator,
BOOST_ASIO_HANDLER_TYPE(
AcceptHandler, void(error_code))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
decorator}.run(buffers);
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class AcceptHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
AcceptHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_accept(
http::request<Body, http::basic_fields<Allocator>> const& req,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
- boost::asio::async_completion<AcceptHandler,
- void(error_code)> init{handler};
+ "AsyncStream requirements not met");
+ BOOST_BEAST_HANDLER_INIT(
+ AcceptHandler, void(error_code));
reset();
using boost::asio::asio_handler_is_continuation;
response_op<
BOOST_ASIO_HANDLER_TYPE(
AcceptHandler, void(error_code))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
req,
&default_decorate_res}();
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class Body, class Allocator,
class ResponseDecorator,
class AcceptHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
AcceptHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_accept_ex(
http::request<Body, http::basic_fields<Allocator>> const& req,
ResponseDecorator const& decorator,
AcceptHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
- static_assert(detail::is_ResponseDecorator<
+ "AsyncStream requirements not met");
+ static_assert(detail::is_response_decorator<
ResponseDecorator>::value,
"ResponseDecorator requirements not met");
- boost::asio::async_completion<AcceptHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ AcceptHandler, void(error_code));
reset();
using boost::asio::asio_handler_is_continuation;
response_op<
BOOST_ASIO_HANDLER_TYPE(
AcceptHandler, void(error_code))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
req,
decorator}();
@@ -708,10 +731,10 @@ async_accept_ex(
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Decorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
do_accept(
Decorator const& decorator,
error_code& ec)
@@ -725,28 +748,30 @@ do_accept(
do_accept(p.get(), decorator, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator,
class Decorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
do_accept(
- http::request<Body,http::basic_fields<Allocator>> const& req,
+ http::request<Body,
+ http::basic_fields<Allocator>> const& req,
Decorator const& decorator,
error_code& ec)
{
- auto const res = build_response(req, decorator);
+ error_code result;
+ auto const res = build_response(req, decorator, result);
http::write(stream_, res, ec);
if(ec)
return;
- if(res.result() != http::status::switching_protocols)
+ ec = result;
+ if(ec)
{
- ec = error::handshake_failed;
// VFALCO TODO Respect keep alive setting, perform
// teardown if Connection: close.
return;
}
- pmd_read(pmd_config_, res);
+ do_pmd_config(res, is_deflate_supported{});
open(role_type::server);
}
diff --git a/boost/beast/websocket/impl/close.ipp b/boost/beast/websocket/impl/close.ipp
index 0349dd1409..7b0e1ff648 100644
--- a/boost/beast/websocket/impl/close.ipp
+++ b/boost/beast/websocket/impl/close.ipp
@@ -19,6 +19,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
@@ -34,25 +35,23 @@ namespace websocket {
frame. Finally it invokes the teardown operation to shut down the
underlying connection.
*/
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
-class stream<NextLayer>::close_op
+class stream<NextLayer, deflateSupported>::close_op
: public boost::asio::coroutine
{
struct state
{
- stream<NextLayer>& ws;
+ stream<NextLayer, deflateSupported>& ws;
detail::frame_buffer fb;
error_code ev;
- token tok;
bool cont = false;
state(
- Handler&,
- stream<NextLayer>& ws_,
+ Handler const&,
+ stream<NextLayer, deflateSupported>& ws_,
close_reason const& cr)
: ws(ws_)
- , tok(ws.tok_.unique())
{
// Serialize the close frame
ws.template write_close<
@@ -63,13 +62,15 @@ class stream<NextLayer>::close_op
handler_ptr<state, Handler> d_;
public:
+ static constexpr int id = 4; // for soft_mutex
+
close_op(close_op&&) = default;
- close_op(close_op const&) = default;
+ close_op(close_op const&) = delete;
template<class DeducedHandler>
close_op(
DeducedHandler&& h,
- stream<NextLayer>& ws,
+ stream<NextLayer, deflateSupported>& ws,
close_reason const& cr)
: d_(std::forward<DeducedHandler>(h), ws, cr)
{
@@ -81,16 +82,16 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(d_.handler());
+ return (boost::asio::get_associated_allocator)(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
d_.handler(), d_->ws.get_executor());
}
@@ -107,12 +108,21 @@ public:
return op->d_->cont || asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, close_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f,
+ std::addressof(op->d_.handler()));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
close_op<Handler>::
operator()(
error_code ec,
@@ -121,16 +131,12 @@ operator()(
{
using beast::detail::clamp;
auto& d = *d_;
- close_code code{};
d.cont = cont;
BOOST_ASIO_CORO_REENTER(*this)
{
// Maybe suspend
- if(! d.ws.wr_block_)
+ if(d.ws.wr_block_.try_lock(this))
{
- // Acquire the write block
- d.ws.wr_block_ = d.tok;
-
// Make sure the stream is open
if(! d.ws.check_open(ec))
goto upcall;
@@ -138,19 +144,17 @@ operator()(
else
{
// Suspend
- BOOST_ASSERT(d.ws.wr_block_ != d.tok);
BOOST_ASIO_CORO_YIELD
d.ws.paused_close_.emplace(std::move(*this));
// Acquire the write block
- BOOST_ASSERT(! d.ws.wr_block_);
- d.ws.wr_block_ = d.tok;
+ d.ws.wr_block_.lock(this);
// Resume
BOOST_ASIO_CORO_YIELD
boost::asio::post(
d.ws.get_executor(), std::move(*this));
- BOOST_ASSERT(d.ws.wr_block_ == d.tok);
+ BOOST_ASSERT(d.ws.wr_block_.is_locked(this));
// Make sure the stream is open
if(! d.ws.check_open(ec))
@@ -181,27 +185,20 @@ operator()(
}
// Maybe suspend
- if(! d.ws.rd_block_)
- {
- // Acquire the read block
- d.ws.rd_block_ = d.tok;
- }
- else
+ if(! d.ws.rd_block_.try_lock(this))
{
// Suspend
- BOOST_ASSERT(d.ws.rd_block_ != d.tok);
BOOST_ASIO_CORO_YIELD
d.ws.paused_r_close_.emplace(std::move(*this));
// Acquire the read block
- BOOST_ASSERT(! d.ws.rd_block_);
- d.ws.rd_block_ = d.tok;
+ d.ws.rd_block_.lock(this);
// Resume
BOOST_ASIO_CORO_YIELD
boost::asio::post(
d.ws.get_executor(), std::move(*this));
- BOOST_ASSERT(d.ws.rd_block_ == d.tok);
+ BOOST_ASSERT(d.ws.rd_block_.is_locked(this));
// Make sure the stream is open
BOOST_ASSERT(d.ws.status_ != status::open);
@@ -219,13 +216,10 @@ operator()(
{
// Read frame header
while(! d.ws.parse_fh(
- d.ws.rd_fh_, d.ws.rd_buf_, code))
+ d.ws.rd_fh_, d.ws.rd_buf_, d.ev))
{
- if(code != close_code::none)
- {
- d.ev = error::failed;
+ if(d.ev)
goto teardown;
- }
BOOST_ASIO_CORO_YIELD
d.ws.stream_.async_read_some(
d.ws.rd_buf_.prepare(read_size(d.ws.rd_buf_,
@@ -244,16 +238,12 @@ operator()(
d.ws.rd_close_ = true;
auto const mb = buffers_prefix(
clamp(d.ws.rd_fh_.len),
- d.ws.rd_buf_.data());
+ d.ws.rd_buf_.mutable_data());
if(d.ws.rd_fh_.len > 0 && d.ws.rd_fh_.mask)
detail::mask_inplace(mb, d.ws.rd_key_);
- detail::read_close(d.ws.cr_, mb, code);
- if(code != close_code::none)
- {
- // Protocol error
- d.ev = error::failed;
+ detail::read_close(d.ws.cr_, mb, d.ev);
+ if(d.ev)
goto teardown;
- }
d.ws.rd_buf_.consume(clamp(d.ws.rd_fh_.len));
goto teardown;
}
@@ -283,12 +273,12 @@ operator()(
teardown:
// Teardown
- BOOST_ASSERT(d.ws.wr_block_ == d.tok);
+ BOOST_ASSERT(d.ws.wr_block_.is_locked(this));
using beast::websocket::async_teardown;
BOOST_ASIO_CORO_YIELD
async_teardown(d.ws.role_,
d.ws.stream_, std::move(*this));
- BOOST_ASSERT(d.ws.wr_block_ == d.tok);
+ BOOST_ASSERT(d.ws.wr_block_.is_locked(this));
if(ec == boost::asio::error::eof)
{
// Rationale:
@@ -304,13 +294,10 @@ operator()(
d.ws.close();
upcall:
- BOOST_ASSERT(d.ws.wr_block_ == d.tok);
- d.ws.wr_block_.reset();
- if(d.ws.rd_block_ == d.tok)
- {
- d.ws.rd_block_.reset();
+ BOOST_ASSERT(d.ws.wr_block_.is_locked(this));
+ d.ws.wr_block_.unlock(this);
+ if(d.ws.rd_block_.try_unlock(this))
d.ws.paused_r_rd_.maybe_invoke();
- }
d.ws.paused_rd_.maybe_invoke() ||
d.ws.paused_ping_.maybe_invoke() ||
d.ws.paused_wr_.maybe_invoke();
@@ -327,9 +314,9 @@ operator()(
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
close(close_reason const& cr)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -340,9 +327,9 @@ close(close_reason const& cr)
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
close(close_reason const& cr, error_code& ec)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -364,18 +351,18 @@ close(close_reason const& cr, error_code& ec)
if(! check_ok(ec))
return;
status_ = status::closing;
+ error_code result;
// Drain the connection
- close_code code{};
if(rd_remain_ > 0)
goto read_payload;
for(;;)
{
// Read frame header
- while(! parse_fh(rd_fh_, rd_buf_, code))
+ while(! parse_fh(rd_fh_, rd_buf_, result))
{
- if(code != close_code::none)
- return do_fail(close_code::none,
- error::failed, ec);
+ if(result)
+ return do_fail(
+ close_code::none, result, ec);
auto const bytes_transferred =
stream_.read_some(
rd_buf_.prepare(read_size(rd_buf_,
@@ -393,15 +380,15 @@ close(close_reason const& cr, error_code& ec)
rd_close_ = true;
auto const mb = buffers_prefix(
clamp(rd_fh_.len),
- rd_buf_.data());
+ rd_buf_.mutable_data());
if(rd_fh_.len > 0 && rd_fh_.mask)
detail::mask_inplace(mb, rd_key_);
- detail::read_close(cr_, mb, code);
- if(code != close_code::none)
+ detail::read_close(cr_, mb, result);
+ if(result)
{
- // Protocol error
- return do_fail(close_code::none,
- error::failed, ec);
+ // Protocol violation
+ return do_fail(
+ close_code::none, result, ec);
}
rd_buf_.consume(clamp(rd_fh_.len));
break;
@@ -434,20 +421,20 @@ close(close_reason const& cr, error_code& ec)
ec.assign(0, ec.category());
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class CloseHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
CloseHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_close(close_reason const& cr, CloseHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
- boost::asio::async_completion<CloseHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ CloseHandler, void(error_code));
close_op<BOOST_ASIO_HANDLER_TYPE(
CloseHandler, void(error_code))>{
- init.completion_handler, *this, cr}(
+ std::move(init.completion_handler), *this, cr}(
{}, 0, false);
return init.result.get();
}
diff --git a/boost/beast/websocket/impl/error.ipp b/boost/beast/websocket/impl/error.ipp
index ed18829cfe..56a20e2551 100644
--- a/boost/beast/websocket/impl/error.ipp
+++ b/boost/beast/websocket/impl/error.ipp
@@ -11,71 +11,128 @@
#define BOOST_BEAST_WEBSOCKET_IMPL_ERROR_IPP
namespace boost {
-
-namespace system {
-template<>
-struct is_error_code_enum<beast::websocket::error>
-{
- static bool const value = true;
-};
-} // system
-
namespace beast {
namespace websocket {
namespace detail {
-class websocket_error_category : public error_category
+inline
+const char*
+error_codes::
+name() const noexcept
{
-public:
- const char*
- name() const noexcept override
- {
- return "boost.beast.websocket";
- }
+ return "boost.beast.websocket";
+}
- std::string
- message(int ev) const override
+inline
+std::string
+error_codes::
+message(int ev) const
+{
+ switch(static_cast<error>(ev))
{
- switch(static_cast<error>(ev))
- {
- default:
- case error::failed: return "WebSocket connection failed due to a protocol violation";
- case error::closed: return "WebSocket connection closed normally";
- case error::handshake_failed: return "WebSocket upgrade handshake failed";
- case error::buffer_overflow: return "WebSocket dynamic buffer overflow";
- case error::partial_deflate_block: return "WebSocket partial deflate block";
- }
- }
+ default:
+ case error::closed: return "The WebSocket stream was gracefully closed at both endpoints";
+ case error::buffer_overflow: return "The WebSocket operation caused a dynamic buffer overflow";
+ case error::partial_deflate_block: return "The WebSocket stream produced an incomplete deflate block";
+ case error::message_too_big: return "The WebSocket message exceeded the locally configured limit";
- error_condition
- default_error_condition(int ev) const noexcept override
- {
- return error_condition(ev, *this);
- }
+ case error::bad_http_version: return "The WebSocket handshake was not HTTP/1.1";
+ case error::bad_method: return "The WebSocket handshake method was not GET";
+ case error::no_host: return "The WebSocket handshake Host field is missing";
+ case error::no_connection: return "The WebSocket handshake Connection field is missing";
+ case error::no_connection_upgrade: return "The WebSocket handshake Connection field is missing the upgrade token";
+ case error::no_upgrade: return "The WebSocket handshake Upgrade field is missing";
+ case error::no_upgrade_websocket: return "The WebSocket handshake Upgrade field is missing the websocket token";
+ case error::no_sec_key: return "The WebSocket handshake Sec-WebSocket-Key field is missing";
+ case error::bad_sec_key: return "The WebSocket handshake Sec-WebSocket-Key field is invalid";
+ case error::no_sec_version: return "The WebSocket handshake Sec-WebSocket-Version field is missing";
+ case error::bad_sec_version: return "The WebSocket handshake Sec-WebSocket-Version field is invalid";
+ case error::no_sec_accept: return "The WebSocket handshake Sec-WebSocket-Accept field is missing";
+ case error::bad_sec_accept: return "The WebSocket handshake Sec-WebSocket-Accept field is invalid";
+ case error::upgrade_declined: return "The WebSocket handshake was declined by the remote peer";
- bool
- equivalent(int ev,
- error_condition const& condition
- ) const noexcept override
- {
- return condition.value() == ev &&
- &condition.category() == this;
+ case error::bad_opcode: return "The WebSocket frame contained an illegal opcode";
+ case error::bad_data_frame: return "The WebSocket data frame was unexpected";
+ case error::bad_continuation: return "The WebSocket continuation frame was unexpected";
+ case error::bad_reserved_bits: return "The WebSocket frame contained illegal reserved bits";
+ case error::bad_control_fragment: return "The WebSocket control frame was fragmented";
+ case error::bad_control_size: return "The WebSocket control frame size was invalid";
+ case error::bad_unmasked_frame: return "The WebSocket frame was unmasked";
+ case error::bad_masked_frame: return "The WebSocket frame was masked";
+ case error::bad_size: return "The WebSocket frame size was not canonical";
+ case error::bad_frame_payload: return "The WebSocket frame payload was not valid utf8";
+ case error::bad_close_code: return "The WebSocket close frame reason code was invalid";
+ case error::bad_close_size: return "The WebSocket close frame payload size was invalid";
+ case error::bad_close_payload: return "The WebSocket close frame payload was not valid utf8";
}
+}
- bool
- equivalent(error_code const& error, int ev) const noexcept override
+inline
+error_condition
+error_codes::
+default_error_condition(int ev) const noexcept
+{
+ switch(static_cast<error>(ev))
{
- return error.value() == ev &&
- &error.category() == this;
+ default:
+ case error::closed:
+ case error::buffer_overflow:
+ case error::partial_deflate_block:
+ case error::message_too_big:
+ return {ev, *this};
+
+ case error::bad_http_version:
+ case error::bad_method:
+ case error::no_host:
+ case error::no_connection:
+ case error::no_connection_upgrade:
+ case error::no_upgrade:
+ case error::no_upgrade_websocket:
+ case error::no_sec_key:
+ case error::bad_sec_key:
+ case error::no_sec_version:
+ case error::bad_sec_version:
+ case error::no_sec_accept:
+ case error::bad_sec_accept:
+ case error::upgrade_declined:
+ return condition::handshake_failed;
+
+ case error::bad_opcode:
+ case error::bad_data_frame:
+ case error::bad_continuation:
+ case error::bad_reserved_bits:
+ case error::bad_control_fragment:
+ case error::bad_control_size:
+ case error::bad_unmasked_frame:
+ case error::bad_masked_frame:
+ case error::bad_size:
+ case error::bad_frame_payload:
+ case error::bad_close_code:
+ case error::bad_close_size:
+ case error::bad_close_payload:
+ return condition::protocol_violation;
}
-};
+}
+
+inline
+const char*
+error_conditions::
+name() const noexcept
+{
+ return "boost.beast.websocket";
+}
inline
-error_category const&
-get_error_category()
+std::string
+error_conditions::
+message(int cv) const
{
- static detail::websocket_error_category const cat{};
- return cat;
+ switch(static_cast<condition>(cv))
+ {
+ default:
+ case condition::handshake_failed: return "The WebSocket handshake failed";
+ case condition::protocol_violation: return "A WebSocket protocol violation occurred";
+ }
}
} // detail
@@ -84,9 +141,18 @@ inline
error_code
make_error_code(error e)
{
- return error_code(
- static_cast<std::underlying_type<error>::type>(e),
- detail::get_error_category());
+ static detail::error_codes const cat{};
+ return error_code{static_cast<
+ std::underlying_type<error>::type>(e), cat};
+}
+
+inline
+error_condition
+make_error_condition(condition c)
+{
+ static detail::error_conditions const cat{};
+ return error_condition{static_cast<
+ std::underlying_type<condition>::type>(c), cat};
}
} // websocket
diff --git a/boost/beast/websocket/impl/handshake.ipp b/boost/beast/websocket/impl/handshake.ipp
index cdd8d47342..8e33e1a890 100644
--- a/boost/beast/websocket/impl/handshake.ipp
+++ b/boost/beast/websocket/impl/handshake.ipp
@@ -21,6 +21,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/assert.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
@@ -33,25 +34,27 @@ namespace websocket {
// send the upgrade request and process the response
//
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
-class stream<NextLayer>::handshake_op
+class stream<NextLayer, deflateSupported>::handshake_op
: public boost::asio::coroutine
{
struct data
{
- stream<NextLayer>& ws;
+ stream<NextLayer, deflateSupported>& ws;
response_type* res_p;
detail::sec_ws_key_type key;
http::request<http::empty_body> req;
response_type res;
template<class Decorator>
- data(Handler&, stream<NextLayer>& ws_,
+ data(
+ Handler const&,
+ stream<NextLayer, deflateSupported>& ws_,
response_type* res_p_,
- string_view host,
- string_view target,
- Decorator const& decorator)
+ string_view host,
+ string_view target,
+ Decorator const& decorator)
: ws(ws_)
, res_p(res_p_)
, req(ws.build_request(key,
@@ -65,11 +68,11 @@ class stream<NextLayer>::handshake_op
public:
handshake_op(handshake_op&&) = default;
- handshake_op(handshake_op const&) = default;
+ handshake_op(handshake_op const&) = delete;
template<class DeducedHandler, class... Args>
handshake_op(DeducedHandler&& h,
- stream<NextLayer>& ws, Args&&... args)
+ stream<NextLayer, deflateSupported>& ws, Args&&... args)
: d_(std::forward<DeducedHandler>(h),
ws, std::forward<Args>(args)...)
{
@@ -81,16 +84,16 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(d_.handler());
+ return (boost::asio::get_associated_allocator)(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
d_.handler(), d_->ws.get_executor());
}
@@ -106,19 +109,29 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, handshake_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f,
+ std::addressof(op->d_.handler()));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
void
-stream<NextLayer>::handshake_op<Handler>::
+stream<NextLayer, deflateSupported>::
+handshake_op<Handler>::
operator()(error_code ec, std::size_t)
{
auto& d = *d_;
BOOST_ASIO_CORO_REENTER(*this)
{
// Send HTTP Upgrade
- pmd_read(d.ws.pmd_config_, d.req);
+ d.ws.do_pmd_config(d.req, is_deflate_supported{});
BOOST_ASIO_CORO_YIELD
http::async_write(d.ws.stream_,
d.req, std::move(*this));
@@ -146,31 +159,31 @@ operator()(error_code ec, std::size_t)
}
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_handshake(string_view host,
string_view target,
HandshakeHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
- boost::asio::async_completion<HandshakeHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>{
- init.completion_handler, *this, nullptr, host,
+ std::move(init.completion_handler), *this, nullptr, host,
target, &default_decorate_req}();
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_handshake(response_type& res,
string_view host,
string_view target,
@@ -178,20 +191,20 @@ async_handshake(response_type& res,
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
- boost::asio::async_completion<HandshakeHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>{
- init.completion_handler, *this, &res, host,
+ std::move(init.completion_handler), *this, &res, host,
target, &default_decorate_req}();
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator,
@@ -199,23 +212,23 @@ async_handshake_ex(string_view host,
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
- static_assert(detail::is_RequestDecorator<
+ static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
- boost::asio::async_completion<HandshakeHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>{
- init.completion_handler, *this, nullptr, host,
+ std::move(init.completion_handler), *this, nullptr, host,
target, decorator}();
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class RequestDecorator, class HandshakeHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
HandshakeHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_handshake_ex(response_type& res,
string_view host,
string_view target,
@@ -224,21 +237,21 @@ async_handshake_ex(response_type& res,
{
static_assert(is_async_stream<next_layer_type>::value,
"AsyncStream requirements not met");
- static_assert(detail::is_RequestDecorator<
+ static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
- boost::asio::async_completion<HandshakeHandler,
- void(error_code)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ HandshakeHandler, void(error_code));
handshake_op<BOOST_ASIO_HANDLER_TYPE(
HandshakeHandler, void(error_code))>{
- init.completion_handler, *this, &res, host,
+ std::move(init.completion_handler), *this, &res, host,
target, decorator}();
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake(string_view host,
string_view target)
{
@@ -251,9 +264,9 @@ handshake(string_view host,
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake(response_type& res,
string_view host,
string_view target)
@@ -266,17 +279,17 @@ handshake(response_type& res,
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator)
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_RequestDecorator<
+ static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
@@ -285,10 +298,10 @@ handshake_ex(string_view host,
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake_ex(response_type& res,
string_view host,
string_view target,
@@ -296,7 +309,7 @@ handshake_ex(response_type& res,
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_RequestDecorator<
+ static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
error_code ec;
@@ -305,9 +318,9 @@ handshake_ex(response_type& res,
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake(string_view host,
string_view target, error_code& ec)
{
@@ -317,9 +330,9 @@ handshake(string_view host,
host, target, &default_decorate_req, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake(response_type& res,
string_view host,
string_view target,
@@ -331,10 +344,10 @@ handshake(response_type& res,
host, target, &default_decorate_req, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake_ex(string_view host,
string_view target,
RequestDecorator const& decorator,
@@ -342,17 +355,17 @@ handshake_ex(string_view host,
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_RequestDecorator<
+ static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
do_handshake(nullptr,
host, target, decorator, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
handshake_ex(response_type& res,
string_view host,
string_view target,
@@ -361,7 +374,7 @@ handshake_ex(response_type& res,
{
static_assert(is_sync_stream<next_layer_type>::value,
"SyncStream requirements not met");
- static_assert(detail::is_RequestDecorator<
+ static_assert(detail::is_request_decorator<
RequestDecorator>::value,
"RequestDecorator requirements not met");
do_handshake(&res,
@@ -370,10 +383,10 @@ handshake_ex(response_type& res,
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class RequestDecorator>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
do_handshake(
response_type* res_p,
string_view host,
@@ -387,7 +400,7 @@ do_handshake(
{
auto const req = build_request(
key, host, target, decorator);
- pmd_read(pmd_config_, req);
+ do_pmd_config(req, is_deflate_supported{});
http::write(stream_, req, ec);
}
if(ec)
diff --git a/boost/beast/websocket/impl/ping.ipp b/boost/beast/websocket/impl/ping.ipp
index 79003261de..c7deb9c37c 100644
--- a/boost/beast/websocket/impl/ping.ipp
+++ b/boost/beast/websocket/impl/ping.ipp
@@ -19,6 +19,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/throw_exception.hpp>
#include <memory>
@@ -32,24 +33,22 @@ namespace websocket {
It only sends the frames it does not make attempts to read
any frame data.
*/
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
-class stream<NextLayer>::ping_op
+class stream<NextLayer, deflateSupported>::ping_op
: public boost::asio::coroutine
{
struct state
{
- stream<NextLayer>& ws;
+ stream<NextLayer, deflateSupported>& ws;
detail::frame_buffer fb;
- token tok;
state(
- Handler&,
- stream<NextLayer>& ws_,
+ Handler const&,
+ stream<NextLayer, deflateSupported>& ws_,
detail::opcode op,
ping_data const& payload)
: ws(ws_)
- , tok(ws.tok_.unique())
{
// Serialize the control frame
ws.template write_ping<
@@ -61,13 +60,15 @@ class stream<NextLayer>::ping_op
handler_ptr<state, Handler> d_;
public:
+ static constexpr int id = 3; // for soft_mutex
+
ping_op(ping_op&&) = default;
- ping_op(ping_op const&) = default;
+ ping_op(ping_op const&) = delete;
template<class DeducedHandler>
ping_op(
DeducedHandler&& h,
- stream<NextLayer>& ws,
+ stream<NextLayer, deflateSupported>& ws,
detail::opcode op,
ping_data const& payload)
: d_(std::forward<DeducedHandler>(h),
@@ -81,16 +82,16 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(d_.handler());
+ return (boost::asio::get_associated_allocator)(d_.handler());
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
d_.handler(), d_->ws.get_executor());
}
@@ -105,12 +106,21 @@ public:
return asio_handler_is_continuation(
std::addressof(op->d_.handler()));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, ping_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(
+ f, std::addressof(op->d_.handler()));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Handler>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
ping_op<Handler>::
operator()(error_code ec, std::size_t)
{
@@ -118,11 +128,8 @@ operator()(error_code ec, std::size_t)
BOOST_ASIO_CORO_REENTER(*this)
{
// Maybe suspend
- if(! d.ws.wr_block_)
+ if(d.ws.wr_block_.try_lock(this))
{
- // Acquire the write block
- d.ws.wr_block_ = d.tok;
-
// Make sure the stream is open
if(! d.ws.check_open(ec))
{
@@ -136,19 +143,17 @@ operator()(error_code ec, std::size_t)
else
{
// Suspend
- BOOST_ASSERT(d.ws.wr_block_ != d.tok);
BOOST_ASIO_CORO_YIELD
d.ws.paused_ping_.emplace(std::move(*this));
// Acquire the write block
- BOOST_ASSERT(! d.ws.wr_block_);
- d.ws.wr_block_ = d.tok;
+ d.ws.wr_block_.lock(this);
// Resume
BOOST_ASIO_CORO_YIELD
boost::asio::post(
d.ws.get_executor(), std::move(*this));
- BOOST_ASSERT(d.ws.wr_block_ == d.tok);
+ BOOST_ASSERT(d.ws.wr_block_.is_locked(this));
// Make sure the stream is open
if(! d.ws.check_open(ec))
@@ -163,8 +168,7 @@ operator()(error_code ec, std::size_t)
goto upcall;
upcall:
- BOOST_ASSERT(d.ws.wr_block_ == d.tok);
- d.ws.wr_block_.reset();
+ d.ws.wr_block_.unlock(this);
d.ws.paused_close_.maybe_invoke() ||
d.ws.paused_rd_.maybe_invoke() ||
d.ws.paused_wr_.maybe_invoke();
@@ -174,9 +178,9 @@ operator()(error_code ec, std::size_t)
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
ping(ping_data const& payload)
{
error_code ec;
@@ -185,9 +189,9 @@ ping(ping_data const& payload)
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
ping(ping_data const& payload, error_code& ec)
{
// Make sure the stream is open
@@ -201,9 +205,9 @@ ping(ping_data const& payload, error_code& ec)
return;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
pong(ping_data const& payload)
{
error_code ec;
@@ -212,9 +216,9 @@ pong(ping_data const& payload)
BOOST_THROW_EXCEPTION(system_error{ec});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
pong(ping_data const& payload, error_code& ec)
{
// Make sure the stream is open
@@ -228,38 +232,38 @@ pong(ping_data const& payload, error_code& ec)
return;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_ping(ping_data const& payload, WriteHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
- boost::asio::async_completion<WriteHandler,
- void(error_code)> init{handler};
+ "AsyncStream requirements not met");
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code));
ping_op<BOOST_ASIO_HANDLER_TYPE(
WriteHandler, void(error_code))>{
- init.completion_handler, *this,
+ std::move(init.completion_handler), *this,
detail::opcode::ping, payload}();
return init.result.get();
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_pong(ping_data const& payload, WriteHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
- boost::asio::async_completion<WriteHandler,
- void(error_code)> init{handler};
+ "AsyncStream requirements not met");
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code));
ping_op<BOOST_ASIO_HANDLER_TYPE(
WriteHandler, void(error_code))>{
- init.completion_handler, *this,
+ std::move(init.completion_handler), *this,
detail::opcode::pong, payload}();
return init.result.get();
}
diff --git a/boost/beast/websocket/impl/read.ipp b/boost/beast/websocket/impl/read.ipp
index 422cc3766b..1dfbd01e72 100644
--- a/boost/beast/websocket/impl/read.ipp
+++ b/boost/beast/websocket/impl/read.ipp
@@ -22,6 +22,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
@@ -35,42 +36,75 @@ namespace boost {
namespace beast {
namespace websocket {
+namespace detail {
+
+template<>
+inline
+void
+stream_base<true>::
+inflate(
+ zlib::z_params& zs,
+ zlib::Flush flush,
+ error_code& ec)
+{
+ this->pmd_->zi.write(zs, flush, ec);
+}
+
+template<>
+inline
+void
+stream_base<true>::
+do_context_takeover_read(role_type role)
+{
+ if((role == role_type::client &&
+ pmd_config_.server_no_context_takeover) ||
+ (role == role_type::server &&
+ pmd_config_.client_no_context_takeover))
+ {
+ pmd_->zi.reset();
+ }
+}
+
+} // detail
+
+//------------------------------------------------------------------------------
+
/* Read some message frame data.
Also reads and handles control frames.
*/
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class MutableBufferSequence,
class Handler>
-class stream<NextLayer>::read_some_op
+class stream<NextLayer, deflateSupported>::read_some_op
: public boost::asio::coroutine
{
Handler h_;
- stream<NextLayer>& ws_;
+ stream<NextLayer, deflateSupported>& ws_;
MutableBufferSequence bs_;
buffers_suffix<MutableBufferSequence> cb_;
std::size_t bytes_written_ = 0;
- error_code ev_;
- token tok_;
+ error_code result_;
close_code code_;
bool did_read_ = false;
bool cont_ = false;
public:
+ static constexpr int id = 1; // for soft_mutex
+
read_some_op(read_some_op&&) = default;
- read_some_op(read_some_op const&) = default;
+ read_some_op(read_some_op const&) = delete;
template<class DeducedHandler>
read_some_op(
DeducedHandler&& h,
- stream<NextLayer>& ws,
+ stream<NextLayer, deflateSupported>& ws,
MutableBufferSequence const& bs)
: h_(std::forward<DeducedHandler>(h))
, ws_(ws)
, bs_(bs)
, cb_(bs)
- , tok_(ws_.tok_.unique())
, code_(close_code::none)
{
}
@@ -81,16 +115,16 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, ws_.get_executor());
}
@@ -112,12 +146,20 @@ public:
return op->cont_ || asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, read_some_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class MutableBufferSequence, class Handler>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read_some_op<MutableBufferSequence, Handler>::
operator()(
error_code ec,
@@ -127,17 +169,13 @@ operator()(
using beast::detail::clamp;
using boost::asio::buffer;
using boost::asio::buffer_size;
- close_code code{};
cont_ = cont;
BOOST_ASIO_CORO_REENTER(*this)
{
// Maybe suspend
do_maybe_suspend:
- if(! ws_.rd_block_)
+ if(ws_.rd_block_.try_lock(this))
{
- // Acquire the read block
- ws_.rd_block_ = tok_;
-
// Make sure the stream is not closed
if( ws_.status_ == status::closed ||
ws_.status_ == status::failed)
@@ -150,19 +188,17 @@ operator()(
{
do_suspend:
// Suspend
- BOOST_ASSERT(ws_.rd_block_ != tok_);
BOOST_ASIO_CORO_YIELD
- ws_.paused_r_rd_.save(std::move(*this));
+ ws_.paused_r_rd_.emplace(std::move(*this));
// Acquire the read block
- BOOST_ASSERT(! ws_.rd_block_);
- ws_.rd_block_ = tok_;
+ ws_.rd_block_.lock(this);
// Resume
BOOST_ASIO_CORO_YIELD
boost::asio::post(
ws_.get_executor(), std::move(*this));
- BOOST_ASSERT(ws_.rd_block_ == tok_);
+ BOOST_ASSERT(ws_.rd_block_.is_locked(this));
// The only way to get read blocked is if
// a `close_op` wrote a close frame
@@ -177,7 +213,7 @@ operator()(
// then finish the read with operation_aborted.
loop:
- BOOST_ASSERT(ws_.rd_block_ == tok_);
+ BOOST_ASSERT(ws_.rd_block_.is_locked(this));
// See if we need to read a frame header. This
// condition is structured to give the decompressor
// a chance to emit the final empty deflate block
@@ -187,45 +223,46 @@ operator()(
{
// Read frame header
while(! ws_.parse_fh(
- ws_.rd_fh_, ws_.rd_buf_, code))
+ ws_.rd_fh_, ws_.rd_buf_, result_))
{
- if(code != close_code::none)
+ if(result_)
{
// _Fail the WebSocket Connection_
- code_ = code;
- ev_ = error::failed;
+ if(result_ == error::message_too_big)
+ code_ = close_code::too_big;
+ else
+ code_ = close_code::protocol_error;
goto close;
}
- BOOST_ASSERT(ws_.rd_block_ == tok_);
+ BOOST_ASSERT(ws_.rd_block_.is_locked(this));
BOOST_ASIO_CORO_YIELD
ws_.stream_.async_read_some(
ws_.rd_buf_.prepare(read_size(
ws_.rd_buf_, ws_.rd_buf_.max_size())),
std::move(*this));
- BOOST_ASSERT(ws_.rd_block_ == tok_);
+ BOOST_ASSERT(ws_.rd_block_.is_locked(this));
if(! ws_.check_ok(ec))
goto upcall;
ws_.rd_buf_.commit(bytes_transferred);
// Allow a close operation
// to acquire the read block
- BOOST_ASSERT(ws_.rd_block_ == tok_);
- ws_.rd_block_.reset();
+ ws_.rd_block_.unlock(this);
if( ws_.paused_r_close_.maybe_invoke())
{
// Suspend
- BOOST_ASSERT(ws_.rd_block_);
+ BOOST_ASSERT(ws_.rd_block_.is_locked());
goto do_suspend;
}
// Acquire read block
- ws_.rd_block_ = tok_;
+ ws_.rd_block_.lock(this);
}
// Immediately apply the mask to the portion
// of the buffer holding payload data.
if(ws_.rd_fh_.len > 0 && ws_.rd_fh_.mask)
detail::mask_inplace(buffers_prefix(
clamp(ws_.rd_fh_.len),
- ws_.rd_buf_.data()),
+ ws_.rd_buf_.mutable_data()),
ws_.rd_key_);
if(detail::is_control(ws_.rd_fh_.op))
{
@@ -236,6 +273,17 @@ operator()(
// Handle ping frame
if(ws_.rd_fh_.op == detail::opcode::ping)
{
+ if(ws_.ctrl_cb_)
+ {
+ if(! cont_)
+ {
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(
+ ws_.get_executor(),
+ std::move(*this));
+ BOOST_ASSERT(cont_);
+ }
+ }
{
auto const b = buffers_prefix(
clamp(ws_.rd_fh_.len),
@@ -249,43 +297,34 @@ operator()(
if(ws_.status_ == status::closing)
goto loop;
if(ws_.ctrl_cb_)
- ws_.ctrl_cb_(frame_type::ping, payload);
+ ws_.ctrl_cb_(
+ frame_type::ping, payload);
ws_.rd_fb_.reset();
ws_.template write_ping<
flat_static_buffer_base>(ws_.rd_fb_,
detail::opcode::pong, payload);
}
- //BOOST_ASSERT(! ws_.paused_r_close_);
-
// Allow a close operation
// to acquire the read block
- BOOST_ASSERT(ws_.rd_block_ == tok_);
- ws_.rd_block_.reset();
+ ws_.rd_block_.unlock(this);
ws_.paused_r_close_.maybe_invoke();
// Maybe suspend
- if(! ws_.wr_block_)
- {
- // Acquire the write block
- ws_.wr_block_ = tok_;
- }
- else
+ if(! ws_.wr_block_.try_lock(this))
{
// Suspend
- BOOST_ASSERT(ws_.wr_block_ != tok_);
BOOST_ASIO_CORO_YIELD
- ws_.paused_rd_.save(std::move(*this));
+ ws_.paused_rd_.emplace(std::move(*this));
// Acquire the write block
- BOOST_ASSERT(! ws_.wr_block_);
- ws_.wr_block_ = tok_;
+ ws_.wr_block_.lock(this);
// Resume
BOOST_ASIO_CORO_YIELD
boost::asio::post(
ws_.get_executor(), std::move(*this));
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
// Make sure the stream is open
if(! ws_.check_open(ec))
@@ -293,14 +332,14 @@ operator()(
}
// Send pong
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
BOOST_ASIO_CORO_YIELD
boost::asio::async_write(ws_.stream_,
ws_.rd_fb_.data(), std::move(*this));
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
if(! ws_.check_ok(ec))
goto upcall;
- ws_.wr_block_.reset();
+ ws_.wr_block_.unlock(this);
ws_.paused_close_.maybe_invoke() ||
ws_.paused_ping_.maybe_invoke() ||
ws_.paused_wr_.maybe_invoke();
@@ -309,11 +348,22 @@ operator()(
// Handle pong frame
if(ws_.rd_fh_.op == detail::opcode::pong)
{
+ // Ignore pong when closing
+ if(! ws_.wr_close_ && ws_.ctrl_cb_)
+ {
+ if(! cont_)
+ {
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(
+ ws_.get_executor(),
+ std::move(*this));
+ BOOST_ASSERT(cont_);
+ }
+ }
auto const cb = buffers_prefix(clamp(
ws_.rd_fh_.len), ws_.rd_buf_.data());
auto const len = buffer_size(cb);
BOOST_ASSERT(len == ws_.rd_fh_.len);
- code = close_code::none;
ping_data payload;
detail::read_ping(payload, cb);
ws_.rd_buf_.consume(len);
@@ -325,6 +375,17 @@ operator()(
// Handle close frame
BOOST_ASSERT(ws_.rd_fh_.op == detail::opcode::close);
{
+ if(ws_.ctrl_cb_)
+ {
+ if(! cont_)
+ {
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(
+ ws_.get_executor(),
+ std::move(*this));
+ BOOST_ASSERT(cont_);
+ }
+ }
auto const cb = buffers_prefix(clamp(
ws_.rd_fh_.len), ws_.rd_buf_.data());
auto const len = buffer_size(cb);
@@ -332,12 +393,11 @@ operator()(
BOOST_ASSERT(! ws_.rd_close_);
ws_.rd_close_ = true;
close_reason cr;
- detail::read_close(cr, cb, code);
- if(code != close_code::none)
+ detail::read_close(cr, cb, result_);
+ if(result_)
{
// _Fail the WebSocket Connection_
- code_ = code;
- ev_ = error::failed;
+ code_ = close_code::protocol_error;
goto close;
}
ws_.cr_ = cr;
@@ -351,14 +411,14 @@ operator()(
// _Close the WebSocket Connection_
BOOST_ASSERT(ws_.wr_close_);
code_ = close_code::none;
- ev_ = error::closed;
+ result_ = error::closed;
goto close;
}
// _Start the WebSocket Closing Handshake_
code_ = cr.code == close_code::none ?
close_code::normal :
static_cast<close_code>(cr.code);
- ev_ = error::closed;
+ result_ = error::closed;
goto close;
}
}
@@ -369,7 +429,7 @@ operator()(
}
ws_.rd_done_ = false;
}
- if(! ws_.pmd_ || ! ws_.pmd_->rd_set)
+ if(! ws_.rd_deflated())
{
if(ws_.rd_remain_ > 0)
{
@@ -389,7 +449,7 @@ operator()(
ws_.rd_buf_.commit(bytes_transferred);
if(ws_.rd_fh_.mask)
detail::mask_inplace(buffers_prefix(clamp(
- ws_.rd_remain_), ws_.rd_buf_.data()),
+ ws_.rd_remain_), ws_.rd_buf_.mutable_data()),
ws_.rd_key_);
}
if(ws_.rd_buf_.size() > 0)
@@ -409,7 +469,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::bad_payload;
- ev_ = error::failed;
+ result_ = error::bad_frame_payload;
goto close;
}
}
@@ -443,7 +503,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::bad_payload;
- ev_ = error::failed;
+ result_ = error::bad_frame_payload;
goto close;
}
}
@@ -477,7 +537,7 @@ operator()(
if(ws_.rd_fh_.mask)
detail::mask_inplace(
buffers_prefix(clamp(ws_.rd_remain_),
- ws_.rd_buf_.data()), ws_.rd_key_);
+ ws_.rd_buf_.mutable_data()), ws_.rd_key_);
did_read_ = true;
}
zlib::z_params zs;
@@ -511,7 +571,7 @@ operator()(
0x00, 0x00, 0xff, 0xff };
zs.next_in = empty_block;
zs.avail_in = sizeof(empty_block);
- ws_.pmd_->zi.write(zs, zlib::Flush::sync, ec);
+ ws_.inflate(zs, zlib::Flush::sync, ec);
if(! ec)
{
// https://github.com/madler/zlib/issues/280
@@ -520,12 +580,7 @@ operator()(
}
if(! ws_.check_ok(ec))
goto upcall;
- if(
- (ws_.role_ == role_type::client &&
- ws_.pmd_config_.server_no_context_takeover) ||
- (ws_.role_ == role_type::server &&
- ws_.pmd_config_.client_no_context_takeover))
- ws_.pmd_->zi.reset();
+ ws_.do_context_takeover_read(ws_.role_);
ws_.rd_done_ = true;
break;
}
@@ -533,7 +588,7 @@ operator()(
{
break;
}
- ws_.pmd_->zi.write(zs, zlib::Flush::sync, ec);
+ ws_.inflate(zs, zlib::Flush::sync, ec);
if(! ws_.check_ok(ec))
goto upcall;
if(ws_.rd_msg_max_ && beast::detail::sum_exceeds(
@@ -541,7 +596,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::too_big;
- ev_ = error::failed;
+ result_ = error::message_too_big;
goto close;
}
cb_.consume(zs.total_out);
@@ -559,7 +614,7 @@ operator()(
{
// _Fail the WebSocket Connection_
code_ = close_code::bad_payload;
- ev_ = error::failed;
+ result_ = error::bad_frame_payload;
goto close;
}
}
@@ -567,30 +622,25 @@ operator()(
goto upcall;
close:
- if(! ws_.wr_block_)
+ if(ws_.wr_block_.try_lock(this))
{
- // Acquire the write block
- ws_.wr_block_ = tok_;
-
// Make sure the stream is open
BOOST_ASSERT(ws_.status_ == status::open);
}
else
{
// Suspend
- BOOST_ASSERT(ws_.wr_block_ != tok_);
BOOST_ASIO_CORO_YIELD
- ws_.paused_rd_.save(std::move(*this));
+ ws_.paused_rd_.emplace(std::move(*this));
// Acquire the write block
- BOOST_ASSERT(! ws_.wr_block_);
- ws_.wr_block_ = tok_;
+ ws_.wr_block_.lock(this);
// Resume
BOOST_ASIO_CORO_YIELD
boost::asio::post(
ws_.get_executor(), std::move(*this));
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
// Make sure the stream is open
if(! ws_.check_open(ec))
@@ -611,23 +661,23 @@ operator()(
ws_.rd_fb_, code_);
// Send close frame
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
BOOST_ASIO_CORO_YIELD
boost::asio::async_write(
ws_.stream_, ws_.rd_fb_.data(),
std::move(*this));
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
if(! ws_.check_ok(ec))
goto upcall;
}
// Teardown
using beast::websocket::async_teardown;
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
BOOST_ASIO_CORO_YIELD
async_teardown(ws_.role_,
ws_.stream_, std::move(*this));
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
if(ec == boost::asio::error::eof)
{
// Rationale:
@@ -635,7 +685,7 @@ operator()(
ec.assign(0, ec.category());
}
if(! ec)
- ec = ev_;
+ ec = result_;
if(ec && ec != error::closed)
ws_.status_ = status::failed;
else
@@ -643,16 +693,12 @@ operator()(
ws_.close();
upcall:
- if(ws_.rd_block_ == tok_)
- ws_.rd_block_.reset();
+ ws_.rd_block_.try_unlock(this);
ws_.paused_r_close_.maybe_invoke();
- if(ws_.wr_block_ == tok_)
- {
- ws_.wr_block_.reset();
+ if(ws_.wr_block_.try_unlock(this))
ws_.paused_close_.maybe_invoke() ||
ws_.paused_ping_.maybe_invoke() ||
ws_.paused_wr_.maybe_invoke();
- }
if(! cont_)
return boost::asio::post(
ws_.stream_.get_executor(),
@@ -664,15 +710,15 @@ operator()(
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<
class DynamicBuffer,
class Handler>
-class stream<NextLayer>::read_op
+class stream<NextLayer, deflateSupported>::read_op
: public boost::asio::coroutine
{
Handler h_;
- stream<NextLayer>& ws_;
+ stream<NextLayer, deflateSupported>& ws_;
DynamicBuffer& b_;
std::size_t limit_;
std::size_t bytes_written_ = 0;
@@ -683,12 +729,12 @@ public:
boost::asio::associated_allocator_t<Handler>;
read_op(read_op&&) = default;
- read_op(read_op const&) = default;
+ read_op(read_op const&) = delete;
template<class DeducedHandler>
read_op(
DeducedHandler&& h,
- stream<NextLayer>& ws,
+ stream<NextLayer, deflateSupported>& ws,
DynamicBuffer& b,
std::size_t limit,
bool some)
@@ -704,16 +750,16 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, ws_.get_executor());
}
@@ -728,12 +774,20 @@ public:
return asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, read_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer, class Handler>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read_op<DynamicBuffer, Handler>::
operator()(
error_code ec,
@@ -781,10 +835,10 @@ operator()(
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read(DynamicBuffer& buffer)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -799,10 +853,10 @@ read(DynamicBuffer& buffer)
return bytes_written;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read(DynamicBuffer& buffer, error_code& ec)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -821,25 +875,25 @@ read(DynamicBuffer& buffer, error_code& ec)
return bytes_written;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer, class ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_read(DynamicBuffer& buffer, ReadHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
+ "AsyncStream requirements not met");
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
- boost::asio::async_completion<
- ReadHandler, void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
read_op<
DynamicBuffer,
BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
buffer,
0,
@@ -849,10 +903,10 @@ async_read(DynamicBuffer& buffer, ReadHandler&& handler)
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read_some(
DynamicBuffer& buffer,
std::size_t limit)
@@ -870,10 +924,10 @@ read_some(
return bytes_written;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read_some(
DynamicBuffer& buffer,
std::size_t limit,
@@ -906,28 +960,28 @@ read_some(
return bytes_written;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer, class ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_read_some(
DynamicBuffer& buffer,
std::size_t limit,
ReadHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
+ "AsyncStream requirements not met");
static_assert(
boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
"DynamicBuffer requirements not met");
- boost::asio::async_completion<ReadHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
read_op<
DynamicBuffer,
BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler,
+ std::move(init.completion_handler),
*this,
buffer,
limit,
@@ -937,10 +991,10 @@ async_read_some(
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class MutableBufferSequence>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read_some(
MutableBufferSequence const& buffers)
{
@@ -956,10 +1010,10 @@ read_some(
return bytes_written;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class MutableBufferSequence>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read_some(
MutableBufferSequence const& buffers,
error_code& ec)
@@ -986,12 +1040,17 @@ loop:
if(rd_remain_ == 0 && (! rd_fh_.fin || rd_done_))
{
// Read frame header
- while(! parse_fh(rd_fh_, rd_buf_, code))
+ error_code result;
+ while(! parse_fh(rd_fh_, rd_buf_, result))
{
- if(code != close_code::none)
+ if(result)
{
// _Fail the WebSocket Connection_
- do_fail(code, error::failed, ec);
+ if(result == error::message_too_big)
+ code = close_code::too_big;
+ else
+ code = close_code::protocol_error;
+ do_fail(code, result, ec);
return bytes_written;
}
auto const bytes_transferred =
@@ -1007,7 +1066,7 @@ loop:
// of the buffer holding payload data.
if(rd_fh_.len > 0 && rd_fh_.mask)
detail::mask_inplace(buffers_prefix(
- clamp(rd_fh_.len), rd_buf_.data()),
+ clamp(rd_fh_.len), rd_buf_.mutable_data()),
rd_key_);
if(detail::is_control(rd_fh_.op))
{
@@ -1058,11 +1117,12 @@ loop:
BOOST_ASSERT(! rd_close_);
rd_close_ = true;
close_reason cr;
- detail::read_close(cr, b, code);
- if(code != close_code::none)
+ detail::read_close(cr, b, result);
+ if(result)
{
// _Fail the WebSocket Connection_
- do_fail(code, error::failed, ec);
+ do_fail(close_code::protocol_error,
+ result, ec);
return bytes_written;
}
cr_ = cr;
@@ -1090,7 +1150,7 @@ loop:
{
ec.assign(0, ec.category());
}
- if(! pmd_ || ! pmd_->rd_set)
+ if(! this->rd_deflated())
{
if(rd_remain_ > 0)
{
@@ -1108,7 +1168,7 @@ loop:
if(rd_fh_.mask)
detail::mask_inplace(
buffers_prefix(clamp(rd_remain_),
- rd_buf_.data()), rd_key_);
+ rd_buf_.mutable_data()), rd_key_);
}
if(rd_buf_.size() > 0)
{
@@ -1127,10 +1187,8 @@ loop:
! rd_utf8_.finish()))
{
// _Fail the WebSocket Connection_
- do_fail(
- close_code::bad_payload,
- error::failed,
- ec);
+ do_fail(close_code::bad_payload,
+ error::bad_frame_payload, ec);
return bytes_written;
}
}
@@ -1164,7 +1222,7 @@ loop:
{
// _Fail the WebSocket Connection_
do_fail(close_code::bad_payload,
- error::failed, ec);
+ error::bad_frame_payload, ec);
return bytes_written;
}
}
@@ -1217,7 +1275,7 @@ loop:
if(rd_fh_.mask)
detail::mask_inplace(
buffers_prefix(clamp(rd_remain_),
- rd_buf_.data()), rd_key_);
+ rd_buf_.mutable_data()), rd_key_);
auto const in = buffers_prefix(
clamp(rd_remain_), buffers_front(
rd_buf_.data()));
@@ -1238,7 +1296,7 @@ loop:
0x00, 0x00, 0xff, 0xff };
zs.next_in = empty_block;
zs.avail_in = sizeof(empty_block);
- pmd_->zi.write(zs, zlib::Flush::sync, ec);
+ this->inflate(zs, zlib::Flush::sync, ec);
if(! ec)
{
// https://github.com/madler/zlib/issues/280
@@ -1247,12 +1305,7 @@ loop:
}
if(! check_ok(ec))
return bytes_written;
- if(
- (role_ == role_type::client &&
- pmd_config_.server_no_context_takeover) ||
- (role_ == role_type::server &&
- pmd_config_.client_no_context_takeover))
- pmd_->zi.reset();
+ this->do_context_takeover_read(role_);
rd_done_ = true;
break;
}
@@ -1260,14 +1313,14 @@ loop:
{
break;
}
- pmd_->zi.write(zs, zlib::Flush::sync, ec);
+ this->inflate(zs, zlib::Flush::sync, ec);
if(! check_ok(ec))
return bytes_written;
if(rd_msg_max_ && beast::detail::sum_exceeds(
rd_size_, zs.total_out, rd_msg_max_))
{
do_fail(close_code::too_big,
- error::failed, ec);
+ error::message_too_big, ec);
return bytes_written;
}
cb.consume(zs.total_out);
@@ -1285,7 +1338,7 @@ loop:
{
// _Fail the WebSocket Connection_
do_fail(close_code::bad_payload,
- error::failed, ec);
+ error::bad_frame_payload, ec);
return bytes_written;
}
}
@@ -1293,25 +1346,25 @@ loop:
return bytes_written;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class MutableBufferSequence, class ReadHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(error_code, std::size_t))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_read_some(
MutableBufferSequence const& buffers,
ReadHandler&& handler)
{
static_assert(is_async_stream<next_layer_type>::value,
- "AsyncStream requirements requirements not met");
+ "AsyncStream requirements not met");
static_assert(boost::asio::is_mutable_buffer_sequence<
MutableBufferSequence>::value,
"MutableBufferSequence requirements not met");
- boost::asio::async_completion<ReadHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ ReadHandler, void(error_code, std::size_t));
read_some_op<MutableBufferSequence, BOOST_ASIO_HANDLER_TYPE(
ReadHandler, void(error_code, std::size_t))>{
- init.completion_handler,*this, buffers}(
+ std::move(init.completion_handler), *this, buffers}(
{}, 0, false);
return init.result.get();
}
@@ -1320,4 +1373,4 @@ async_read_some(
} // beast
} // boost
-#endif \ No newline at end of file
+#endif
diff --git a/boost/beast/websocket/impl/rfc6455.ipp b/boost/beast/websocket/impl/rfc6455.ipp
index d688b63d1b..07fdc30686 100644
--- a/boost/beast/websocket/impl/rfc6455.ipp
+++ b/boost/beast/websocket/impl/rfc6455.ipp
@@ -26,9 +26,9 @@ is_upgrade(http::header<true,
return false;
if(req.method() != http::verb::get)
return false;
- if(! http::token_list{req["Connection"]}.exists("upgrade"))
+ if(! http::token_list{req[http::field::connection]}.exists("upgrade"))
return false;
- if(! http::token_list{req["Upgrade"]}.exists("websocket"))
+ if(! http::token_list{req[http::field::upgrade]}.exists("websocket"))
return false;
return true;
}
diff --git a/boost/beast/websocket/impl/stream.ipp b/boost/beast/websocket/impl/stream.ipp
index f8e4a5fc01..cf747c230d 100644
--- a/boost/beast/websocket/impl/stream.ipp
+++ b/boost/beast/websocket/impl/stream.ipp
@@ -40,55 +40,20 @@ namespace boost {
namespace beast {
namespace websocket {
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class... Args>
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
stream(Args&&... args)
: stream_(std::forward<Args>(args)...)
- , tok_(1)
{
BOOST_ASSERT(rd_buf_.max_size() >=
max_control_frame_size);
}
-template<class NextLayer>
-std::size_t
-stream<NextLayer>::
-read_size_hint(
- std::size_t initial_size) const
-{
- using beast::detail::clamp;
- std::size_t result;
- BOOST_ASSERT(initial_size > 0);
- if(! pmd_ || (! rd_done_ && ! pmd_->rd_set))
- {
- // current message is uncompressed
-
- if(rd_done_)
- {
- // first message frame
- result = initial_size;
- goto done;
- }
- else if(rd_fh_.fin)
- {
- // last message frame
- BOOST_ASSERT(rd_remain_ > 0);
- result = clamp(rd_remain_);
- goto done;
- }
- }
- result = (std::max)(
- initial_size, clamp(rd_remain_));
-done:
- BOOST_ASSERT(result != 0);
- return result;
-}
-
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer, class>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
read_size_hint(DynamicBuffer& buffer) const
{
static_assert(
@@ -102,10 +67,12 @@ read_size_hint(DynamicBuffer& buffer) const
return read_size_hint(initial_size);
}
-template<class NextLayer>
+//------------------------------------------------------------------------------
+
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
-set_option(permessage_deflate const& o)
+stream<NextLayer, deflateSupported>::
+set_option(permessage_deflate const& o, std::true_type)
{
if( o.server_max_window_bits > 15 ||
o.server_max_window_bits < 9)
@@ -123,14 +90,27 @@ set_option(permessage_deflate const& o)
o.memLevel > 9)
BOOST_THROW_EXCEPTION(std::invalid_argument{
"invalid memLevel"});
- pmd_opts_ = o;
+ this->pmd_opts_ = o;
}
-//------------------------------------------------------------------------------
+template<class NextLayer, bool deflateSupported>
+void
+stream<NextLayer, deflateSupported>::
+set_option(permessage_deflate const& o, std::false_type)
+{
+ if(o.client_enable || o.server_enable)
+ {
+ // Can't enable permessage-deflate
+ // when deflateSupported == false.
+ //
+ BOOST_THROW_EXCEPTION(std::invalid_argument{
+ "deflateSupported == false"});
+ }
+}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
open(role_type role)
{
// VFALCO TODO analyze and remove dupe code in reset()
@@ -144,6 +124,9 @@ open(role_type role)
rd_fh_.fin = false;
rd_close_ = false;
wr_close_ = false;
+ // These should not be necessary, because all completion
+ // handlers must be allowed to execute otherwise the
+ // stream exhibits undefined behavior.
wr_block_.reset();
rd_block_.reset();
cr_.code = close_code::none;
@@ -151,47 +134,59 @@ open(role_type role)
wr_cont_ = false;
wr_buf_size_ = 0;
- if(((role_ == role_type::client && pmd_opts_.client_enable) ||
- (role_ == role_type::server && pmd_opts_.server_enable)) &&
- pmd_config_.accept)
+ open_pmd(is_deflate_supported{});
+}
+
+template<class NextLayer, bool deflateSupported>
+inline
+void
+stream<NextLayer, deflateSupported>::
+open_pmd(std::true_type)
+{
+ if(((role_ == role_type::client &&
+ this->pmd_opts_.client_enable) ||
+ (role_ == role_type::server &&
+ this->pmd_opts_.server_enable)) &&
+ this->pmd_config_.accept)
{
- pmd_normalize(pmd_config_);
- pmd_.reset(new pmd_t);
+ pmd_normalize(this->pmd_config_);
+ this->pmd_.reset(new typename
+ detail::stream_base<deflateSupported>::pmd_type);
if(role_ == role_type::client)
{
- pmd_->zi.reset(
- pmd_config_.server_max_window_bits);
- pmd_->zo.reset(
- pmd_opts_.compLevel,
- pmd_config_.client_max_window_bits,
- pmd_opts_.memLevel,
+ this->pmd_->zi.reset(
+ this->pmd_config_.server_max_window_bits);
+ this->pmd_->zo.reset(
+ this->pmd_opts_.compLevel,
+ this->pmd_config_.client_max_window_bits,
+ this->pmd_opts_.memLevel,
zlib::Strategy::normal);
}
else
{
- pmd_->zi.reset(
- pmd_config_.client_max_window_bits);
- pmd_->zo.reset(
- pmd_opts_.compLevel,
- pmd_config_.server_max_window_bits,
- pmd_opts_.memLevel,
+ this->pmd_->zi.reset(
+ this->pmd_config_.client_max_window_bits);
+ this->pmd_->zo.reset(
+ this->pmd_opts_.compLevel,
+ this->pmd_config_.server_max_window_bits,
+ this->pmd_opts_.memLevel,
zlib::Strategy::normal);
}
}
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
close()
{
wr_buf_.reset();
- pmd_.reset();
+ close_pmd(is_deflate_supported{});
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
reset()
{
BOOST_ASSERT(status_ != status::open);
@@ -203,19 +198,23 @@ reset()
rd_close_ = false;
wr_close_ = false;
wr_cont_ = false;
+ // These should not be necessary, because all completion
+ // handlers must be allowed to execute otherwise the
+ // stream exhibits undefined behavior.
wr_block_.reset();
rd_block_.reset();
cr_.code = close_code::none;
}
// Called before each write frame
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
+inline
void
-stream<NextLayer>::
-begin_msg()
+stream<NextLayer, deflateSupported>::
+begin_msg(std::true_type)
{
wr_frag_ = wr_frag_opt_;
- wr_compress_ = static_cast<bool>(pmd_);
+ wr_compress_ = static_cast<bool>(this->pmd_);
// Maintain the write buffer
if( wr_compress_ ||
@@ -235,31 +234,118 @@ begin_msg()
}
}
+// Called before each write frame
+template<class NextLayer, bool deflateSupported>
+inline
+void
+stream<NextLayer, deflateSupported>::
+begin_msg(std::false_type)
+{
+ wr_frag_ = wr_frag_opt_;
+
+ // Maintain the write buffer
+ if(role_ == role_type::client)
+ {
+ if(! wr_buf_ || wr_buf_size_ != wr_buf_opt_)
+ {
+ wr_buf_size_ = wr_buf_opt_;
+ wr_buf_ = boost::make_unique_noinit<
+ std::uint8_t[]>(wr_buf_size_);
+ }
+ }
+ else
+ {
+ wr_buf_size_ = wr_buf_opt_;
+ wr_buf_.reset();
+ }
+}
+
+template<class NextLayer, bool deflateSupported>
+std::size_t
+stream<NextLayer, deflateSupported>::
+read_size_hint(
+ std::size_t initial_size,
+ std::true_type) const
+{
+ using beast::detail::clamp;
+ std::size_t result;
+ BOOST_ASSERT(initial_size > 0);
+ if(! this->pmd_ || (! rd_done_ && ! this->pmd_->rd_set))
+ {
+ // current message is uncompressed
+
+ if(rd_done_)
+ {
+ // first message frame
+ result = initial_size;
+ goto done;
+ }
+ else if(rd_fh_.fin)
+ {
+ // last message frame
+ BOOST_ASSERT(rd_remain_ > 0);
+ result = clamp(rd_remain_);
+ goto done;
+ }
+ }
+ result = (std::max)(
+ initial_size, clamp(rd_remain_));
+done:
+ BOOST_ASSERT(result != 0);
+ return result;
+}
+
+template<class NextLayer, bool deflateSupported>
+std::size_t
+stream<NextLayer, deflateSupported>::
+read_size_hint(
+ std::size_t initial_size,
+ std::false_type) const
+{
+ using beast::detail::clamp;
+ std::size_t result;
+ BOOST_ASSERT(initial_size > 0);
+ // compression is not supported
+ if(rd_done_)
+ {
+ // first message frame
+ result = initial_size;
+ }
+ else if(rd_fh_.fin)
+ {
+ // last message frame
+ BOOST_ASSERT(rd_remain_ > 0);
+ result = clamp(rd_remain_);
+ }
+ else
+ {
+ result = (std::max)(
+ initial_size, clamp(rd_remain_));
+ }
+ BOOST_ASSERT(result != 0);
+ return result;
+}
+
//------------------------------------------------------------------------------
// Attempt to read a complete frame header.
// Returns `false` if more bytes are needed
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer>
bool
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
parse_fh(
detail::frame_header& fh,
DynamicBuffer& b,
- close_code& code)
+ error_code& ec)
{
using boost::asio::buffer;
using boost::asio::buffer_copy;
using boost::asio::buffer_size;
- auto const err =
- [&](close_code cv)
- {
- code = cv;
- return false;
- };
if(buffer_size(b.data()) < 2)
{
- code = close_code::none;
+ // need more bytes
+ ec.assign(0, ec.category());
return false;
}
buffers_suffix<typename
@@ -282,7 +368,8 @@ parse_fh(
need += 4;
if(buffer_size(cb) < need)
{
- code = close_code::none;
+ // need more bytes
+ ec.assign(0, ec.category());
return false;
}
fh.op = static_cast<
@@ -299,28 +386,30 @@ parse_fh(
if(rd_cont_)
{
// new data frame when continuation expected
- return err(close_code::protocol_error);
+ ec = error::bad_data_frame;
+ return false;
}
- if((fh.rsv1 && ! pmd_) ||
- fh.rsv2 || fh.rsv3)
+ if(fh.rsv2 || fh.rsv3 ||
+ ! this->rd_deflated(fh.rsv1))
{
// reserved bits not cleared
- return err(close_code::protocol_error);
+ ec = error::bad_reserved_bits;
+ return false;
}
- if(pmd_)
- pmd_->rd_set = fh.rsv1;
break;
case detail::opcode::cont:
if(! rd_cont_)
{
// continuation without an active message
- return err(close_code::protocol_error);
+ ec = error::bad_continuation;
+ return false;
}
if(fh.rsv1 || fh.rsv2 || fh.rsv3)
{
// reserved bits not cleared
- return err(close_code::protocol_error);
+ ec = error::bad_reserved_bits;
+ return false;
}
break;
@@ -328,31 +417,41 @@ parse_fh(
if(detail::is_reserved(fh.op))
{
// reserved opcode
- return err(close_code::protocol_error);
+ ec = error::bad_opcode;
+ return false;
}
if(! fh.fin)
{
// fragmented control message
- return err(close_code::protocol_error);
+ ec = error::bad_control_fragment;
+ return false;
}
if(fh.len > 125)
{
// invalid length for control message
- return err(close_code::protocol_error);
+ ec = error::bad_control_size;
+ return false;
}
if(fh.rsv1 || fh.rsv2 || fh.rsv3)
{
// reserved bits not cleared
- return err(close_code::protocol_error);
+ ec = error::bad_reserved_bits;
+ return false;
}
break;
}
- // unmasked frame from client
if(role_ == role_type::server && ! fh.mask)
- return err(close_code::protocol_error);
- // masked frame from server
+ {
+ // unmasked frame from client
+ ec = error::bad_unmasked_frame;
+ return false;
+ }
if(role_ == role_type::client && fh.mask)
- return err(close_code::protocol_error);
+ {
+ // masked frame from server
+ ec = error::bad_masked_frame;
+ return false;
+ }
if(detail::is_control(fh.op) &&
buffer_size(cb) < need + fh.len)
{
@@ -368,9 +467,12 @@ parse_fh(
BOOST_ASSERT(buffer_size(cb) >= sizeof(tmp));
cb.consume(buffer_copy(buffer(tmp), cb));
fh.len = detail::big_uint16_to_native(&tmp[0]);
- // length not canonical
if(fh.len < 126)
- return err(close_code::protocol_error);
+ {
+ // length not canonical
+ ec = error::bad_size;
+ return false;
+ }
break;
}
case 127:
@@ -379,9 +481,12 @@ parse_fh(
BOOST_ASSERT(buffer_size(cb) >= sizeof(tmp));
cb.consume(buffer_copy(buffer(tmp), cb));
fh.len = detail::big_uint64_to_native(&tmp[0]);
- // length not canonical
if(fh.len < 65536)
- return err(close_code::protocol_error);
+ {
+ // length not canonical
+ ec = error::bad_size;
+ return false;
+ }
break;
}
}
@@ -409,26 +514,34 @@ parse_fh(
{
if(rd_size_ > (std::numeric_limits<
std::uint64_t>::max)() - fh.len)
- return err(close_code::too_big);
+ {
+ // message size exceeds configured limit
+ ec = error::message_too_big;
+ return false;
+ }
}
- if(! pmd_ || ! pmd_->rd_set)
+ if(! this->rd_deflated())
{
if(rd_msg_max_ && beast::detail::sum_exceeds(
rd_size_, fh.len, rd_msg_max_))
- return err(close_code::too_big);
+ {
+ // message size exceeds configured limit
+ ec = error::message_too_big;
+ return false;
+ }
}
rd_cont_ = ! fh.fin;
rd_remain_ = fh.len;
}
b.consume(b.size() - buffer_size(cb));
- code = close_code::none;
+ ec.assign(0, ec.category());
return true;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
write_close(DynamicBuffer& db, close_reason const& cr)
{
using namespace boost::endian;
@@ -479,10 +592,10 @@ write_close(DynamicBuffer& db, close_reason const& cr)
}
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class DynamicBuffer>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
write_ping(DynamicBuffer& db,
detail::opcode code, ping_data const& data)
{
@@ -513,14 +626,13 @@ write_ping(DynamicBuffer& db,
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Decorator>
request_type
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
build_request(detail::sec_ws_key_type& key,
- string_view host,
- string_view target,
- Decorator const& decorator)
+ string_view host, string_view target,
+ Decorator const& decorator)
{
request_type req;
req.target(target);
@@ -532,34 +644,45 @@ build_request(detail::sec_ws_key_type& key,
detail::make_sec_ws_key(key, wr_gen_);
req.set(http::field::sec_websocket_key, key);
req.set(http::field::sec_websocket_version, "13");
- if(pmd_opts_.client_enable)
+ build_request_pmd(req, is_deflate_supported{});
+ decorator(req);
+ if(! req.count(http::field::user_agent))
+ req.set(http::field::user_agent,
+ BOOST_BEAST_VERSION_STRING);
+ return req;
+}
+
+template<class NextLayer, bool deflateSupported>
+inline
+void
+stream<NextLayer, deflateSupported>::
+build_request_pmd(request_type& req, std::true_type)
+{
+ if(this->pmd_opts_.client_enable)
{
detail::pmd_offer config;
config.accept = true;
config.server_max_window_bits =
- pmd_opts_.server_max_window_bits;
+ this->pmd_opts_.server_max_window_bits;
config.client_max_window_bits =
- pmd_opts_.client_max_window_bits;
+ this->pmd_opts_.client_max_window_bits;
config.server_no_context_takeover =
- pmd_opts_.server_no_context_takeover;
+ this->pmd_opts_.server_no_context_takeover;
config.client_no_context_takeover =
- pmd_opts_.client_no_context_takeover;
+ this->pmd_opts_.client_no_context_takeover;
detail::pmd_write(req, config);
}
- decorator(req);
- if(! req.count(http::field::user_agent))
- req.set(http::field::user_agent,
- BOOST_BEAST_VERSION_STRING);
- return req;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Body, class Allocator, class Decorator>
response_type
-stream<NextLayer>::
-build_response(http::request<Body,
- http::basic_fields<Allocator>> const& req,
- Decorator const& decorator)
+stream<NextLayer, deflateSupported>::
+build_response(
+ http::request<Body,
+ http::basic_fields<Allocator>> const& req,
+ Decorator const& decorator,
+ error_code& result)
{
auto const decorate =
[&decorator](response_type& res)
@@ -573,40 +696,58 @@ build_response(http::request<Body,
}
};
auto err =
- [&](std::string const& text)
+ [&](error e)
{
+ result = e;
response_type res;
res.version(req.version());
res.result(http::status::bad_request);
- res.body() = text;
+ res.body() = result.message();
res.prepare_payload();
decorate(res);
return res;
};
- if(req.version() < 11)
- return err("HTTP version 1.1 required");
+ if(req.version() != 11)
+ return err(error::bad_http_version);
if(req.method() != http::verb::get)
- return err("Wrong method");
- if(! is_upgrade(req))
- return err("Expected Upgrade request");
+ return err(error::bad_method);
if(! req.count(http::field::host))
- return err("Missing Host");
- if(! req.count(http::field::sec_websocket_key))
- return err("Missing Sec-WebSocket-Key");
- auto const key = req[http::field::sec_websocket_key];
- if(key.size() > detail::sec_ws_key_type::max_size_n)
- return err("Invalid Sec-WebSocket-Key");
- {
- auto const version =
- req[http::field::sec_websocket_version];
- if(version.empty())
- return err("Missing Sec-WebSocket-Version");
- if(version != "13")
+ return err(error::no_host);
+ {
+ auto const it = req.find(http::field::connection);
+ if(it == req.end())
+ return err(error::no_connection);
+ if(! http::token_list{it->value()}.exists("upgrade"))
+ return err(error::no_connection_upgrade);
+ }
+ {
+ auto const it = req.find(http::field::upgrade);
+ if(it == req.end())
+ return err(error::no_upgrade);
+ if(! http::token_list{it->value()}.exists("websocket"))
+ return err(error::no_upgrade_websocket);
+ }
+ string_view key;
+ {
+ auto const it = req.find(http::field::sec_websocket_key);
+ if(it == req.end())
+ return err(error::no_sec_key);
+ key = it->value();
+ if(key.size() > detail::sec_ws_key_type::max_size_n)
+ return err(error::bad_sec_key);
+ }
+ {
+ auto const it = req.find(http::field::sec_websocket_version);
+ if(it == req.end())
+ return err(error::no_sec_version);
+ if(it->value() != "13")
{
response_type res;
res.result(http::status::upgrade_required);
res.version(req.version());
res.set(http::field::sec_websocket_version, "13");
+ result = error::bad_sec_version;
+ res.body() = result.message();
res.prepare_payload();
decorate(res);
return res;
@@ -614,12 +755,6 @@ build_response(http::request<Body,
}
response_type res;
- {
- detail::pmd_offer offer;
- detail::pmd_offer unused;
- pmd_read(offer, req);
- pmd_negotiate(res, unused, offer, pmd_opts_);
- }
res.result(http::status::switching_protocols);
res.version(req.version());
res.set(http::field::upgrade, "websocket");
@@ -629,53 +764,95 @@ build_response(http::request<Body,
detail::make_sec_ws_accept(acc, key);
res.set(http::field::sec_websocket_accept, acc);
}
+ build_response_pmd(res, req, is_deflate_supported{});
decorate(res);
+ result = {};
return res;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
+template<class Body, class Allocator>
+inline
+void
+stream<NextLayer, deflateSupported>::
+build_response_pmd(
+ response_type& res,
+ http::request<Body,
+ http::basic_fields<Allocator>> const& req,
+ std::true_type)
+{
+ detail::pmd_offer offer;
+ detail::pmd_offer unused;
+ pmd_read(offer, req);
+ pmd_negotiate(res, unused, offer, this->pmd_opts_);
+}
+
+// Called when the WebSocket Upgrade response is received
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
-on_response(response_type const& res,
- detail::sec_ws_key_type const& key, error_code& ec)
+stream<NextLayer, deflateSupported>::
+on_response(
+ response_type const& res,
+ detail::sec_ws_key_type const& key,
+ error_code& ec)
{
- bool const success = [&]()
+ auto const err =
+ [&](error e)
+ {
+ ec = e;
+ };
+ if(res.result() != http::status::switching_protocols)
+ return err(error::upgrade_declined);
+ if(res.version() != 11)
+ return err(error::bad_http_version);
{
- if(res.version() < 11)
- return false;
- if(res.result() != http::status::switching_protocols)
- return false;
- if(! http::token_list{res[http::field::connection]}.exists("upgrade"))
- return false;
- if(! http::token_list{res[http::field::upgrade]}.exists("websocket"))
- return false;
- if(res.count(http::field::sec_websocket_accept) != 1)
- return false;
+ auto const it = res.find(http::field::connection);
+ if(it == res.end())
+ return err(error::no_connection);
+ if(! http::token_list{it->value()}.exists("upgrade"))
+ return err(error::no_connection_upgrade);
+ }
+ {
+ auto const it = res.find(http::field::upgrade);
+ if(it == res.end())
+ return err(error::no_upgrade);
+ if(! http::token_list{it->value()}.exists("websocket"))
+ return err(error::no_upgrade_websocket);
+ }
+ {
+ auto const it = res.find(http::field::sec_websocket_accept);
+ if(it == res.end())
+ return err(error::no_sec_accept);
detail::sec_ws_accept_type acc;
detail::make_sec_ws_accept(acc, key);
- if(acc.compare(
- res[http::field::sec_websocket_accept]) != 0)
- return false;
- return true;
- }();
- if(! success)
- {
- ec = error::handshake_failed;
- return;
+ if(acc.compare(it->value()) != 0)
+ return err(error::bad_sec_accept);
}
+
ec.assign(0, ec.category());
+ on_response_pmd(res, is_deflate_supported{});
+ open(role_type::client);
+}
+
+template<class NextLayer, bool deflateSupported>
+inline
+void
+stream<NextLayer, deflateSupported>::
+on_response_pmd(
+ response_type const& res,
+ std::true_type)
+{
detail::pmd_offer offer;
pmd_read(offer, res);
// VFALCO see if offer satisfies pmd_config_,
// return an error if not.
- pmd_config_ = offer; // overwrite for now
- open(role_type::client);
+ this->pmd_config_ = offer; // overwrite for now
}
// _Fail the WebSocket Connection_
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
do_fail(
std::uint16_t code, // if set, send a close frame first
error_code ev, // error code to use upon success
diff --git a/boost/beast/websocket/impl/teardown.ipp b/boost/beast/websocket/impl/teardown.ipp
index 8f4475f246..add6b2773d 100644
--- a/boost/beast/websocket/impl/teardown.ipp
+++ b/boost/beast/websocket/impl/teardown.ipp
@@ -14,7 +14,9 @@
#include <boost/beast/core/type_traits.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
+#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/asio/post.hpp>
#include <memory>
@@ -25,7 +27,7 @@ namespace websocket {
namespace detail {
template<class Handler>
-class teardown_tcp_op
+class teardown_tcp_op : public boost::asio::coroutine
{
using socket_type =
boost::asio::ip::tcp::socket;
@@ -33,7 +35,7 @@ class teardown_tcp_op
Handler h_;
socket_type& s_;
role_type role_;
- int step_ = 0;
+ bool nb_;
public:
teardown_tcp_op(teardown_tcp_op&& other) = default;
@@ -56,7 +58,7 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
@@ -65,7 +67,7 @@ public:
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, s_.get_executor());
}
@@ -78,60 +80,83 @@ public:
bool asio_handler_is_continuation(teardown_tcp_op* op)
{
using boost::asio::asio_handler_is_continuation;
- return op->step_ >= 3 ||
- asio_handler_is_continuation(std::addressof(op->h_));
+ return asio_handler_is_continuation(
+ std::addressof(op->h_));
+ }
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, teardown_tcp_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(f, std::addressof(op->h_));
}
};
template<class Handler>
void
teardown_tcp_op<Handler>::
-operator()(error_code ec, std::size_t)
+operator()(error_code ec, std::size_t bytes_transferred)
{
using boost::asio::buffer;
using tcp = boost::asio::ip::tcp;
- switch(step_)
+ BOOST_ASIO_CORO_REENTER(*this)
{
- case 0:
+ nb_ = s_.non_blocking();
s_.non_blocking(true, ec);
+ if(! ec)
+ {
+ if(role_ == role_type::server)
+ s_.shutdown(tcp::socket::shutdown_send, ec);
+ }
if(ec)
{
- step_ = 1;
- return boost::asio::post(
+ BOOST_ASIO_CORO_YIELD
+ boost::asio::post(
s_.get_executor(),
bind_handler(std::move(*this), ec, 0));
+ goto upcall;
}
- step_ = 2;
- if(role_ == role_type::server)
- s_.shutdown(tcp::socket::shutdown_send, ec);
- goto do_read;
-
- case 1:
- break;
-
- case 2:
- step_ = 3;
-
- case 3:
- if(ec != boost::asio::error::would_block)
- break;
+ for(;;)
{
- char buf[2048];
- s_.read_some(
- boost::asio::buffer(buf), ec);
+ {
+ char buf[2048];
+ s_.read_some(
+ boost::asio::buffer(buf), ec);
+ }
+ if(ec == boost::asio::error::would_block)
+ {
+ BOOST_ASIO_CORO_YIELD
+ s_.async_wait(
+ boost::asio::ip::tcp::socket::wait_read,
+ std::move(*this));
+ continue;
+ }
if(ec)
+ {
+ if(ec != boost::asio::error::eof)
+ goto upcall;
+ ec = {};
+ break;
+ }
+ if(bytes_transferred == 0)
+ {
+ // happens sometimes
break;
+ }
}
-
- do_read:
- return s_.async_read_some(
- boost::asio::null_buffers{},
- std::move(*this));
+ if(role_ == role_type::client)
+ s_.shutdown(tcp::socket::shutdown_send, ec);
+ if(ec)
+ goto upcall;
+ s_.close(ec);
+ upcall:
+ {
+ error_code ignored;
+ s_.non_blocking(nb_, ignored);
+ }
+ h_(ec);
}
- if(role_ == role_type::client)
- s_.shutdown(tcp::socket::shutdown_send, ec);
- s_.close(ec);
- h_(ec);
}
} // detail
@@ -149,17 +174,31 @@ teardown(
if(role == role_type::server)
socket.shutdown(
boost::asio::ip::tcp::socket::shutdown_send, ec);
- while(! ec)
+ if(ec)
+ return;
+ for(;;)
{
- char buf[8192];
- auto const n = socket.read_some(
- buffer(buf), ec);
- if(! n)
+ char buf[2048];
+ auto const bytes_transferred =
+ socket.read_some(buffer(buf), ec);
+ if(ec)
+ {
+ if(ec != boost::asio::error::eof)
+ return;
+ ec = {};
break;
+ }
+ if(bytes_transferred == 0)
+ {
+ // happens sometimes
+ break;
+ }
}
if(role == role_type::client)
socket.shutdown(
boost::asio::ip::tcp::socket::shutdown_send, ec);
+ if(ec)
+ return;
socket.close(ec);
}
diff --git a/boost/beast/websocket/impl/write.ipp b/boost/beast/websocket/impl/write.ipp
index b04f2826fc..d12f2f9e12 100644
--- a/boost/beast/websocket/impl/write.ipp
+++ b/boost/beast/websocket/impl/write.ipp
@@ -14,7 +14,6 @@
#include <boost/beast/core/buffers_cat.hpp>
#include <boost/beast/core/buffers_prefix.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
-#include <boost/beast/core/handler_ptr.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/core/type_traits.hpp>
#include <boost/beast/core/detail/clamp.hpp>
@@ -24,6 +23,7 @@
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
+#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
@@ -34,39 +34,139 @@ namespace boost {
namespace beast {
namespace websocket {
-template<class NextLayer>
+namespace detail {
+
+// Compress a buffer sequence
+// Returns: `true` if more calls are needed
+//
+template<>
+template<class ConstBufferSequence>
+bool
+stream_base<true>::
+deflate(
+ boost::asio::mutable_buffer& out,
+ buffers_suffix<ConstBufferSequence>& cb,
+ bool fin,
+ std::size_t& total_in,
+ error_code& ec)
+{
+ using boost::asio::buffer;
+ BOOST_ASSERT(out.size() >= 6);
+ auto& zo = this->pmd_->zo;
+ zlib::z_params zs;
+ zs.avail_in = 0;
+ zs.next_in = nullptr;
+ zs.avail_out = out.size();
+ zs.next_out = out.data();
+ for(auto in : beast::detail::buffers_range(cb))
+ {
+ zs.avail_in = in.size();
+ if(zs.avail_in == 0)
+ continue;
+ zs.next_in = in.data();
+ zo.write(zs, zlib::Flush::none, ec);
+ if(ec)
+ {
+ if(ec != zlib::error::need_buffers)
+ return false;
+ BOOST_ASSERT(zs.avail_out == 0);
+ BOOST_ASSERT(zs.total_out == out.size());
+ ec.assign(0, ec.category());
+ break;
+ }
+ if(zs.avail_out == 0)
+ {
+ BOOST_ASSERT(zs.total_out == out.size());
+ break;
+ }
+ BOOST_ASSERT(zs.avail_in == 0);
+ }
+ total_in = zs.total_in;
+ cb.consume(zs.total_in);
+ if(zs.avail_out > 0 && fin)
+ {
+ auto const remain = boost::asio::buffer_size(cb);
+ if(remain == 0)
+ {
+ // Inspired by Mark Adler
+ // https://github.com/madler/zlib/issues/149
+ //
+ // VFALCO We could do this flush twice depending
+ // on how much space is in the output.
+ zo.write(zs, zlib::Flush::block, ec);
+ BOOST_ASSERT(! ec || ec == zlib::error::need_buffers);
+ if(ec == zlib::error::need_buffers)
+ ec.assign(0, ec.category());
+ if(ec)
+ return false;
+ if(zs.avail_out >= 6)
+ {
+ zo.write(zs, zlib::Flush::full, ec);
+ BOOST_ASSERT(! ec);
+ // remove flush marker
+ zs.total_out -= 4;
+ out = buffer(out.data(), zs.total_out);
+ return false;
+ }
+ }
+ }
+ ec.assign(0, ec.category());
+ out = buffer(out.data(), zs.total_out);
+ return true;
+}
+
+template<>
+inline
+void
+stream_base<true>::
+do_context_takeover_write(role_type role)
+{
+ if((role == role_type::client &&
+ this->pmd_config_.client_no_context_takeover) ||
+ (role == role_type::server &&
+ this->pmd_config_.server_no_context_takeover))
+ {
+ this->pmd_->zo.reset();
+ }
+}
+
+} // detail
+
+//------------------------------------------------------------------------------
+
+template<class NextLayer, bool deflateSupported>
template<class Buffers, class Handler>
-class stream<NextLayer>::write_some_op
+class stream<NextLayer, deflateSupported>::write_some_op
: public boost::asio::coroutine
{
Handler h_;
- stream<NextLayer>& ws_;
+ stream<NextLayer, deflateSupported>& ws_;
buffers_suffix<Buffers> cb_;
detail::frame_header fh_;
detail::prepared_key key_;
std::size_t bytes_transferred_ = 0;
std::size_t remain_;
std::size_t in_;
- token tok_;
int how_;
bool fin_;
bool more_;
bool cont_ = false;
public:
+ static constexpr int id = 2; // for soft_mutex
+
write_some_op(write_some_op&&) = default;
- write_some_op(write_some_op const&) = default;
+ write_some_op(write_some_op const&) = delete;
template<class DeducedHandler>
write_some_op(
DeducedHandler&& h,
- stream<NextLayer>& ws,
+ stream<NextLayer, deflateSupported>& ws,
bool fin,
Buffers const& bs)
: h_(std::forward<DeducedHandler>(h))
, ws_(ws)
, cb_(bs)
- , tok_(ws_.tok_.unique())
, fin_(fin)
{
}
@@ -77,16 +177,16 @@ public:
allocator_type
get_allocator() const noexcept
{
- return boost::asio::get_associated_allocator(h_);
+ return (boost::asio::get_associated_allocator)(h_);
}
using executor_type = boost::asio::associated_executor_t<
- Handler, decltype(std::declval<stream<NextLayer>&>().get_executor())>;
+ Handler, decltype(std::declval<stream<NextLayer, deflateSupported>&>().get_executor())>;
executor_type
get_executor() const noexcept
{
- return boost::asio::get_associated_executor(
+ return (boost::asio::get_associated_executor)(
h_, ws_.get_executor());
}
@@ -108,12 +208,21 @@ public:
return op->cont_ || asio_handler_is_continuation(
std::addressof(op->h_));
}
+
+ template<class Function>
+ friend
+ void asio_handler_invoke(Function&& f, write_some_op* op)
+ {
+ using boost::asio::asio_handler_invoke;
+ asio_handler_invoke(
+ f, std::addressof(op->h_));
+ }
};
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class Buffers, class Handler>
void
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
write_some_op<Buffers, Handler>::
operator()(
error_code ec,
@@ -194,11 +303,8 @@ operator()(
}
// Maybe suspend
- if(! ws_.wr_block_)
+ if(ws_.wr_block_.try_lock(this))
{
- // Acquire the write block
- ws_.wr_block_ = tok_;
-
// Make sure the stream is open
if(! ws_.check_open(ec))
goto upcall;
@@ -207,19 +313,17 @@ operator()(
{
do_suspend:
// Suspend
- BOOST_ASSERT(ws_.wr_block_ != tok_);
BOOST_ASIO_CORO_YIELD
- ws_.paused_wr_.save(std::move(*this));
+ ws_.paused_wr_.emplace(std::move(*this));
// Acquire the write block
- BOOST_ASSERT(! ws_.wr_block_);
- ws_.wr_block_ = tok_;
+ ws_.wr_block_.lock(this);
// Resume
BOOST_ASIO_CORO_YIELD
boost::asio::post(
ws_.get_executor(), std::move(*this));
- BOOST_ASSERT(ws_.wr_block_ == tok_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked(this));
// Make sure the stream is open
if(! ws_.check_open(ec))
@@ -278,15 +382,15 @@ operator()(
fh_.op = detail::opcode::cont;
// Allow outgoing control frames to
// be sent in between message frames
- ws_.wr_block_.reset();
+ ws_.wr_block_.unlock(this);
if( ws_.paused_close_.maybe_invoke() ||
ws_.paused_rd_.maybe_invoke() ||
ws_.paused_ping_.maybe_invoke())
{
- BOOST_ASSERT(ws_.wr_block_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked());
goto do_suspend;
}
- ws_.wr_block_ = tok_;
+ ws_.wr_block_.lock(this);
}
goto upcall;
}
@@ -377,15 +481,15 @@ operator()(
fh_.op = detail::opcode::cont;
// Allow outgoing control frames to
// be sent in between message frames:
- ws_.wr_block_.reset();
+ ws_.wr_block_.unlock(this);
if( ws_.paused_close_.maybe_invoke() ||
ws_.paused_rd_.maybe_invoke() ||
ws_.paused_ping_.maybe_invoke())
{
- BOOST_ASSERT(ws_.wr_block_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked());
goto do_suspend;
}
- ws_.wr_block_ = tok_;
+ ws_.wr_block_.lock(this);
}
goto upcall;
}
@@ -398,8 +502,7 @@ operator()(
{
b = buffer(ws_.wr_buf_.get(),
ws_.wr_buf_size_);
- more_ = detail::deflate(ws_.pmd_->zo,
- b, cb_, fin_, in_, ec);
+ more_ = ws_.deflate(b, cb_, fin_, in_, ec);
if(! ws_.check_ok(ec))
goto upcall;
n = buffer_size(b);
@@ -439,24 +542,20 @@ operator()(
fh_.rsv1 = false;
// Allow outgoing control frames to
// be sent in between message frames:
- ws_.wr_block_.reset();
+ ws_.wr_block_.unlock(this);
if( ws_.paused_close_.maybe_invoke() ||
ws_.paused_rd_.maybe_invoke() ||
ws_.paused_ping_.maybe_invoke())
{
- BOOST_ASSERT(ws_.wr_block_);
+ BOOST_ASSERT(ws_.wr_block_.is_locked());
goto do_suspend;
}
- ws_.wr_block_ = tok_;
+ ws_.wr_block_.lock(this);
}
else
{
- if(fh_.fin && (
- (ws_.role_ == role_type::client &&
- ws_.pmd_config_.client_no_context_takeover) ||
- (ws_.role_ == role_type::server &&
- ws_.pmd_config_.server_no_context_takeover)))
- ws_.pmd_->zo.reset();
+ if(fh_.fin)
+ ws_.do_context_takeover_write(ws_.role_);
goto upcall;
}
}
@@ -465,25 +564,24 @@ operator()(
//--------------------------------------------------------------------------
upcall:
- BOOST_ASSERT(ws_.wr_block_ == tok_);
- ws_.wr_block_.reset();
+ ws_.wr_block_.unlock(this);
ws_.paused_close_.maybe_invoke() ||
ws_.paused_rd_.maybe_invoke() ||
ws_.paused_ping_.maybe_invoke();
if(! cont_)
return boost::asio::post(
ws_.stream_.get_executor(),
- bind_handler(h_, ec, bytes_transferred_));
+ bind_handler(std::move(h_), ec, bytes_transferred_));
h_(ec, bytes_transferred_);
}
}
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
write_some(bool fin, ConstBufferSequence const& buffers)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -499,10 +597,10 @@ write_some(bool fin, ConstBufferSequence const& buffers)
return bytes_transferred;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
write_some(bool fin,
ConstBufferSequence const& buffers, error_code& ec)
{
@@ -544,9 +642,8 @@ write_some(bool fin,
{
auto b = buffer(
wr_buf_.get(), wr_buf_size_);
- auto const more = detail::deflate(
- pmd_->zo, b, cb, fin,
- bytes_transferred, ec);
+ auto const more = this->deflate(
+ b, cb, fin, bytes_transferred, ec);
if(! check_ok(ec))
return bytes_transferred;
auto const n = buffer_size(b);
@@ -582,12 +679,8 @@ write_some(bool fin,
fh.op = detail::opcode::cont;
fh.rsv1 = false;
}
- if(fh.fin && (
- (role_ == role_type::client &&
- pmd_config_.client_no_context_takeover) ||
- (role_ == role_type::server &&
- pmd_config_.server_no_context_takeover)))
- pmd_->zo.reset();
+ if(fh.fin)
+ this->do_context_takeover_write(role_);
}
else if(! fh.mask)
{
@@ -712,11 +805,11 @@ write_some(bool fin,
return bytes_transferred;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence, class WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_write_some(bool fin,
ConstBufferSequence const& bs, WriteHandler&& handler)
{
@@ -725,21 +818,21 @@ async_write_some(bool fin,
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
- boost::asio::async_completion<WriteHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
write_some_op<ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE(
WriteHandler, void(error_code, std::size_t))>{
- init.completion_handler, *this, fin, bs}(
+ std::move(init.completion_handler), *this, fin, bs}(
{}, 0, false);
return init.result.get();
}
//------------------------------------------------------------------------------
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
write(ConstBufferSequence const& buffers)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -754,10 +847,10 @@ write(ConstBufferSequence const& buffers)
return bytes_transferred;
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence>
std::size_t
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
write(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_sync_stream<next_layer_type>::value,
@@ -768,11 +861,11 @@ write(ConstBufferSequence const& buffers, error_code& ec)
return write_some(true, buffers, ec);
}
-template<class NextLayer>
+template<class NextLayer, bool deflateSupported>
template<class ConstBufferSequence, class WriteHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(error_code, std::size_t))
-stream<NextLayer>::
+stream<NextLayer, deflateSupported>::
async_write(
ConstBufferSequence const& bs, WriteHandler&& handler)
{
@@ -781,11 +874,11 @@ async_write(
static_assert(boost::asio::is_const_buffer_sequence<
ConstBufferSequence>::value,
"ConstBufferSequence requirements not met");
- boost::asio::async_completion<WriteHandler,
- void(error_code, std::size_t)> init{handler};
+ BOOST_BEAST_HANDLER_INIT(
+ WriteHandler, void(error_code, std::size_t));
write_some_op<ConstBufferSequence, BOOST_ASIO_HANDLER_TYPE(
WriteHandler, void(error_code, std::size_t))>{
- init.completion_handler, *this, true, bs}(
+ std::move(init.completion_handler), *this, true, bs}(
{}, 0, false);
return init.result.get();
}
diff --git a/boost/beast/websocket/ssl.hpp b/boost/beast/websocket/ssl.hpp
index 44d5dc8082..d51921a481 100644
--- a/boost/beast/websocket/ssl.hpp
+++ b/boost/beast/websocket/ssl.hpp
@@ -55,9 +55,9 @@ teardown(
@param stream The stream to tear down.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& error // result of operation
); @endcode
diff --git a/boost/beast/websocket/stream.hpp b/boost/beast/websocket/stream.hpp
index b6d10834ef..90cb753294 100644
--- a/boost/beast/websocket/stream.hpp
+++ b/boost/beast/websocket/stream.hpp
@@ -15,11 +15,13 @@
#include <boost/beast/websocket/option.hpp>
#include <boost/beast/websocket/role.hpp>
#include <boost/beast/websocket/rfc6455.hpp>
+#include <boost/beast/websocket/stream_fwd.hpp>
#include <boost/beast/websocket/detail/frame.hpp>
#include <boost/beast/websocket/detail/hybi13.hpp>
#include <boost/beast/websocket/detail/mask.hpp>
#include <boost/beast/websocket/detail/pausation.hpp>
#include <boost/beast/websocket/detail/pmd_extension.hpp>
+#include <boost/beast/websocket/detail/stream_base.hpp>
#include <boost/beast/websocket/detail/utf8_checker.hpp>
#include <boost/beast/core/static_buffer.hpp>
#include <boost/beast/core/string.hpp>
@@ -28,8 +30,6 @@
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/http/detail/type_traits.hpp>
-#include <boost/beast/zlib/deflate_stream.hpp>
-#include <boost/beast/zlib/inflate_stream.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/error.hpp>
#include <algorithm>
@@ -38,16 +38,10 @@
#include <limits>
#include <type_traits>
-#include <boost/asio/io_context.hpp> // DEPRECATED
-
namespace boost {
namespace beast {
namespace websocket {
-namespace detail {
-class frame_test;
-}
-
/// The type of object holding HTTP Upgrade requests
using request_type = http::request<http::empty_body>;
@@ -71,6 +65,10 @@ enum class frame_type
pong
};
+namespace detail {
+class frame_test;
+} // detail
+
//--------------------------------------------------------------------
/** Provides message-oriented functionality using WebSocket.
@@ -109,6 +107,12 @@ enum class frame_type
For asynchronous operations, the type must support the
@b AsyncStream concept.
+ @tparam deflateSupported A `bool` indicating whether or not the
+ stream will be capable of negotiating the permessage-deflate websocket
+ extension. Note that even if this is set to `true`, the permessage
+ deflate options (set by the caller at runtime) must still have the
+ feature enabled for a successful negotiation to occur.
+
@note A stream object must not be moved or destroyed while there
are pending asynchronous operations associated with it.
@@ -117,16 +121,22 @@ enum class frame_type
@b DynamicBuffer,
@b SyncStream
*/
-template<class NextLayer>
+template<
+ class NextLayer,
+ bool deflateSupported>
class stream
+#ifndef BOOST_BEAST_DOXYGEN
+ : private detail::stream_base<deflateSupported>
+#endif
{
friend class close_test;
friend class frame_test;
friend class ping_test;
- friend class read_test;
+ friend class read1_test;
+ friend class read2_test;
friend class stream_test;
friend class write_test;
-
+
/* The read buffer has to be at least as large
as the largest possible control frame including
the frame header.
@@ -134,36 +144,9 @@ class stream
static std::size_t constexpr max_control_frame_size = 2 + 8 + 4 + 125;
static std::size_t constexpr tcp_frame_size = 1536;
- struct op {};
-
using control_cb_type =
std::function<void(frame_type, string_view)>;
- // tokens are used to order reads and writes
- class token
- {
- unsigned char id_ = 0;
- public:
- token() = default;
- token(token const&) = default;
- explicit token(unsigned char id) : id_(id) {}
- operator bool() const { return id_ != 0; }
- bool operator==(token const& t) { return id_ == t.id_; }
- bool operator!=(token const& t) { return id_ != t.id_; }
- token unique() { token t{id_++}; if(id_ == 0) ++id_; return t; }
- void reset() { id_ = 0; }
- };
-
- // State information for the permessage-deflate extension
- struct pmd_t
- {
- // `true` if current read message is compressed
- bool rd_set = false;
-
- zlib::deflate_stream zo;
- zlib::inflate_stream zi;
- };
-
enum class status
{
open,
@@ -183,8 +166,7 @@ class stream
std::uint64_t rd_remain_ // message frame bytes left in current frame
= 0;
detail::frame_header rd_fh_; // current frame header
- detail::prepared_key rd_key_ // current stateful mask key
- = 0;
+ detail::prepared_key rd_key_; // current stateful mask key
detail::frame_buffer rd_fb_; // to write control frames (during reads)
detail::utf8_checker rd_utf8_; // to validate utf8
static_buffer<
@@ -197,15 +179,14 @@ class stream
= true;
bool rd_close_ // did we read a close frame?
= false;
- token rd_block_; // op currenly reading
+ detail::soft_mutex rd_block_; // op currently reading
- token tok_; // used to order asynchronous ops
role_type role_ // server or client
= role_type::client;
status status_
= status::closed;
- token wr_block_; // op currenly writing
+ detail::soft_mutex wr_block_; // op currently writing
bool wr_close_ // did we write a close frame?
= false;
bool wr_cont_ // next write is a continuation
@@ -231,21 +212,20 @@ class stream
detail::pausation paused_wr_; // paused write op
detail::pausation paused_ping_; // paused ping op
detail::pausation paused_close_; // paused close op
- detail::pausation paused_r_rd_; // paused read op (read)
- detail::pausation paused_r_close_;// paused close op (read)
-
- std::unique_ptr<pmd_t> pmd_; // pmd settings or nullptr
- permessage_deflate pmd_opts_; // local pmd options
- detail::pmd_offer pmd_config_; // offer (client) or negotiation (server)
+ detail::pausation paused_r_rd_; // paused read op (async read)
+ detail::pausation paused_r_close_;// paused close op (async read)
public:
+ /// Indicates if the permessage-deflate extension is supported
+ using is_deflate_supported =
+ std::integral_constant<bool, deflateSupported>;
+
/// The type of the next layer.
using next_layer_type =
typename std::remove_reference<NextLayer>::type;
/// The type of the lowest layer.
- using lowest_layer_type =
- typename get_lowest_layer<next_layer_type>::type;
+ using lowest_layer_type = get_lowest_layer<next_layer_type>;
/// The type of the executor associated with the object.
using executor_type = typename next_layer_type::executor_type;
@@ -444,7 +424,11 @@ public:
*/
std::size_t
read_size_hint(
- std::size_t initial_size = +tcp_frame_size) const;
+ std::size_t initial_size = +tcp_frame_size) const
+ {
+ return read_size_hint(initial_size,
+ is_deflate_supported{});
+ }
/** Returns a suggested maximum buffer size for the next call to read.
@@ -475,15 +459,22 @@ public:
//
//--------------------------------------------------------------------------
- /// Set the permessage-deflate extension options
+ /** Set the permessage-deflate extension options
+
+ @throws invalid_argument if `deflateSupported == false`, and either
+ `client_enable` or `server_enable` is `true`.
+ */
void
- set_option(permessage_deflate const& o);
+ set_option(permessage_deflate const& o)
+ {
+ set_option(o, is_deflate_supported{});
+ }
/// Get the permessage-deflate extension options
void
get_option(permessage_deflate& o)
{
- o = pmd_opts_;
+ get_option(o, is_deflate_supported{});
}
/** Set the automatic fragmentation option.
@@ -580,27 +571,26 @@ public:
string_view payload // The payload in the frame
);
@endcode
- The implementation type-erases the callback without requiring
- a dynamic allocation. For this reason, the callback object is
- passed by a non-constant reference.
+ The implementation type-erases the callback which may require
+ a dynamic allocation. To prevent the possiblity of a dynamic
+ allocation, use `std::ref` to wrap the callback.
If the read operation which receives the control frame is
an asynchronous operation, the callback will be invoked using
the same method as that used to invoke the final handler.
- @note It is not necessary to send a close frame upon receipt
- of a close frame. The implementation does this automatically.
- Attempting to send a close frame after a close frame is
- received will result in undefined behavior.
+ @note Incoming ping and close frames are automatically
+ handled. Pings are responded to with pongs, and a close frame
+ is responded to with a close frame leading to the closure of
+ the stream. It is not necessary to manually send pings, pongs,
+ or close frames from inside the control callback.
+ Attempting to manually send a close frame from inside the
+ control callback after receiving a close frame will result
+ in undefined behavior.
*/
- template<class Callback>
void
- control_callback(Callback& cb)
+ control_callback(std::function<void(frame_type, string_view)> cb)
{
- // Callback may not be constant, caller is responsible for
- // managing the lifetime of the callback. Copies are not made.
- BOOST_STATIC_ASSERT(! std::is_const<Callback>::value);
-
- ctrl_cb_ = std::ref(cb);
+ ctrl_cb_ = std::move(cb);
}
/** Reset the control frame callback.
@@ -1183,9 +1173,9 @@ public:
required by the HTTP protocol. Copies of this parameter may
be made as needed.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -1235,9 +1225,9 @@ public:
required by the HTTP protocol. Copies of this parameter may
be made as needed.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -1293,9 +1283,9 @@ public:
request_type& req
); @endcode
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -1355,9 +1345,9 @@ public:
request_type& req
); @endcode
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -1930,9 +1920,9 @@ public:
@ref http::read or @ref http::async_read, then call @ref accept
or @ref async_accept with the request.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -1991,9 +1981,9 @@ public:
response_type& res
); @endcode
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -2054,9 +2044,9 @@ public:
then to received WebSocket frames. The implementation will
copy the caller provided data before the function returns.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -2132,9 +2122,9 @@ public:
response_type& res
); @endcode
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -2193,9 +2183,9 @@ public:
Ownership is not transferred, the implementation will not access
this object from other threads.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -2256,9 +2246,9 @@ public:
response_type& res
); @endcode
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec // Result of operation
); @endcode
@@ -2358,8 +2348,8 @@ public:
next layer'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 (such as @ref async_ping,
- @ref stream::async_write, @ref stream::async_write_some, or
- @ref stream::async_close) until this operation completes.
+ @ref async_write, @ref async_write_some, or @ref async_close)
+ until this operation completes.
If the close reason specifies a close code other than
@ref beast::websocket::close_code::none, the close frame is
@@ -2373,9 +2363,9 @@ public:
@param cr The reason for the close.
- @param handler The handler to be called when the close operation
- completes. Copies will be made of the handler as required. The
- function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The function signature of the handler must be:
@code
void handler(
error_code const& ec // Result of operation
@@ -2451,9 +2441,9 @@ public:
@param payload The payload of the ping message, which may be empty.
- @param handler The handler to be called when the read operation
- completes. Copies will be made of the handler as required. The
- function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The function signature of the handler must be:
@code
void handler(
error_code const& ec // Result of operation
@@ -2544,9 +2534,9 @@ public:
@param payload The payload of the pong message, which may be empty.
- @param handler The handler to be called when the read operation
- completes. Copies will be made of the handler as required. The
- function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The function signature of the handler must be:
@code
void handler(
error_code const& ec // Result of operation
@@ -2702,9 +2692,9 @@ public:
any masking or decompression has been applied. This object must
remain valid until the handler is called.
- @param handler The handler to be called when the read operation
- completes. Copies will be made of the handler as required. The
- equivalent function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code
void handler(
error_code const& ec, // Result of operation
@@ -2882,9 +2872,9 @@ public:
will append into the buffer. If this value is zero, then a reasonable
size will be chosen automatically.
- @param handler The handler to be called when the read operation
- completes. Copies will be made of the handler as required. The
- equivalent function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code
void handler(
error_code const& ec, // Result of operation
@@ -3055,9 +3045,9 @@ public:
locations pointed to by the buffer sequence remains valid
until the completion handler is called.
- @param handler The handler to be called when the read operation
- completes. Copies will be made of the handler as required. The
- equivalent function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code
void handler(
error_code const& ec, // Result of operation
@@ -3177,8 +3167,8 @@ public:
to the next layer'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 (such as
- stream::async_write, stream::async_write_some, or
- stream::async_close).
+ @ref async_write, @ref async_write_some, or
+ @ref async_close).
The current setting of the @ref binary option controls
whether the message opcode is set to text or binary. If the
@@ -3193,9 +3183,9 @@ public:
the memory locations pointed to by buffers remains valid
until the completion handler is called.
- @param handler The handler to be called when the write operation
- completes. Copies will be made of the handler as required. The
- function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The function signature of the handler must be:
@code
void handler(
error_code const& ec, // Result of operation
@@ -3306,8 +3296,8 @@ public:
as a <em>composed operation</em>. The actual payload sent
may be transformed as per the WebSocket protocol settings. The
program must ensure that the stream performs no other write
- operations (such as stream::async_write, stream::async_write_some,
- or stream::async_close).
+ operations (such as @ref async_write, @ref async_write_some,
+ or @ref async_close).
If this is the beginning of a new message, the message opcode
will be set to text or binary as per the current setting of
@@ -3323,9 +3313,9 @@ public:
the caller, which must guarantee that they remain valid until
the handler is called.
- @param handler The handler to be called when the write completes.
- Copies will be made of the handler as required. The equivalent
- function signature of the handler must be:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& ec, // Result of operation
std::size_t bytes_transferred // Number of bytes written from the
@@ -3343,10 +3333,8 @@ public:
private:
template<class, class> class accept_op;
template<class> class close_op;
- template<class> class fail_op;
template<class> class handshake_op;
template<class> class ping_op;
- template<class> class read_fh_op;
template<class, class> class read_some_op;
template<class, class> class read_op;
template<class> class response_op;
@@ -3356,10 +3344,65 @@ private:
static void default_decorate_req(request_type&) {}
static void default_decorate_res(response_type&) {}
+ void
+ set_option(permessage_deflate const& o, std::true_type);
+
+ void
+ set_option(permessage_deflate const&, std::false_type);
+
+ void
+ get_option(permessage_deflate& o, std::true_type)
+ {
+ o = this->pmd_opts_;
+ }
+
+ void
+ get_option(permessage_deflate& o, std::false_type)
+ {
+ o = {};
+ o.client_enable = false;
+ o.server_enable = false;
+ }
+
void open(role_type role);
+
+ void open_pmd(std::true_type);
+
+ void open_pmd(std::false_type)
+ {
+ }
+
void close();
+
+ void close_pmd(std::true_type)
+ {
+ this->pmd_.reset();
+ }
+
+ void close_pmd(std::false_type)
+ {
+ }
+
void reset();
- void begin_msg();
+
+ void begin_msg()
+ {
+ begin_msg(is_deflate_supported{});
+ }
+
+ void begin_msg(std::true_type);
+
+ void begin_msg(std::false_type);
+
+ std::size_t
+ read_size_hint(
+ std::size_t initial_size,
+ std::true_type) const;
+
+ std::size_t
+ read_size_hint(
+ std::size_t initial_size,
+ std::false_type) const;
bool
check_open(error_code& ec)
@@ -3387,8 +3430,10 @@ private:
template<class DynamicBuffer>
bool
- parse_fh(detail::frame_header& fh,
- DynamicBuffer& b, close_code& code);
+ parse_fh(
+ detail::frame_header& fh,
+ DynamicBuffer& b,
+ error_code& ec);
template<class DynamicBuffer>
void
@@ -3399,6 +3444,10 @@ private:
write_ping(DynamicBuffer& b,
detail::opcode op, ping_data const& data);
+ //
+ // upgrade
+ //
+
template<class Decorator>
request_type
build_request(detail::sec_ws_key_type& key,
@@ -3406,28 +3455,95 @@ private:
string_view target,
Decorator const& decorator);
- template<class Body,
- class Allocator, class Decorator>
+ void
+ build_request_pmd(request_type& req, std::true_type);
+
+ void
+ build_request_pmd(request_type&, std::false_type)
+ {
+ }
+
+ template<
+ class Body, class Allocator, class Decorator>
response_type
- build_response(http::request<Body,
- http::basic_fields<Allocator>> const& req,
- Decorator const& decorator);
+ build_response(
+ http::request<Body,
+ http::basic_fields<Allocator>> const& req,
+ Decorator const& decorator,
+ error_code& ec);
+ template<class Body, class Allocator>
void
- on_response(response_type const& resp,
- detail::sec_ws_key_type const& key, error_code& ec);
+ build_response_pmd(
+ response_type& res,
+ http::request<Body,
+ http::basic_fields<Allocator>> const& req,
+ std::true_type);
+
+ template<class Body, class Allocator>
+ void
+ build_response_pmd(
+ response_type&,
+ http::request<Body,
+ http::basic_fields<Allocator>> const&,
+ std::false_type)
+ {
+ }
+
+ void
+ on_response(
+ response_type const& res,
+ detail::sec_ws_key_type const& key,
+ error_code& ec);
+
+ void
+ on_response_pmd(
+ response_type const& res,
+ std::true_type);
+
+ void
+ on_response_pmd(
+ response_type const&,
+ std::false_type)
+ {
+ }
+
+ //
+ // accept / handshake
+ //
+
+ template<class Allocator>
+ void
+ do_pmd_config(
+ http::basic_fields<Allocator> const& h,
+ std::true_type)
+ {
+ pmd_read(this->pmd_config_, h);
+ }
+
+ template<class Allocator>
+ void
+ do_pmd_config(
+ http::basic_fields<Allocator> const&,
+ std::false_type)
+ {
+ }
template<class Decorator>
void
- do_accept(Decorator const& decorator,
+ do_accept(
+ Decorator const& decorator,
error_code& ec);
- template<class Body, class Allocator,
+ template<
+ class Body, class Allocator,
class Decorator>
void
- do_accept(http::request<Body,
- http::basic_fields<Allocator>> const& req,
- Decorator const& decorator, error_code& ec);
+ do_accept(
+ http::request<Body,
+ http::basic_fields<Allocator>> const& req,
+ Decorator const& decorator,
+ error_code& ec);
template<class RequestDecorator>
void
@@ -3436,6 +3552,10 @@ private:
RequestDecorator const& decorator,
error_code& ec);
+ //
+ // fail
+ //
+
void
do_fail(
std::uint16_t code,
diff --git a/boost/beast/websocket/stream_fwd.hpp b/boost/beast/websocket/stream_fwd.hpp
new file mode 100644
index 0000000000..97ffcb49ed
--- /dev/null
+++ b/boost/beast/websocket/stream_fwd.hpp
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2016-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)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+#ifndef BOOST_BEAST_WEBSOCKET_STREAM_FWD_HPP
+#define BOOST_BEAST_WEBSOCKET_STREAM_FWD_HPP
+
+#include <boost/beast/core/detail/config.hpp>
+
+namespace boost {
+namespace beast {
+namespace websocket {
+
+template<
+ class NextLayer,
+ bool deflateSupported = true>
+class stream;
+
+} // websocket
+} // beast
+} // boost
+
+#endif
diff --git a/boost/beast/websocket/teardown.hpp b/boost/beast/websocket/teardown.hpp
index 289b57c853..a255756dad 100644
--- a/boost/beast/websocket/teardown.hpp
+++ b/boost/beast/websocket/teardown.hpp
@@ -69,9 +69,9 @@ teardown(
@param socket The socket to tear down.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& error // result of operation
);
@@ -145,9 +145,9 @@ teardown(
@param socket The socket to tear down.
- @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:
+ @param handler Invoked when the operation completes.
+ The handler may be moved or copied as needed.
+ The equivalent function signature of the handler must be:
@code void handler(
error_code const& error // result of operation
);
diff --git a/boost/beast/zlib/detail/inflate_stream.hpp b/boost/beast/zlib/detail/inflate_stream.hpp
index 57be172387..4b40ae11a4 100644
--- a/boost/beast/zlib/detail/inflate_stream.hpp
+++ b/boost/beast/zlib/detail/inflate_stream.hpp
@@ -380,12 +380,12 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
mode_ = COPY_;
if(flush == Flush::trees)
return done();
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case COPY_:
mode_ = COPY;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case COPY:
{
@@ -419,7 +419,7 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
return err(error::too_many_symbols);
have_ = 0;
mode_ = LENLENS;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case LENLENS:
{
@@ -447,7 +447,7 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
}
have_ = 0;
mode_ = CODELENS;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case CODELENS:
@@ -536,12 +536,12 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
mode_ = LEN_;
if(flush == Flush::trees)
return done();
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case LEN_:
mode_ = LEN;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case LEN:
{
@@ -594,7 +594,7 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
return err(error::invalid_literal_length);
extra_ = cp->op & 15;
mode_ = LENEXT;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case LENEXT:
@@ -609,7 +609,7 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
}
was_ = length_;
mode_ = DIST;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case DIST:
{
@@ -638,7 +638,7 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
offset_ = cp->val;
extra_ = cp->op & 15;
mode_ = DISTEXT;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
}
case DISTEXT:
@@ -656,7 +656,7 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
return err(error::invalid_distance);
#endif
mode_ = MATCH;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case MATCH:
{
@@ -701,7 +701,7 @@ doWrite(z_params& zs, Flush flush, error_code& ec)
case CHECK:
mode_ = DONE;
- BOOST_BEAST_FALLTHROUGH;
+ BOOST_FALLTHROUGH;
case DONE:
ec = error::end_of_stream;