diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj
index daabd699a..ea09ebfb5 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj
+++ b/Builds/VisualStudio2015/RippleD.vcxproj
@@ -284,6 +284,8 @@
+
+
@@ -312,10 +314,14 @@
+
+
+
+
@@ -494,6 +500,10 @@
True
True
+
+ True
+ True
+
@@ -527,6 +537,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+
+
+ True
+ True
+
+
+
+
+
+
+
+
+
@@ -3423,6 +3501,10 @@
+
+
+
+
True
True
@@ -3439,6 +3521,8 @@
+
+
True
True
@@ -3461,6 +3545,8 @@
+
+
@@ -3485,6 +3571,8 @@
+
+
@@ -3905,10 +3993,6 @@
-
-
-
-
True
diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters
index f47515c7e..bfd80c81d 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters
@@ -79,6 +79,21 @@
{2762284D-66E5-8B48-1F8E-67116DB1FC6B}
+
+ {53D8D640-BEB0-1F2C-61D4-5459CDAC7EB4}
+
+
+ {E8E91EF5-9155-8F58-4249-3EF221768BCE}
+
+
+ {63AB4C85-5B2E-B2A7-9E4F-9F0899402D1D}
+
+
+ {E5986CF5-37A8-1EE5-1085-645EBEE517B6}
+
+
+ {28A822FF-4532-9678-23F2-D844CB0FE207}
+
{65697F48-7FC6-2A4B-DB6C-56781F3990B5}
@@ -376,9 +391,6 @@
{44780F86-42D3-2F2B-0846-5AEE2CA6D7FE}
-
- {1D54E820-ADC9-94FB-19E7-653EFDE4CBE9}
-
{15B4B65A-0F03-7BA9-38CD-42A5712392CB}
@@ -606,6 +618,9 @@
beast\asio
+
+ beast\asio
+
beast\asio
@@ -642,12 +657,18 @@
beast\crypto\detail
+
+ beast\crypto\detail
+
beast\crypto
beast\crypto
+
+ beast\crypto
+
beast\crypto
@@ -864,6 +885,9 @@
beast\unity
+
+ beast\unity
+
beast
@@ -912,6 +936,102 @@
beast\unit_test
+
+ beast
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto\detail
+
+
+ beast\wsproto
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto\impl
+
+
+ beast\wsproto
+
+
+ beast\wsproto
+
+
+ beast\wsproto
+
+
+ beast\wsproto\src\test
+
+
+ beast\wsproto\src\test
+
+
+ beast\wsproto\src\test
+
+
+ beast\wsproto\src\test
+
+
+ beast\wsproto
+
+
+ beast\wsproto
+
+
+ beast\wsproto
+
beast
@@ -3834,6 +3954,12 @@
ripple\server\impl
+
+ ripple\server\impl
+
+
+ ripple\server\impl
+
ripple\server\impl
@@ -3852,6 +3978,9 @@
ripple\server\impl
+
+ ripple\server\impl
+
ripple\server\impl
@@ -3873,6 +4002,9 @@
ripple\server\impl
+
+ ripple\server\impl
+
ripple\server
@@ -3906,6 +4038,9 @@
ripple\server
+
+ ripple\server
+
ripple\shamap
@@ -4311,12 +4446,6 @@
ripple\websocket
-
- ripple\wsproto
-
-
- ripple\wsproto
-
rocksdb2\db
diff --git a/SConstruct b/SConstruct
index bb16b673e..ca6c95f28 100644
--- a/SConstruct
+++ b/SConstruct
@@ -907,6 +907,7 @@ def get_classic_sources(toolchain):
append_sources(result, *list_sources('src/beast/beast/http/src', '.cpp'))
append_sources(result, *list_sources('src/beast/beast/streams', '.cpp'))
append_sources(result, *list_sources('src/beast/beast/test', '.cpp'))
+ append_sources(result, *list_sources('src/beast/beast/wsproto/src', '.cpp'))
append_sources(result, *list_sources('src/ripple/beast/container', '.cpp'))
append_sources(result, *list_sources('src/ripple/beast/insight', '.cpp'))
append_sources(result, *list_sources('src/ripple/beast/net', '.cpp'))
@@ -957,6 +958,7 @@ def get_unity_sources(toolchain):
'src/beast/beast/unity/beast_http_unity.cpp',
'src/beast/beast/unity/beast_streams_unity.cpp',
'src/beast/beast/unity/beast_test_unity.cpp',
+ 'src/beast/beast/unity/beast_wsproto_unity.cpp',
'src/ripple/beast/unity/beast_container_unity.cpp',
'src/ripple/beast/unity/beast_insight_unity.cpp',
'src/ripple/beast/unity/beast_net_unity.cpp',
diff --git a/src/beast/Jamroot b/src/beast/Jamroot
index e18ad6b7d..aed04ce28 100644
--- a/src/beast/Jamroot
+++ b/src/beast/Jamroot
@@ -34,7 +34,16 @@ else if [ os.name ] = HAIKU
lib network ;
}
-build-project test/asio ;
+if [ os.name ] = NT
+{
+ lib ssl : : ssleay32 ;
+ lib crypto : : libeay32 ;
+}
+else
+{
+ lib ssl ;
+ lib crypto ;
+}
project beast
: requirements
@@ -49,6 +58,8 @@ project beast
multi
static
static
+ gcc:-std=c++14
+ clang:-std=c++14
LINUX:_XOPEN_SOURCE=600
LINUX:_GNU_SOURCE=1
SOLARIS:_XOPEN_SOURCE=500
@@ -68,7 +79,10 @@ project beast
msvc:_SCL_SECURE_NO_WARNINGS=1
msvc:_CRT_SECURE_NO_WARNINGS=1
: usage-requirements
- .
+ .
:
build-dir bin
;
+
+build-project test ;
+build-project examples ;
diff --git a/src/beast/TODO.txt b/src/beast/TODO.txt
new file mode 100644
index 000000000..d5767cb80
--- /dev/null
+++ b/src/beast/TODO.txt
@@ -0,0 +1,8 @@
+* kick out non-beast code
+
+* redo directory structure
+
+* Change build options to C++11 only
+
+* Replace Jamroot with Jamfile
+
diff --git a/src/beast/beast/asio/buffers_debug.h b/src/beast/beast/asio/buffers_debug.h
index 19689c372..e53617996 100644
--- a/src/beast/beast/asio/buffers_debug.h
+++ b/src/beast/beast/asio/buffers_debug.h
@@ -27,7 +27,6 @@ namespace beast {
namespace debug {
template
-static
std::string
buffers_to_string(Buffers const& bs)
{
diff --git a/src/ripple/wsproto/wsproto.h b/src/beast/beast/unity/beast_wsproto_unity.cpp
similarity index 78%
rename from src/ripple/wsproto/wsproto.h
rename to src/beast/beast/unity/beast_wsproto_unity.cpp
index 2f8d326dd..c41bd2ac6 100644
--- a/src/ripple/wsproto/wsproto.h
+++ b/src/beast/beast/unity/beast_wsproto_unity.cpp
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2016 Ripple Labs Inc.
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -17,9 +17,5 @@
*/
//==============================================================================
-#ifndef RIPPLE_WSPROTO_H_INCLUDED
-#define RIPPLE_WSPROTO_H_INCLUDED
-
-#include
-
-#endif
+#include
+#include
diff --git a/src/beast/beast/wsproto.h b/src/beast/beast/wsproto.h
new file mode 100644
index 000000000..542b308a3
--- /dev/null
+++ b/src/beast/beast/wsproto.h
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_H_INCLUDED
+#define BEAST_WSPROTO_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#endif
diff --git a/src/beast/beast/wsproto/README.md b/src/beast/beast/wsproto/README.md
new file mode 100644
index 000000000..22fc6a518
--- /dev/null
+++ b/src/beast/beast/wsproto/README.md
@@ -0,0 +1,232 @@
+# Beast.WSProto
+
+--------------------------------------------------------------------------------
+
+Beast.WSProto provides developers with a robust WebSocket implementation
+built on Boost.Asio with a consistent asynchronous model using a modern
+C++ approach.
+
+## Introduction
+
+Today's web applications increasingly rely on alternatives to standard HTTP
+to achieve performance and/or responsiveness. While WebSocket implementations
+are widely available in common web development languages such as Javascript,
+good implementations in C++ are scarce. A survey of existing C++ WebSocket
+solutions reveals interfaces which have performance limitations, place
+unecessary restrictions on callers, exhibit excess complexity, and fail to
+take advantage of C++ features or the underlying network transport.
+
+Beast.WSProto is built on Boost.Asio, a robust cross platform networking
+framework that is part of Boost and also offered as a standalone library.
+A proposal to add networking functionality to the C++ standard library,
+based on Boost.Asio, is under consideration by the standards committee.
+Since the final approved networking interface for the C++ standard library
+will likely closely resemble the current interface of Boost.Asio, it is
+logical for Beast.WSProto to use Boost.Asio as its network transport.
+
+Beast.WSProto addresses the following goals:
+
+* **Ease of Use.** WSProto offers only one socket object, whose interface
+resembles that of Boost.Asio socket as closely as possible. Users familiar
+with Boost.Asio will be immediately comfortable using a `wsproto::socket`.
+
+* **Flexibility.** Library interfaces should provide callers with maximum
+flexibility in implementation; Important decisions such as how to manage
+buffers or be notified of completed asynchronous operations should be made
+by callers not the library.
+
+* **Performance.** The implementation should achieve the highest level
+of performance possible, with no penalty for using abstractions.
+
+* **Scalability.** The library should facilitate the development of
+network applications that scale to thousands of concurrent connections.
+
+* **Efficiency.** The library should support techniques such as
+scatter-gather I/O, and allow programs to minimise data copying.
+
+* **Basis for further abstraction.** The library should permit the
+development of other libraries that provide higher levels of abstraction.
+
+Beast.WSProto takes advantage of Boost.Asio's universal Asynchronous
+model, handler allocation, and handler invocation hooks. Calls to wsproto
+asynchronous initiation functions allow callers the choice of using a
+completion handler, stackful or stackless coroutines, futures, or user
+defined customizations (for example, Boost.Fiber). The implementation
+uses handler invocation hooks (`asio_handler_invoke`), providing
+execution guarantees on composed operations in a manner identical to
+Boost.Asio. The implementation also uses handler allocation hooks
+(`asio_handler_allocate`) when allocating memory internally for composed
+operations.
+
+There is no need for inheritance or virtual members in `wsproto::socket`.
+All operations are templated and transparent to the compiler, allowing for
+maximum inlining and optimization.
+
+## Usage
+
+All examples and identifiers mentioned in this document are written as
+if the following declarations are in effect:
+```C++
+#include
+using namespace beast;
+using namespace boost::asio;
+```
+
+### Creating a Socket
+
+To participate in a WebSocket connection, callers create an instance
+of `wsproto::socket` templated on the `Stream` argument, which must meet
+the requirements of `AsyncReadStream`, `AsyncWriteStream`, `SyncReadStream`,
+and `SyncWriteStream`. Examples of types that meet these requirements are
+`ip::tcp::socket` and `ssl::stream<...>`:
+```c++
+io_service ios;
+wsproto::socket ws1(ios); // owns the socket
+
+ssl::context ctx(ssl::context::sslv23);
+wsproto::socket> wss(ios, ctx); // owns the socket
+
+ip::tcp::socket sock(ios);
+wsproto::socket ws2(sock); // does not own the socket
+```
+
+### Connection Establishment
+
+Callers are responsible for performing tasks such as connection establishment
+before attempting websocket activities.
+```c++
+io_service ios;
+wsproto::socket ws(ios);
+ws.next_layer().connect(ip::tcp::endpoint(
+ ip::tcp::address::from_string("127.0.0.1"), 80));
+```
+
+### WebSocket Handshake
+
+After the connection is established, the socket may be used to initiate
+or accept a WebSocket Update request.
+
+```c++
+// send a WebSocket Upgrade request.
+ws.handshake();
+```
+
+### Sending and Receiving Messages
+
+After the WebSocket handshake is accomplished, callers may send and receive
+messages using the message oriented interface:
+```c++
+void echo(wsproto::socket& ws)
+{
+ streambuf sb;
+ wsproto::opcode op;
+ wsproto::read(ws, op, sb);
+ wsproto::write(ws, op, sb.data());
+ sb.consume(sb.size());
+}
+```
+
+Alternatively, callers may process incoming message data
+incrementally:
+```c++
+void echo(wsproto::socket& ws)
+{
+ streambuf sb;
+ wsproto::msg_info mi{};
+ for(;;)
+ {
+ ws.read_some(mi, sb);
+ if(mi.fin)
+ break;
+ }
+ wsproto::write(ws, op, sb.data());
+}
+```
+
+### Asynchronous Completions, Coroutines, and Futures
+
+Asynchronous versions are available for all functions:
+```c++
+wsproto::async_read(ws, sb, std::bind(
+ &on_read, beast::asio::placeholders::error));
+```
+
+Calls to WSProto asynchronous initiation functions support
+asio-style completion handlers, and other completion tokens
+such as support for coroutines or futures:
+```c++
+void echo(wsproto::socket& ws,
+ boost::asio::yield_context yield)
+{
+ wsproto::async_read(ws, sb, yield);
+ std::future fut =
+ wsproto::async_write(ws, sb.data(), boost::use_future);
+ ...
+}
+```
+
+## Implementation
+
+### Buffers
+
+Because calls to read WebSocket data may return a variable amount of bytes,
+the interface to calls that read data require an object that meets the
+requirements of `Streambuf`. This concept is modeled on
+`boost::asio::basic_streambuf`, which meets the requirements of `Streambuf`
+defined below.
+
+The `Streambuf` concept is intended to permit the following implementation
+strategies:
+
+* A single contiguous character array, which is reallocated as necessary to
+ accommodate changes in the size of the byte sequence. This is the
+ implementation approach currently used in `boost::asio::basic_streambuf`.
+* A sequence of one or more byte arrays, where each array is of the same
+ size. Additional byte array objects are appended to the sequence to
+ accommodate changes in the size of the byte sequence.
+* A sequence of one or more byte arrays of varying sizes. Additional byte
+ array objects are appended to the sequence to accommodate changes in the
+ size of the byte sequence. This is the implementation approach currently
+ used in `beast::basic_streambuf`.
+
+#### `Streambuf` requirements:
+
+In the table below, `X` denotes a class, `a` denotes a value
+of type `X`, `n` denotes a value convertible to `std::size_t`,
+and `U` and `T` denote unspecified types.
+
+expression | return | type assertion/note/pre/post-condition
+------------------------- | ------------- | --------------------------------------
+`X::const_buffers_type` | `T` | `T` meets the requirements for `ConstBufferSequence`.
+`X::mutable_buffers_type` | `U` | `U` meets the requirements for `MutableBufferSequence`.
+`a.commit(n)` | | Moves bytes from the output sequence to the input sequence.
+`a.consume(n)` | | Removes bytes from the input sequence.
+`a.data()` | `T` | Returns a list of buffers that represents the input sequence.
+`a.prepare(n)` | `U` | Returns a list of buffers that represents the output sequence, with the given size.
+`a.size()` | `std::size_t` | Returns the size of the input sequence.
+`a.max_size()` | `std::size_t` | Returns the maximum size of the `Streambuf`.
+
+### Thread Safety
+
+Like a regular asio socket, a `wsproto::socket` is not thread safe. Callers are
+responsible for synchronizing operations on the socket using an implicit or
+explicit strand, as per the Asio documentation. A `wsproto::socket` supports
+one active read and one active write at the same time (caller initiated close,
+ping, and pong operations count as a write).
+
+### Buffering
+
+The implementation does not perform queueing or buffering of messages. If desired,
+these features should be implemented by callers. The impact of this design is
+that the caller is in full control of the allocation strategy used to store
+data and the back-pressure applied on the read and write side of the underlying
+TCP/IP connection.
+
+### The `io_service`
+
+The creation and operation of the `boost::asio::io_service` associated with the
+Stream object underlying the `wsproto::socket` is completely left up to the
+user of the library, permitting any implementation strategy including one that
+does not require threads for environments where threads are unavailable.
+Beast.WSProto itself does not use or require threads.
diff --git a/src/beast/beast/wsproto/detail/debug.h b/src/beast/beast/wsproto/detail/debug.h
new file mode 100644
index 000000000..a3696c9ff
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/debug.h
@@ -0,0 +1,88 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_DEBUG_H_INCLUDED
+#define BEAST_WSPROTO_DEBUG_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+template
+std::string
+to_hex(boost::asio::const_buffer b)
+{
+ using namespace boost::asio;
+ std::stringstream ss;
+ auto p = buffer_cast(b);
+ auto n = buffer_size(b);
+ while(n--)
+ {
+ ss <<
+ std::setfill('0') <<
+ std::setw(2) <<
+ std::hex << int(*p++) << " ";
+ }
+ return ss.str();
+}
+
+template
+std::string
+to_hex(Buffers const& bs)
+{
+ std::string s;
+ for(auto const& b : bs)
+ s.append(to_hex(boost::asio::const_buffer(b)));
+ return s;
+}
+
+template
+std::string
+buffers_to_string(Buffers const& bs)
+{
+ using namespace boost::asio;
+ std::string s;
+ s.reserve(buffer_size(bs));
+ for(auto const& b : bs)
+ s.append(buffer_cast(b),
+ buffer_size(b));
+ return s;
+}
+
+template
+std::string
+format(std::string s)
+{
+ auto const w = 84;
+ for(int n = w*(s.size()/w); n>0; n-=w)
+ s.insert(n, 1, '\n');
+ return s;
+}
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/decorator.h b/src/beast/beast/wsproto/detail/decorator.h
new file mode 100644
index 000000000..7078849cf
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/decorator.h
@@ -0,0 +1,112 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_DECORATOR_H_INCLUDED
+#define BEAST_WSPROTO_DECORATOR_H_INCLUDED
+
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+using request_type = http::request;
+
+using response_type = http::response;
+
+struct abstract_decorator
+{
+ virtual
+ ~abstract_decorator() = default;
+
+ virtual
+ void
+ operator()(request_type& req) = 0;
+
+ virtual
+ void
+ operator()(response_type& resp) = 0;
+};
+
+template
+class decorator : public abstract_decorator
+{
+ T t_;
+
+public:
+ decorator() = default;
+
+ decorator(T&& t)
+ : t_(std::move(t))
+ {
+ }
+
+ decorator(T const& t)
+ : t_(t)
+ {
+ }
+
+ void
+ operator()(request_type& req) override
+ {
+ t_(req);
+ }
+
+ void
+ operator()(response_type& resp) override
+ {
+ t_(resp);
+ }
+};
+
+struct default_decorator
+{
+ static
+ char const*
+ version()
+ {
+ return "Beast.WSProto/1.0";
+ }
+
+ template
+ void
+ operator()(http::message& req)
+ {
+ req.headers.replace("User-Agent", version());
+ }
+
+ template
+ void
+ operator()(http::message& resp)
+ {
+ resp.headers.replace("Server", version());
+ }
+};
+
+using decorator_type =
+ std::unique_ptr;
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/error.h b/src/beast/beast/wsproto/detail/error.h
new file mode 100644
index 000000000..f19e1bc03
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/error.h
@@ -0,0 +1,104 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_DETAIL_ERROR_H_INCLUDED
+#define BEAST_WSPROTO_DETAIL_ERROR_H_INCLUDED
+
+#include
+
+namespace boost {
+namespace system {
+template<>
+struct is_error_code_enum
+{
+ static bool const value = true;
+};
+} // system
+} // boost
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+class error_category : public boost::system::error_category
+{
+public:
+ const char*
+ name() const noexcept override
+ {
+ return "wsproto";
+ }
+
+ std::string
+ message(int ev) const override
+ {
+ switch(static_cast(ev))
+ {
+ case error::closed: return "WebSocket connection closed normally";
+ case error::failed: return "WebSocket connection failed due to a protocol violation";
+ case error::handshake_failed: return "WebSocket Upgrade handshake failed";
+ case error::keep_alive: return "WebSocket Upgrade handshake failed but connection is still open";
+
+ case error::response_malformed: return "malformed HTTP response";
+ case error::response_failed: return "upgrade request failed";
+ case error::response_denied: return "upgrade request denied";
+ case error::request_malformed: return "malformed HTTP request";
+ case error::request_invalid: return "upgrade request invalid";
+ case error::request_denied: return "upgrade request denied";
+ default:
+ return "wsproto.error";
+ }
+ }
+
+ boost::system::error_condition
+ default_error_condition(int ev) const noexcept override
+ {
+ return boost::system::error_condition(ev, *this);
+ }
+
+ bool
+ equivalent(int ev,
+ boost::system::error_condition const& condition
+ ) const noexcept override
+ {
+ return condition.value() == ev &&
+ &condition.category() == this;
+ }
+
+ bool
+ equivalent(error_code const& error, int ev) const noexcept override
+ {
+ return error.value() == ev &&
+ &error.category() == this;
+ }
+};
+
+inline
+boost::system::error_category const&
+get_error_category()
+{
+ static detail::error_category const cat{};
+ return cat;
+}
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/frame.h b/src/beast/beast/wsproto/detail/frame.h
new file mode 100644
index 000000000..cd9db0780
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/frame.h
@@ -0,0 +1,375 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_FRAME_H_INCLUDED
+#define BEAST_WSPROTO_FRAME_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+// Contents of a WebSocket frame header
+struct frame_header
+{
+ opcode op;
+ bool fin;
+ bool mask;
+ bool rsv1;
+ bool rsv2;
+ bool rsv3;
+ std::uint64_t len;
+ std::uint32_t key;
+};
+
+// holds the largest possible frame header
+using fh_streambuf =
+ static_streambuf_n<14>;
+
+// holds the largest possible control frame
+using frame_streambuf =
+ static_streambuf_n< 2 + 8 + 4 + 125 >;
+
+inline
+bool constexpr
+is_reserved(opcode op)
+{
+ return
+ (op >= opcode::rsv3 && op <= opcode::rsv7) ||
+ (op >= opcode::crsvb && op <= opcode::crsvf);
+}
+
+inline
+bool constexpr
+is_valid(opcode op)
+{
+ return op <= opcode::crsvf;
+}
+
+inline
+bool constexpr
+is_control(opcode op)
+{
+ return op >= opcode::close;
+}
+
+// Returns `true` if a close code is valid
+inline
+bool
+is_valid(close_code code)
+{
+ auto const v = static_cast<
+ std::uint16_t>(code);
+ switch(v)
+ {
+ case 1000:
+ case 1001:
+ case 1002:
+ case 1003:
+ case 1007:
+ case 1008:
+ case 1009:
+ case 1010:
+ case 1011:
+ case 1012:
+ case 1013:
+ return true;
+
+ // explicitly reserved
+ case 1004:
+ case 1005:
+ case 1006:
+ case 1014:
+ case 1015:
+ return false;
+ }
+ // reserved
+ if(v >= 1016 && v <= 2999)
+ return false;
+ // not used
+ if(v >= 0 && v <= 999)
+ return false;
+ return true;
+}
+
+//------------------------------------------------------------------------------
+
+// Write frame header to streambuf
+//
+template
+void
+write(Streambuf& sb, frame_header const& fh)
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ using namespace boost::endian;
+ std::size_t n;
+ std::uint8_t b[14];
+ b[0] = (fh.fin ? 0x80 : 0x00) | static_cast(fh.op);
+ b[1] = fh.mask ? 0x80 : 0x00;
+ if (fh.len <= 125)
+ {
+ b[1] |= fh.len;
+ n = 2;
+ }
+ else if (fh.len <= 65535)
+ {
+ b[1] |= 126;
+ ::new(&b[2]) big_uint16_buf_t{
+ (std::uint16_t)fh.len};
+ n = 4;
+ }
+ else
+ {
+ b[1] |= 127;
+ ::new(&b[2]) big_uint64_buf_t{fh.len};
+ n = 10;
+ }
+ if(fh.mask)
+ {
+ little_uint32_buf_t key(fh.key);
+ std::copy(key.data(),
+ key.data() + 4, &b[n]);
+ n += 4;
+ }
+ sb.commit(buffer_copy(
+ sb.prepare(n), buffer(b)));
+}
+
+// Read fixed frame header
+// Requires at least 2 bytes
+//
+template
+std::size_t
+read_fh1(frame_header& fh, Streambuf& sb,
+ role_type role, close_code& code)
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ std::uint8_t b[2];
+ assert(buffer_size(sb.data()) >= sizeof(b));
+ sb.consume(buffer_copy(buffer(b), sb.data()));
+ std::size_t need;
+ fh.len = b[1] & 0x7f;
+ switch(fh.len)
+ {
+ case 126: need = 2; break;
+ case 127: need = 8; break;
+ default:
+ need = 0;
+ }
+ if((fh.mask = (b[1] & 0x80) != 0))
+ need += 4;
+ fh.op = static_cast(b[0] & 0x0f);
+ fh.fin = (b[0] & 0x80) != 0;
+ fh.rsv1 = (b[0] & 0x40) != 0;
+ fh.rsv2 = (b[0] & 0x20) != 0;
+ fh.rsv3 = (b[0] & 0x10) != 0;
+ // invalid length for control message
+ if(is_control(fh.op) && fh.len > 125)
+ {
+ code = close_code::protocol_error;
+ return 0;
+ }
+ // reserved bits not cleared
+ if(fh.rsv1 || fh.rsv2 || fh.rsv3)
+ {
+ code = close_code::protocol_error;
+ return 0;
+ }
+ // reserved opcode
+ if(is_reserved(fh.op))
+ {
+ code = close_code::protocol_error;
+ return 0;
+ }
+ // invalid opcode
+ // (only in locally generated headers)
+ if(! is_valid(fh.op))
+ {
+ code = close_code::protocol_error;
+ return 0;
+ }
+ // fragmented control message
+ if(is_control(fh.op) && ! fh.fin)
+ {
+ code = close_code::protocol_error;
+ return 0;
+ }
+ // unmasked frame from client
+ if(role == role_type::server && ! fh.mask)
+ {
+ code = close_code::protocol_error;
+ return 0;
+ }
+ // masked frame from server
+ if(role == role_type::client && fh.mask)
+ {
+ code = close_code::protocol_error;
+ return 0;
+ }
+ code = close_code::none;
+ return need;
+}
+
+// Decode variable frame header from stream
+//
+template
+void
+read_fh2(frame_header& fh, Streambuf& sb,
+ role_type role, close_code& code)
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ using namespace boost::endian;
+ switch(fh.len)
+ {
+ case 126:
+ {
+ std::uint8_t b[2];
+ assert(buffer_size(sb.data()) >= sizeof(b));
+ sb.consume(buffer_copy(buffer(b), sb.data()));
+ fh.len = reinterpret_cast<
+ big_uint16_buf_t const*>(&b[0])->value();
+ // length not canonical
+ if(fh.len < 126)
+ {
+ code = close_code::protocol_error;
+ return;
+ }
+ break;
+ }
+ case 127:
+ {
+ std::uint8_t b[8];
+ assert(buffer_size(sb.data()) >= sizeof(b));
+ sb.consume(buffer_copy(buffer(b), sb.data()));
+ fh.len = reinterpret_cast<
+ big_uint64_buf_t const*>(&b[0])->value();
+ // length not canonical
+ if(fh.len < 65536)
+ {
+ code = close_code::protocol_error;
+ return;
+ }
+ break;
+ }
+ }
+ if(fh.mask)
+ {
+ std::uint8_t b[4];
+ assert(buffer_size(sb.data()) >= sizeof(b));
+ sb.consume(buffer_copy(buffer(b), sb.data()));
+ fh.key = reinterpret_cast<
+ little_uint32_buf_t const*>(&b[0])->value();
+ }
+ code = close_code::none;
+}
+
+// Read data from buffers
+// This is for ping and pong payloads
+//
+template
+void
+read(ping_payload_type& data,
+ Buffers const& bs, close_code& code)
+{
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ using boost::asio::mutable_buffers_1;
+ assert(buffer_size(bs) <= data.max_size());
+ data.resize(buffer_size(bs));
+ buffer_copy(mutable_buffers_1{
+ data.data(), data.size()}, bs);
+}
+
+// Read close_reason, return true on success
+// This is for the close payload
+//
+template
+void
+read(close_reason& cr,
+ Buffers const& bs, close_code& code)
+{
+ using boost::asio::buffer;
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ using namespace boost::endian;
+ auto n = buffer_size(bs);
+ assert(n <= 125);
+ if(n == 0)
+ {
+ cr = close_reason{};
+ code = close_code::none;
+ return;
+ }
+ if(n == 1)
+ {
+ code = close_code::protocol_error;
+ return;
+ }
+ consuming_buffers cb(bs);
+ {
+ std::uint8_t b[2];
+ buffer_copy(buffer(b), cb);
+ cr.code = static_cast(
+ reinterpret_cast<
+ big_uint16_buf_t const*>(&b[0])->value());
+ cb.consume(2);
+ n -= 2;
+ if(! is_valid(cr.code))
+ {
+ code = close_code::protocol_error;
+ return;
+ }
+ }
+ if(n > 0)
+ {
+ cr.reason.resize(n);
+ buffer_copy(buffer(&cr.reason[0], n), cb);
+ if(! detail::check_utf8(
+ cr.reason.data(), cr.reason.size()))
+ {
+ code = close_code::protocol_error;
+ return;
+ }
+ }
+ else
+ {
+ cr.reason = "";
+ }
+ code = close_code::none;
+}
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/hybi13.h b/src/beast/beast/wsproto/detail/hybi13.h
new file mode 100644
index 000000000..ec7d56559
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/hybi13.h
@@ -0,0 +1,66 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_HYBI13_H_INCLUDED
+#define BEAST_WSPROTO_HYBI13_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+template
+std::string
+make_sec_ws_key(Gen& g)
+{
+ union U
+ {
+ std::array a4;
+ std::array a16;
+ };
+ U u;
+ for(int i = 0; i < 4; ++i)
+ u.a4[i] = g();
+ return base64_encode(u.a16.data(), u.a16.size());
+}
+
+template
+std::string
+make_sec_ws_accept(boost::string_ref const& key)
+{
+ std::string s(key.data(), key.size());
+ s += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ beast::sha_hasher h;
+ h(s.data(), s.size());
+ auto const digest = static_cast<
+ beast::sha_hasher::result_type>(h);
+ return base64_encode(digest.data(), digest.size());
+}
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/invokable.h b/src/beast/beast/wsproto/detail/invokable.h
new file mode 100644
index 000000000..140246893
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/invokable.h
@@ -0,0 +1,168 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_INVOKABLE_H_INCLUDED
+#define BEAST_WSPROTO_INVOKABLE_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+// "Parks" a composed operation, to invoke later
+//
+class invokable
+{
+ struct base
+ {
+ base() = default;
+ base(base &&) = default;
+ virtual ~base() = default;
+ virtual void move(void* p) = 0;
+ virtual void operator()() = 0;
+ };
+
+ template
+ struct holder : base
+ {
+ F f;
+
+ holder(holder&&) = default;
+
+ template
+ explicit
+ holder(U&& u)
+ : f(std::forward(u))
+ {
+ }
+
+ void
+ move(void* p) override
+ {
+ ::new(p) holder(std::move(*this));
+ }
+
+ void
+ operator()() override
+ {
+ F f_(std::move(f));
+ this->~holder();
+ // invocation of f_() can
+ // assign a new invokable.
+ f_();
+ }
+ };
+
+ struct exemplar
+ {
+ std::shared_ptr _;
+ void operator()(){}
+ };
+
+ using buf_type = std::uint8_t[
+ sizeof(holder)];
+
+ bool b_ = false;
+ alignas(holder) buf_type buf_;
+
+public:
+#ifndef NDEBUG
+ ~invokable()
+ {
+ // Engaged invokables must be invoked before
+ // destruction otherwise the io_service
+ // invariants are broken w.r.t completions.
+ assert(! b_);
+ }
+#endif
+
+ invokable() = default;
+ invokable(invokable const&) = delete;
+ invokable& operator=(invokable const&) = delete;
+
+ invokable(invokable&& other)
+ : b_(other.b_)
+ {
+ if(other.b_)
+ {
+ other.get().move(buf_);
+ other.b_ = false;
+ }
+ }
+
+ invokable&
+ operator=(invokable&& other)
+ {
+ // Engaged invokables must be invoked before
+ // assignment otherwise the io_service
+ // invariants are broken w.r.t completions.
+ assert(! b_);
+
+ if(other.b_)
+ {
+ b_ = true;
+ other.get().move(buf_);
+ other.b_ = false;
+ }
+ return *this;
+ }
+
+ template
+ void
+ emplace(F&& f);
+
+ void
+ maybe_invoke()
+ {
+ if(b_)
+ {
+ b_ = false;
+ get()();
+ }
+ }
+
+private:
+ base&
+ get()
+ {
+ return *reinterpret_cast(buf_);
+ }
+};
+
+template
+void
+invokable::emplace(F&& f)
+{
+ static_assert(sizeof(buf_type) >= sizeof(holder),
+ "buffer too small");
+ assert(! b_);
+ ::new(buf_) holder(std::forward(f));
+ b_ = true;
+}
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/mask.h b/src/beast/beast/wsproto/detail/mask.h
new file mode 100644
index 000000000..220268665
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/mask.h
@@ -0,0 +1,389 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_DETAIL_MASKGEN_H_INCLUDED
+#define BEAST_WSPROTO_DETAIL_MASKGEN_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+// Pseudo-random source of mask keys
+//
+template
+class maskgen_t
+{
+ std::mt19937 g_;
+
+public:
+ using result_type = typename std::mt19937::result_type;
+
+ maskgen_t(maskgen_t const&) = delete;
+ maskgen_t& operator=(maskgen_t const&) = delete;
+
+ maskgen_t();
+
+ result_type
+ operator()() noexcept;
+
+ void
+ rekey();
+};
+
+template
+maskgen_t<_>::maskgen_t()
+{
+ rekey();
+}
+
+template
+auto
+maskgen_t<_>::operator()() noexcept ->
+ result_type
+{
+ for(;;)
+ if(auto key = g_())
+ return key;
+}
+
+template
+void
+maskgen_t<_>::rekey()
+{
+ std::random_device rng;
+ std::array e;
+ for(auto& i : e)
+ i = rng();
+ std::seed_seq ss(e.begin(), e.end());
+ g_.seed(ss);
+}
+
+using maskgen = maskgen_t<>;
+
+//------------------------------------------------------------------------------
+
+//using prepared_key_type = std::size_t;
+using prepared_key_type = std::uint32_t;
+//using prepared_key_type = std::uint64_t;
+
+inline
+void
+prepare_key(std::uint32_t& prepared, std::uint32_t key)
+{
+ prepared = key;
+}
+
+inline
+void
+prepare_key(std::uint64_t& prepared, std::uint32_t key)
+{
+ prepared =
+ (static_cast(key) << 32) | key;
+}
+
+template
+inline
+std::enable_if_t::value, T>
+rol(T t, unsigned n = 1)
+{
+ auto constexpr bits =
+ static_cast(
+ sizeof(T) * CHAR_BIT);
+ n &= bits-1;
+ return static_cast((t << n) |
+ (static_cast>(t) >> (bits - n)));
+}
+
+template
+inline
+std::enable_if_t::value, T>
+ror(T t, unsigned n = 1)
+{
+ auto constexpr bits =
+ static_cast(
+ sizeof(T) * CHAR_BIT);
+ n &= bits-1;
+ return static_cast((t << (bits - n)) |
+ (static_cast>(t) >> n));
+}
+
+// 32-bit Uuoptimized
+//
+template
+void
+mask_inplace_safe(
+ boost::asio::mutable_buffer const& b,
+ std::uint32_t& key)
+{
+ using boost::asio::buffer_cast;
+ using boost::asio::buffer_size;
+ auto n = buffer_size(b);
+ auto p = buffer_cast(b);
+ for(auto i = n / sizeof(key); i; --i)
+ {
+ *p ^= key ; ++p;
+ *p ^= (key >> 8); ++p;
+ *p ^= (key >>16); ++p;
+ *p ^= (key >>24); ++p;
+ }
+ n %= sizeof(key);
+ switch(n)
+ {
+ case 3: p[2] ^= (key >>16);
+ case 2: p[1] ^= (key >> 8);
+ case 1: p[0] ^= key;
+ key = ror(key, n*8);
+ default:
+ break;
+ }
+}
+
+// 64-bit unoptimized
+//
+template
+void
+mask_inplace_safe(
+ boost::asio::mutable_buffer const& b,
+ std::uint64_t& key)
+{
+ using boost::asio::buffer_cast;
+ using boost::asio::buffer_size;
+ auto n = buffer_size(b);
+ auto p = buffer_cast(b);
+ for(auto i = n / sizeof(key); i; --i)
+ {
+ *p ^= key ; ++p;
+ *p ^= (key >> 8); ++p;
+ *p ^= (key >>16); ++p;
+ *p ^= (key >>24); ++p;
+ *p ^= (key >>32); ++p;
+ *p ^= (key >>40); ++p;
+ *p ^= (key >>48); ++p;
+ *p ^= (key >>56); ++p;
+ }
+ n %= sizeof(key);
+ switch(n)
+ {
+ case 7: p[6] ^= (key >>16);
+ case 6: p[5] ^= (key >> 8);
+ case 5: p[4] ^= key;
+ case 4: p[3] ^= (key >>24);
+ case 3: p[2] ^= (key >>16);
+ case 2: p[1] ^= (key >> 8);
+ case 1: p[0] ^= key;
+ key = ror(key, n*8);
+ default:
+ break;
+ }
+}
+
+// 32-bit optimized
+template
+void
+mask_inplace_32(
+ boost::asio::mutable_buffer const& b,
+ std::uint32_t& key)
+{
+ using boost::asio::buffer_cast;
+ using boost::asio::buffer_size;
+ auto n = buffer_size(b);
+ auto p = buffer_cast(b);
+ auto m = reinterpret_cast<
+ uintptr_t>(p) % sizeof(key);
+ switch(m)
+ {
+ case 1: *p ^= key ; ++p; --n;
+ case 2: *p ^= (key >> 8); ++p; --n;
+ case 3: *p ^= (key >>16); ++p; --n;
+ key = ror(key, m * 8);
+ case 0:
+ break;
+ }
+ for(auto i = n / sizeof(key); i; --i)
+ {
+ *reinterpret_cast<
+ std::uint32_t*>(p) ^= key;
+ p += sizeof(key);
+ }
+ n %= sizeof(key);
+ switch(n)
+ {
+ case 3: p[2] ^= (key >>16);
+ case 2: p[1] ^= (key >> 8);
+ case 1: p[0] ^= key;
+ key = ror(key, n*8);
+ default:
+ break;
+ }
+}
+
+// 64-bit optimized
+//
+template
+void
+mask_inplace_64(
+ boost::asio::mutable_buffer const& b,
+ std::uint64_t& key)
+{
+ using boost::asio::buffer_cast;
+ using boost::asio::buffer_size;
+ auto n = buffer_size(b);
+ auto p = buffer_cast(b);
+ auto m = reinterpret_cast<
+ uintptr_t>(p) % sizeof(key);
+ switch(m)
+ {
+ case 1: *p ^= key ; ++p; --n;
+ case 2: *p ^= (key >> 8); ++p; --n;
+ case 3: *p ^= (key >>16); ++p; --n;
+ case 4: *p ^= (key >>24); ++p; --n;
+ case 5: *p ^= (key >>32); ++p; --n;
+ case 6: *p ^= (key >>40); ++p; --n;
+ case 7: *p ^= (key >>48); ++p; --n;
+ key = ror(key, m * 8);
+ case 0:
+ break;
+ }
+ for(auto i = n / sizeof(key); i; --i)
+ {
+ *reinterpret_cast<
+ std::uint64_t*>(p) ^= key;
+ p += sizeof(key);
+ }
+ n %= sizeof(key);
+ switch(n)
+ {
+ case 3: p[2] ^= (key >>16);
+ case 2: p[1] ^= (key >> 8);
+ case 1: p[0] ^= key;
+ key = ror(key, n*8);
+ default:
+ break;
+ }
+}
+
+// 32-bit x86 optimized
+//
+template
+void
+mask_inplace_x86(
+ boost::asio::mutable_buffer const& b,
+ std::uint32_t& key)
+{
+ using boost::asio::buffer_cast;
+ using boost::asio::buffer_size;
+ auto n = buffer_size(b);
+ auto p = buffer_cast(b);
+ for(auto i = n / sizeof(key); i; --i)
+ {
+ *reinterpret_cast<
+ std::uint32_t*>(p) ^= key;
+ p += sizeof(key);
+ }
+ n %= sizeof(key);
+ switch(n)
+ {
+ case 3: p[2] ^= (key >>16);
+ case 2: p[1] ^= (key >> 8);
+ case 1: p[0] ^= key;
+ key = ror(key, n*8);
+ default:
+ break;
+ }
+}
+
+// 64-bit amd64 optimized
+//
+template
+void
+mask_inplace_amd(
+ boost::asio::mutable_buffer const& b,
+ std::uint64_t& key)
+{
+ using boost::asio::buffer_cast;
+ using boost::asio::buffer_size;
+ auto n = buffer_size(b);
+ auto p = buffer_cast(b);
+ for(auto i = n / sizeof(key); i; --i)
+ {
+ *reinterpret_cast<
+ std::uint64_t*>(p) ^= key;
+ p += sizeof(key);
+ }
+ n %= sizeof(key);
+ switch(n)
+ {
+ case 7: p[6] ^= (key >>16);
+ case 6: p[5] ^= (key >> 8);
+ case 5: p[4] ^= key;
+ case 4: p[3] ^= (key >>24);
+ case 3: p[2] ^= (key >>16);
+ case 2: p[1] ^= (key >> 8);
+ case 1: p[0] ^= key;
+ key = ror(key, n*8);
+ default:
+ break;
+ }
+}
+
+inline
+void
+mask_inplace(
+ boost::asio::mutable_buffer const& b,
+ std::uint32_t& key)
+{
+ mask_inplace_safe(b, key);
+ //mask_inplace_32(b, key);
+ //mask_inplace_x86(b, key);
+}
+
+inline
+void
+mask_inplace(
+ boost::asio::mutable_buffer const& b,
+ std::uint64_t& key)
+{
+ mask_inplace_safe(b, key);
+ //mask_inplace_64(b, key);
+ //mask_inplace_amd(b, key);
+}
+
+// Apply mask in place
+//
+template
+void
+mask_inplace(
+ MutableBuffers const& bs, KeyType& key)
+{
+ for(auto const& b : bs)
+ mask_inplace(b, key);
+}
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/socket_base.h b/src/beast/beast/wsproto/detail/socket_base.h
new file mode 100644
index 000000000..11abd8b5f
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/socket_base.h
@@ -0,0 +1,141 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_SOCKET_BASE_H_INCLUDED
+#define BEAST_WSPROTO_SOCKET_BASE_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+template
+inline
+void
+maybe_throw(error_code const& ec, String const&)
+{
+ if(ec)
+ throw boost::system::system_error{ec};
+}
+
+template
+static
+std::size_t
+clamp(UInt x)
+{
+ if(x >= std::numeric_limits::max())
+ return std::numeric_limits::max();
+ return static_cast(x);
+}
+
+template
+static
+std::size_t
+clamp(UInt x, std::size_t limit)
+{
+ if(x >= limit)
+ return limit;
+ return static_cast(x);
+}
+
+//------------------------------------------------------------------------------
+
+struct socket_base
+{
+protected:
+ struct op {};
+
+ detail::maskgen maskgen_; // source of mask keys
+ decorator_type d_; // adorns http messages
+ bool keep_alive_ = false; // close on failed upgrade
+ role_type role_; // server or client
+ bool error_ = false; // non-zero ec was delivered
+
+ std::size_t rd_msg_max_ =
+ 16 * 1024 * 1024; // max message size
+ detail::frame_header rd_fh_; // current frame header
+ detail::prepared_key_type rd_key_; // prepared masking key
+ detail::utf8_checker rd_utf8_check_;// for current text msg
+ std::uint64_t rd_size_; // size of the current message so far
+ std::uint64_t rd_need_ = 0; // bytes left in msg frame payload
+ opcode rd_opcode_; // opcode of current msg
+ bool rd_cont_ = false; // expecting a continuation frame
+ bool rd_close_ = false; // got close frame
+ op* rd_block_ = nullptr; // op currently reading
+
+ std::size_t
+ wr_frag_size_ = 16 * 1024; // size of auto-fragments
+ std::size_t wr_buf_size_ = 4096; // write buffer size
+ opcode wr_opcode_ = opcode::text; // outgoing message type
+ bool wr_close_ = false; // sent close frame
+ bool wr_cont_ = false; // next write is continuation frame
+ op* wr_block_ = nullptr; // op currenly writing
+
+ invokable rd_op_; // invoked after write completes
+ invokable wr_op_; // invoked after read completes
+ close_reason cr_; // set from received close frame
+
+ socket_base()
+ : d_(std::make_unique<
+ decorator>())
+ {
+ }
+
+ socket_base(socket_base&&) = default;
+ socket_base(socket_base const&) = delete;
+ socket_base& operator=(socket_base&&) = default;
+ socket_base& operator=(socket_base const&) = delete;
+
+ template
+ void
+ prepare_fh(close_code& code);
+
+ template
+ void
+ write_close(Streambuf& sb,
+ close_reason const& rc);
+
+ template
+ void
+ write_ping(Streambuf& sb, opcode op,
+ ping_payload_type const& data);
+};
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/detail/utf8_checker.h b/src/beast/beast/wsproto/detail/utf8_checker.h
new file mode 100644
index 000000000..7d35134c4
--- /dev/null
+++ b/src/beast/beast/wsproto/detail/utf8_checker.h
@@ -0,0 +1,184 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_UTF8_CHECKER_H_INCLUDED
+#define BEAST_WSPROTO_UTF8_CHECKER_H_INCLUDED
+
+#include
+#include
+#include // DEPRECATED
+
+namespace beast {
+namespace wsproto {
+namespace detail {
+
+// Code adapted from
+// http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+/*
+ Copyright (c) 2008-2009 Bjoern Hoehrmann
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject
+ to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
+*/
+template
+class utf8_checker_t
+{
+ // Table for the UTF8 decode state machine
+ using lut_type = std::uint8_t[400];
+ static
+ lut_type const&
+ lut()
+ {
+ // 400 elements
+ static std::uint8_t constexpr tab[] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
+ 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
+ 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
+ 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
+ 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
+ 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
+ 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1 // s7..s8
+ };
+ return tab;
+ }
+
+ std::uint32_t state_ = 0;
+ std::uint32_t codepoint_ = 0;
+
+public:
+ utf8_checker_t() = default;
+ utf8_checker_t(utf8_checker_t&&) = default;
+ utf8_checker_t(utf8_checker_t const&) = default;
+ utf8_checker_t& operator=(utf8_checker_t&&) = default;
+ utf8_checker_t& operator=(utf8_checker_t const&) = default;
+
+ void
+ reset();
+
+ // Returns `true` on success
+ bool
+ write(void const* buffer, std::size_t size);
+
+ // Returns `true` on success
+ template
+ bool
+ write(BufferSequence const& bs);
+
+ // Returns `true` on success
+ bool
+ finish();
+};
+
+template
+void
+utf8_checker_t<_>::reset()
+{
+ state_ = 0;
+ codepoint_ = 0;
+}
+
+template
+bool
+utf8_checker_t<_>::write(void const* buffer, std::size_t size)
+{
+ auto p = static_cast(buffer);
+ auto plut = &lut()[0];
+ while(size)
+ {
+ auto const byte = *p;
+ auto const type = plut[byte];
+ if(state_)
+ codepoint_ = (byte & 0x3fu) | (codepoint_ << 6);
+ else
+ codepoint_ = (0xff >> type) & byte;
+ state_ = plut[256 + state_ * 16 + type];
+ if(state_ == 1)
+ {
+ reset();
+ return false;
+ }
+ ++p;
+ --size;
+ }
+ return true;
+}
+
+template
+template
+bool
+utf8_checker_t<_>::write(BufferSequence const& bs)
+{
+ using boost::asio::buffer_cast;
+ using boost::asio::buffer_size;
+ for (auto const& b : bs)
+ if(! write(buffer_cast(b),
+ buffer_size(b)))
+ return false;
+ return true;
+}
+
+template
+bool
+utf8_checker_t<_>::finish()
+{
+ auto const success = state_ == 0;
+ reset();
+ return success;
+}
+
+using utf8_checker = utf8_checker_t<>;
+
+template
+bool
+check_utf8(char const* p, std::size_t n)
+{
+ utf8_checker c;
+ if(! c.write(p, n))
+ return false;
+ return c.finish();
+}
+
+} // detail
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/error.h b/src/beast/beast/wsproto/error.h
new file mode 100644
index 000000000..1ccb658ab
--- /dev/null
+++ b/src/beast/beast/wsproto/error.h
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_ERROR_H_INCLUDED
+#define BEAST_WSPROTO_ERROR_H_INCLUDED
+
+#include
+
+namespace beast {
+namespace wsproto {
+
+using error_code = boost::system::error_code;
+
+/// Error values
+enum class error
+{
+ /// Both sides performed a WebSocket close
+ closed = 1,
+
+ /// WebSocket connection failed, protocol violation
+ failed,
+
+ /// Upgrade request failed, connection is closed
+ handshake_failed,
+
+ /// Upgrade request failed, but connection is still open
+ keep_alive,
+
+ /// HTTP response is malformed
+ response_malformed,
+
+ /// HTTP response failed the upgrade
+ response_failed,
+
+ /// Upgrade request denied for invalid fields.
+ response_denied,
+
+ /// Upgrade request is malformed
+ request_malformed,
+
+ /// Upgrade request fields incorrect
+ request_invalid,
+
+ /// Upgrade request denied
+ request_denied
+};
+
+error_code
+make_error_code(error e);
+
+} // wsproto
+} // beast
+
+#include
+
+#endif
diff --git a/src/beast/beast/wsproto/impl/accept_op.ipp b/src/beast/beast/wsproto/impl/accept_op.ipp
new file mode 100644
index 000000000..c82e24cd1
--- /dev/null
+++ b/src/beast/beast/wsproto/impl/accept_op.ipp
@@ -0,0 +1,158 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_ACCEPT_OP_H_INCLUDED
+#define BEAST_WSPROTO_ACCEPT_OP_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+
+// read and respond to an upgrade request
+//
+template
+template
+class socket::accept_op
+{
+ using alloc_type =
+ handler_alloc;
+
+ struct data
+ {
+ socket& ws;
+ http::request req;
+ Handler h;
+ bool cont;
+ int state = 0;
+
+ template
+ data(DeducedHandler&& h_, socket& ws_,
+ Buffers const& buffers)
+ : ws(ws_)
+ , h(std::forward(h_))
+ , cont(boost_asio_handler_cont_helpers::
+ is_continuation(h))
+ {
+ using boost::asio::buffer_copy;
+ using boost::asio::buffer_size;
+ ws.stream_.buffer().commit(buffer_copy(
+ ws.stream_.buffer().prepare(
+ buffer_size(buffers)), buffers));
+ }
+ };
+
+ std::shared_ptr d_;
+
+public:
+ accept_op(accept_op&&) = default;
+ accept_op(accept_op const&) = default;
+
+ template
+ accept_op(DeducedHandler&& h,
+ socket& ws, Args&&... args)
+ : d_(std::allocate_shared(alloc_type{h},
+ std::forward(h), ws,
+ std::forward(args)...))
+ {
+ (*this)(error_code{}, 0, false);
+ }
+
+ void operator()(error_code const& ec)
+ {
+ (*this)(ec, 0);
+ }
+
+ void operator()(error_code const& ec,
+ std::size_t bytes_transferred, bool again = true);
+
+ friend
+ auto asio_handler_allocate(
+ std::size_t size, accept_op* op)
+ {
+ return boost_asio_handler_alloc_helpers::
+ allocate(size, op->d_->h);
+ }
+
+ friend
+ auto asio_handler_deallocate(
+ void* p, std::size_t size, accept_op* op)
+ {
+ return boost_asio_handler_alloc_helpers::
+ deallocate(p, size, op->d_->h);
+ }
+
+ friend
+ auto asio_handler_is_continuation(accept_op* op)
+ {
+ return op->d_->cont;
+ }
+
+ template
+ friend
+ auto asio_handler_invoke(Function&& f, accept_op* op)
+ {
+ return boost_asio_handler_invoke_helpers::
+ invoke(f, op->d_->h);
+ }
+};
+
+template
+template
+void
+socket::accept_op::
+operator()(error_code const& ec,
+ std::size_t bytes_transferred, bool again)
+{
+ auto& d = *d_;
+ d.cont = d.cont || again;
+ while(! ec && d.state != 99)
+ {
+ switch(d.state)
+ {
+ case 0:
+ // read message
+ d.state = 1;
+ http::async_read(d.ws.next_layer_,
+ d.ws.stream_.buffer(), d.req,
+ std::move(*this));
+ return;
+
+ // got message
+ case 1:
+ // respond to request
+ response_op{
+ std::move(d.h), d.ws, d.req, true};
+ return;
+ }
+ }
+ d.h(ec);
+}
+
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/impl/close_op.ipp b/src/beast/beast/wsproto/impl/close_op.ipp
new file mode 100644
index 000000000..f17e050ea
--- /dev/null
+++ b/src/beast/beast/wsproto/impl/close_op.ipp
@@ -0,0 +1,198 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_CLOSE_OP_H_INCLUDED
+#define BEAST_WSPROTO_CLOSE_OP_H_INCLUDED
+
+#include
+#include
+#include
+
+namespace beast {
+namespace wsproto {
+
+// send the close message and wait for the response
+//
+template
+template
+class socket::close_op
+{
+ using alloc_type =
+ handler_alloc;
+ using fb_type =
+ detail::frame_streambuf;
+ using fmb_type =
+ typename fb_type::mutable_buffers_type;
+
+ struct data : op
+ {
+ socket& ws;
+ close_reason cr;
+ Handler h;
+ fb_type fb;
+ fmb_type fmb;
+ bool cont;
+ int state = 0;
+
+ template
+ data(DeducedHandler&& h_, socket& ws_,
+ close_reason const& cr_)
+ : ws(ws_)
+ , cr(cr_)
+ , h(std::forward(h_))
+ , cont(boost_asio_handler_cont_helpers::
+ is_continuation(h))
+ {
+ ws.template write_close<
+ static_streambuf>(fb, cr);
+ }
+ };
+
+ std::shared_ptr d_;
+
+public:
+ close_op(close_op&&) = default;
+ close_op(close_op const&) = default;
+
+ template
+ close_op(DeducedHandler&& h,
+ socket& ws, Args&&... args)
+ : d_(std::allocate_shared(alloc_type{h},
+ std::forward(h), ws,
+ std::forward(args)...))
+ {
+ (*this)(error_code{}, 0, false);
+ }
+
+ void operator()()
+ {
+ auto& d = *d_;
+ d.cont = false;
+ (*this)(error_code{}, 0, false);
+ }
+
+ void operator()(error_code const& ec)
+ {
+ (*this)(ec, 0);
+ }
+
+ void
+ operator()(error_code ec,
+ std::size_t bytes_transferred, bool again = true);
+
+ friend
+ auto asio_handler_allocate(
+ std::size_t size, close_op* op)
+ {
+ return boost_asio_handler_alloc_helpers::
+ allocate(size, op->d_->h);
+ }
+
+ friend
+ auto asio_handler_deallocate(
+ void* p, std::size_t size, close_op* op)
+ {
+ return boost_asio_handler_alloc_helpers::
+ deallocate(p, size, op->d_->h);
+ }
+
+ friend
+ auto asio_handler_is_continuation(close_op* op)
+ {
+ return op->d_->cont;
+ }
+
+ template
+ friend
+ auto asio_handler_invoke(Function&& f, close_op* op)
+ {
+ return boost_asio_handler_invoke_helpers::
+ invoke(f, op->d_->h);
+ }
+};
+
+template
+template
+void
+socket::close_op::operator()(
+ error_code ec, std::size_t bytes_transferred, bool again)
+{
+ auto& d = *d_;
+ d.cont = d.cont || again;
+ while(! ec && d.state != 99)
+ {
+ switch(d.state)
+ {
+ case 0:
+ if(d.ws.wr_block_)
+ {
+ // suspend
+ d.state = 1;
+ d.ws.rd_op_.template emplace<
+ close_op>(std::move(*this));
+ return;
+ }
+ if(d.ws.error_)
+ {
+ // call handler
+ d.state = 99;
+ d.ws.get_io_service().post(
+ bind_handler(std::move(*this),
+ boost::asio::error::operation_aborted, 0));
+ return;
+ }
+ d.state = 2;
+ break;
+
+ // resume
+ case 1:
+ if(d.ws.error_)
+ {
+ // call handler
+ d.state = 99;
+ ec = boost::asio::error::operation_aborted;
+ break;
+ }
+ d.state = 2;
+ break;
+
+ case 2:
+ // send close
+ d.state = 99;
+ assert(! d.ws.wr_close_);
+ d.ws.wr_close_ = true;
+ assert(! d.ws.wr_block_);
+ d.ws.wr_block_ = &d;
+ boost::asio::async_write(d.ws.stream_,
+ d.fb.data(), std::move(*this));
+ return;
+ }
+ }
+ if(ec)
+ d.ws.error_ = true;
+ if(d.ws.wr_block_ == &d)
+ d.ws.wr_block_ = nullptr;
+ d.h(ec);
+ d.ws.rd_op_.maybe_invoke();
+}
+
+} // wsproto
+} // beast
+
+#endif
diff --git a/src/beast/beast/wsproto/impl/error.ipp b/src/beast/beast/wsproto/impl/error.ipp
new file mode 100644
index 000000000..85a7fe954
--- /dev/null
+++ b/src/beast/beast/wsproto/impl/error.ipp
@@ -0,0 +1,39 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_WSPROTO_ERROR_IPP_H_INCLUDED
+#define BEAST_WSPROTO_ERROR_IPP_H_INCLUDED
+
+#include