mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Set Beast version to 1.0.0-b30:
Squashed 'src/beast/' changes from 9f10b11..1b9a714 1b9a714 Set version to 1.0.0-b30 faed9e5 Allow concurrent websocket async ping and writes: 31cda06 Fix race when write suspends 48dd38e Fix race in close frames during reads e2d1bb0 Fix race in pings during reads 36143be Set version to 1.0.0-b29 f0399b6 Fix doc link typo 787b7c2 Check ostream modifier correctly 4fa0bf6 Fix Writer return value documentation 6406da0 Document type-pun in buffer_cat 66cdb37 Fix illegal HTTP characters accepted as hex zero e64ca2f Fix Body requirements doc 6dfd9f9 Fix compilation error in non-template class fa7fea8 Fix race in writes during reads: git-subtree-dir: src/beast git-subtree-split: 1b9a71483347b7027b2fb7fe27ecea148d2e79ba
This commit is contained in:
@@ -1,3 +1,33 @@
|
||||
1.0.0-b30
|
||||
|
||||
WebSocket
|
||||
|
||||
* Fix race in pings during reads
|
||||
* Fix race in close frames during reads
|
||||
* Fix race when write suspends
|
||||
* Allow concurrent websocket async ping and writes
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b29
|
||||
|
||||
* Fix compilation error in non-template class
|
||||
* Document type-pun in buffer_cat
|
||||
* Correctly check ostream modifier (/extras)
|
||||
|
||||
HTTP
|
||||
|
||||
* Fix Body requirements doc
|
||||
* Fix illegal HTTP characters accepted as hex zero
|
||||
* Fix Writer return value documentation
|
||||
|
||||
WebSocket
|
||||
|
||||
* Fix race in writes during reads
|
||||
* Fix doc link typo
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
1.0.0-b28
|
||||
|
||||
* Split out and rename test stream classes
|
||||
|
||||
@@ -91,7 +91,7 @@ This example demonstrates both synchronous and asynchronous
|
||||
WebSocket server implementations.
|
||||
|
||||
* [@examples/websocket_async_echo_server.hpp]
|
||||
* [@examples/websocket_ssync_echo_server.hpp]
|
||||
* [@examples/websocket_sync_echo_server.hpp]
|
||||
* [@examples/websocket_echo.cpp]
|
||||
|
||||
[heading Secure WebSocket]
|
||||
|
||||
@@ -27,7 +27,7 @@ In this table:
|
||||
]
|
||||
]
|
||||
[
|
||||
[`Body::reader`]
|
||||
[`X::reader`]
|
||||
[]
|
||||
[
|
||||
If present, a type meeting the requirements of
|
||||
@@ -36,7 +36,7 @@ In this table:
|
||||
]
|
||||
]
|
||||
[
|
||||
[`Body::writer`]
|
||||
[`X::writer`]
|
||||
[]
|
||||
[
|
||||
If present, a type meeting the requirements of
|
||||
|
||||
@@ -167,7 +167,8 @@ public:
|
||||
the writer must guarantee that the buffers remain valid until the
|
||||
next member function is invoked, which may be the destructor.
|
||||
|
||||
@return `true` if there is data, `false` when done,
|
||||
@return `true` if there is no more data to send,
|
||||
`false` when there may be more data,
|
||||
boost::indeterminate to suspend.
|
||||
|
||||
@note Undefined behavior if the callee takes ownership
|
||||
|
||||
@@ -320,8 +320,8 @@ operations can cause socket writes. However, these writes will not
|
||||
compete with caller-initiated write operations. For the purposes of
|
||||
correctness with respect to the stream invariants, caller-initiated
|
||||
read operations still only count as a read. This means that callers can
|
||||
have a simultaneous active read and write operation in progress, while
|
||||
the implementation also automatically handles control frames.
|
||||
have a simultaneously active read, write, and ping operation in progress,
|
||||
while the implementation also automatically handles control frames.
|
||||
|
||||
[heading Ping and Pong Frames]
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
: std::basic_ostream<CharT, Traits>(&buf_)
|
||||
, buf_(os)
|
||||
{
|
||||
if(os.flags() && std::ios::unitbuf)
|
||||
if(os.flags() & std::ios::unitbuf)
|
||||
std::unitbuf(*this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -283,7 +283,6 @@ reporter<_>::
|
||||
on_log(std::string const& s)
|
||||
{
|
||||
os_ << s;
|
||||
os_.flush();
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
@@ -352,10 +352,7 @@ public:
|
||||
{
|
||||
auto const& name = ss_.str();
|
||||
if(! name.empty())
|
||||
{
|
||||
suite_.log.flush();
|
||||
suite_.runner_->testcase(name);
|
||||
}
|
||||
}
|
||||
|
||||
scoped_testcase(suite& self, std::stringstream& ss)
|
||||
@@ -394,7 +391,6 @@ suite::testcase_t::operator()(
|
||||
std::string const& name, abort_t abort)
|
||||
{
|
||||
suite_.abort_ = abort == abort_on_fail;
|
||||
suite_.log.flush();
|
||||
suite_.runner_->testcase(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ class buffer_cat_helper<Bn...>::const_iterator
|
||||
iter_t<I>&
|
||||
iter()
|
||||
{
|
||||
// type-pun
|
||||
return *reinterpret_cast<
|
||||
iter_t<I>*>(static_cast<void*>(
|
||||
buf_.data()));
|
||||
@@ -91,6 +92,7 @@ class buffer_cat_helper<Bn...>::const_iterator
|
||||
iter_t<I> const&
|
||||
iter() const
|
||||
{
|
||||
// type-pun
|
||||
return *reinterpret_cast<
|
||||
iter_t<I> const*>(static_cast<
|
||||
void const*>(buf_.data()));
|
||||
|
||||
@@ -94,11 +94,11 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
using list_t = typename boost::intrusive::make_list<
|
||||
element, boost::intrusive::constant_time_size<false>>::type;
|
||||
using list_t = boost::intrusive::make_list<element,
|
||||
boost::intrusive::constant_time_size<false>>::type;
|
||||
|
||||
using set_t = typename boost::intrusive::make_multiset<
|
||||
element, boost::intrusive::constant_time_size<true>,
|
||||
using set_t = boost::intrusive::make_multiset<element,
|
||||
boost::intrusive::constant_time_size<true>,
|
||||
boost::intrusive::compare<less>>::type;
|
||||
|
||||
// data
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#define BEAST_HTTP_DETAIL_RFC7230_HPP
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
@@ -25,10 +24,10 @@ is_digit(char c)
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
char
|
||||
is_alpha(char c)
|
||||
{
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
static char 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, 0, // 16
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
|
||||
@@ -37,16 +36,25 @@ is_alpha(char c)
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 80
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 112
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
char
|
||||
is_text(char c)
|
||||
{
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
static char constexpr tab[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
||||
@@ -63,12 +71,13 @@ is_text(char c)
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
char
|
||||
is_tchar(char c)
|
||||
{
|
||||
/*
|
||||
@@ -77,7 +86,7 @@ is_tchar(char c)
|
||||
"^" | "_" | "`" | "|" | "~" |
|
||||
DIGIT | ALPHA
|
||||
*/
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
static char 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, 0, // 16
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32
|
||||
@@ -86,18 +95,27 @@ is_tchar(char c)
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
|
||||
}};
|
||||
return tab[static_cast<std::uint8_t>(c)] != 0;
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
char
|
||||
is_qdchar(char c)
|
||||
{
|
||||
/*
|
||||
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
||||
*/
|
||||
static std::array<bool, 256> constexpr tab = {{
|
||||
static char constexpr tab[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
||||
@@ -114,19 +132,20 @@ is_qdchar(char c)
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
||||
}};
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
char
|
||||
is_qpchar(char c)
|
||||
{
|
||||
/*
|
||||
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||
obs-text = %x80-FF
|
||||
*/
|
||||
static std::array<bool, 256> constexpr tab = {{
|
||||
static char constexpr tab[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
||||
@@ -143,7 +162,8 @@ is_qpchar(char c)
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
||||
}};
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
@@ -161,7 +181,7 @@ to_field_char(char c)
|
||||
| "/" | "[" | "]" | "?" | "="
|
||||
| "{" | "}" | SP | HT
|
||||
*/
|
||||
static std::array<char, 256> constexpr tab = {{
|
||||
static char 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,
|
||||
0, '!', 0, '#', '$', '%', '&', '\'', 0, 0, '*', '+', 0, '-', '.', 0,
|
||||
@@ -169,8 +189,17 @@ to_field_char(char c)
|
||||
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, '^', '_',
|
||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, '|', 0, '~', 0
|
||||
}};
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 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, 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, 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, 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, 0, 0, 0
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
@@ -182,7 +211,7 @@ char
|
||||
to_value_char(char c)
|
||||
{
|
||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
||||
static std::array<std::uint8_t, 256> constexpr tab = {{
|
||||
static unsigned char constexpr tab[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, // 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 32
|
||||
@@ -199,7 +228,8 @@ to_value_char(char c)
|
||||
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, // 208
|
||||
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 224
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 // 240
|
||||
}};
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
|
||||
}
|
||||
|
||||
@@ -207,7 +237,7 @@ inline
|
||||
std::int8_t
|
||||
unhex(char c)
|
||||
{
|
||||
static std::array<std::int8_t, 256> constexpr tab = {{
|
||||
static char constexpr tab[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
|
||||
@@ -215,8 +245,17 @@ unhex(char c)
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 112
|
||||
}};
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 112
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240
|
||||
};
|
||||
static_assert(sizeof(tab) == 256, "");
|
||||
return tab[static_cast<std::uint8_t>(c)];
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
//
|
||||
#define BEAST_VERSION 100000
|
||||
|
||||
#define BEAST_VERSION_STRING "1.0.0-b28"
|
||||
#define BEAST_VERSION_STRING "1.0.0-b30"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -98,6 +98,7 @@ public:
|
||||
{
|
||||
if(other.base_)
|
||||
{
|
||||
// type-pun
|
||||
base_ = reinterpret_cast<base*>(&buf_[0]);
|
||||
other.base_->move(buf_);
|
||||
other.base_ = nullptr;
|
||||
@@ -109,11 +110,12 @@ public:
|
||||
{
|
||||
// Engaged invokables must be invoked before
|
||||
// assignment otherwise the io_service
|
||||
// invariants are broken w.r.t completions.
|
||||
// completion invariants are broken.
|
||||
BOOST_ASSERT(! base_);
|
||||
|
||||
if(other.base_)
|
||||
{
|
||||
// type-pun
|
||||
base_ = reinterpret_cast<base*>(&buf_[0]);
|
||||
other.base_->move(buf_);
|
||||
other.base_ = nullptr;
|
||||
@@ -147,6 +149,7 @@ invokable::emplace(F&& f)
|
||||
"buffer too small");
|
||||
BOOST_ASSERT(! base_);
|
||||
::new(buf_) holder<F>(std::forward<F>(f));
|
||||
// type-pun
|
||||
base_ = reinterpret_cast<base*>(&buf_[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,8 +67,9 @@ protected:
|
||||
op* wr_block_; // op currenly writing
|
||||
|
||||
ping_data* ping_data_; // where to put the payload
|
||||
invokable rd_op_; // invoked after write completes
|
||||
invokable wr_op_; // invoked after read completes
|
||||
invokable rd_op_; // read parking
|
||||
invokable wr_op_; // write parking
|
||||
invokable ping_op_; // ping parking
|
||||
close_reason cr_; // set from received close frame
|
||||
|
||||
// State information for the message being received
|
||||
|
||||
@@ -147,25 +147,33 @@ operator()(error_code ec, bool again)
|
||||
boost::asio::error::operation_aborted));
|
||||
return;
|
||||
}
|
||||
// fall through
|
||||
d.ws.wr_block_ = &d;
|
||||
// [[fallthrough]]
|
||||
|
||||
case 1:
|
||||
// send close frame
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.state = 99;
|
||||
d.ws.wr_close_ = true;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
d.fb.data(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 2:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
d.state = 3;
|
||||
// The current context is safe but might not be
|
||||
// the same as the one for this operation (since
|
||||
// we are being called from a write operation).
|
||||
// Call post to make sure we are invoked the same
|
||||
// way as the final handler for this operation.
|
||||
d.ws.get_io_service().post(
|
||||
bind_handler(std::move(*this), ec));
|
||||
return;
|
||||
|
||||
case 3:
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
if(d.ws.failed_ || d.ws.wr_close_)
|
||||
{
|
||||
// call handler
|
||||
@@ -182,7 +190,8 @@ operator()(error_code ec, bool again)
|
||||
upcall:
|
||||
if(d.ws.wr_block_ == &d)
|
||||
d.ws.wr_block_ = nullptr;
|
||||
d.ws.rd_op_.maybe_invoke();
|
||||
d.ws.rd_op_.maybe_invoke() ||
|
||||
d.ws.ping_op_.maybe_invoke();
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ operator()(error_code ec, bool again)
|
||||
{
|
||||
// suspend
|
||||
d.state = 2;
|
||||
d.ws.wr_op_.template emplace<
|
||||
d.ws.ping_op_.template emplace<
|
||||
ping_op>(std::move(*this));
|
||||
return;
|
||||
}
|
||||
@@ -146,24 +146,32 @@ operator()(error_code ec, bool again)
|
||||
boost::asio::error::operation_aborted));
|
||||
return;
|
||||
}
|
||||
// fall through
|
||||
d.ws.wr_block_ = &d;
|
||||
// [[fallthrough]]
|
||||
|
||||
case 1:
|
||||
// send ping frame
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.state = 99;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
d.fb.data(), std::move(*this));
|
||||
return;
|
||||
|
||||
case 2:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
d.state = 3;
|
||||
// The current context is safe but might not be
|
||||
// the same as the one for this operation (since
|
||||
// we are being called from a write operation).
|
||||
// Call post to make sure we are invoked the same
|
||||
// way as the final handler for this operation.
|
||||
d.ws.get_io_service().post(
|
||||
bind_handler(std::move(*this), ec));
|
||||
return;
|
||||
|
||||
case 3:
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
if(d.ws.failed_ || d.ws.wr_close_)
|
||||
{
|
||||
// call handler
|
||||
@@ -180,7 +188,8 @@ operator()(error_code ec, bool again)
|
||||
upcall:
|
||||
if(d.ws.wr_block_ == &d)
|
||||
d.ws.wr_block_ = nullptr;
|
||||
d.ws.rd_op_.maybe_invoke();
|
||||
d.ws.rd_op_.maybe_invoke() ||
|
||||
d.ws.wr_op_.maybe_invoke();
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
|
||||
@@ -499,6 +499,8 @@ operator()(error_code ec,
|
||||
//------------------------------------------------------------------
|
||||
|
||||
case do_pong_resume:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
d.state = do_pong_resume + 1;
|
||||
d.ws.get_io_service().post(bind_handler(
|
||||
std::move(*this), ec, bytes_transferred));
|
||||
@@ -511,8 +513,7 @@ operator()(error_code ec,
|
||||
ec = boost::asio::error::operation_aborted;
|
||||
goto upcall;
|
||||
}
|
||||
d.state = do_pong;
|
||||
break; // VFALCO fall through?
|
||||
// [[fallthrough]]
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
@@ -520,14 +521,21 @@ operator()(error_code ec,
|
||||
if(d.ws.wr_close_)
|
||||
{
|
||||
// ignore ping when closing
|
||||
if(d.ws.wr_block_)
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.ws.wr_block_ = nullptr;
|
||||
}
|
||||
d.fb.reset();
|
||||
d.state = do_read_fh;
|
||||
break;
|
||||
}
|
||||
// send pong
|
||||
if(! d.ws.wr_block_)
|
||||
d.ws.wr_block_ = &d;
|
||||
else
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.state = do_pong + 1;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
d.fb.data(), std::move(*this));
|
||||
return;
|
||||
@@ -541,18 +549,25 @@ operator()(error_code ec,
|
||||
//------------------------------------------------------------------
|
||||
|
||||
case do_close_resume:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
d.state = do_close_resume + 1;
|
||||
// The current context is safe but might not be
|
||||
// the same as the one for this operation (since
|
||||
// we are being called from a write operation).
|
||||
// Call post to make sure we are invoked the same
|
||||
// way as the final handler for this operation.
|
||||
d.ws.get_io_service().post(bind_handler(
|
||||
std::move(*this), ec, bytes_transferred));
|
||||
return;
|
||||
|
||||
case do_close_resume + 1:
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
if(d.ws.failed_)
|
||||
{
|
||||
// call handler
|
||||
d.state = do_call_handler;
|
||||
ec = boost::asio::error::operation_aborted;
|
||||
break;
|
||||
goto upcall;
|
||||
}
|
||||
if(d.ws.wr_close_)
|
||||
{
|
||||
@@ -566,10 +581,12 @@ operator()(error_code ec,
|
||||
//------------------------------------------------------------------
|
||||
|
||||
case do_close:
|
||||
if(! d.ws.wr_block_)
|
||||
d.ws.wr_block_ = &d;
|
||||
else
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.state = do_teardown;
|
||||
d.ws.wr_close_ = true;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
d.fb.data(), std::move(*this));
|
||||
return;
|
||||
@@ -656,7 +673,8 @@ operator()(error_code ec,
|
||||
upcall:
|
||||
if(d.ws.wr_block_ == &d)
|
||||
d.ws.wr_block_ = nullptr;
|
||||
d.ws.wr_op_.maybe_invoke();
|
||||
d.ws.ping_op_.maybe_invoke() ||
|
||||
d.ws.wr_op_.maybe_invoke();
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class stream<NextLayer>::write_frame_op
|
||||
detail::prepared_key key;
|
||||
std::uint64_t remain;
|
||||
int state = 0;
|
||||
int entry;
|
||||
int entry_state;
|
||||
|
||||
data(Handler& handler_, stream<NextLayer>& ws_,
|
||||
bool fin_, Buffers const& bs)
|
||||
@@ -179,40 +179,44 @@ operator()(error_code ec,
|
||||
d.fh.mask =
|
||||
d.ws.role_ == detail::role_type::client;
|
||||
|
||||
// entry_state determines which algorithm
|
||||
// we will use to send. If we suspend, we
|
||||
// will transition to entry_state + 1 on
|
||||
// the resume.
|
||||
if(d.ws.wr_.compress)
|
||||
{
|
||||
d.entry = do_deflate;
|
||||
d.entry_state = do_deflate;
|
||||
}
|
||||
else if(! d.fh.mask)
|
||||
{
|
||||
if(! d.ws.wr_.autofrag)
|
||||
{
|
||||
d.entry = do_nomask_nofrag;
|
||||
d.entry_state = do_nomask_nofrag;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_.buf_size != 0);
|
||||
d.remain = buffer_size(d.cb);
|
||||
if(d.remain > d.ws.wr_.buf_size)
|
||||
d.entry = do_nomask_frag;
|
||||
d.entry_state = do_nomask_frag;
|
||||
else
|
||||
d.entry = do_nomask_nofrag;
|
||||
d.entry_state = do_nomask_nofrag;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(! d.ws.wr_.autofrag)
|
||||
{
|
||||
d.entry = do_mask_nofrag;
|
||||
d.entry_state = do_mask_nofrag;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_.buf_size != 0);
|
||||
d.remain = buffer_size(d.cb);
|
||||
if(d.remain > d.ws.wr_.buf_size)
|
||||
d.entry = do_mask_frag;
|
||||
d.entry_state = do_mask_frag;
|
||||
else
|
||||
d.entry = do_mask_nofrag;
|
||||
d.entry_state = do_mask_nofrag;
|
||||
}
|
||||
}
|
||||
d.state = do_maybe_suspend;
|
||||
@@ -221,7 +225,13 @@ operator()(error_code ec,
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
case do_nomask_nofrag:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
// [[fallthrough]]
|
||||
|
||||
case do_nomask_nofrag + 1:
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.fh.fin = d.fin;
|
||||
d.fh.len = buffer_size(d.cb);
|
||||
detail::write<static_streambuf>(
|
||||
@@ -229,8 +239,6 @@ operator()(error_code ec,
|
||||
d.ws.wr_.cont = ! d.fin;
|
||||
// Send frame
|
||||
d.state = do_upcall;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
buffer_cat(d.fh_buf.data(), d.cb),
|
||||
std::move(*this));
|
||||
@@ -240,7 +248,13 @@ operator()(error_code ec,
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
case do_nomask_frag:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
// [[fallthrough]]
|
||||
|
||||
case do_nomask_frag + 1:
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
auto const n = clamp(
|
||||
d.remain, d.ws.wr_.buf_size);
|
||||
d.remain -= n;
|
||||
@@ -251,9 +265,7 @@ operator()(error_code ec,
|
||||
d.ws.wr_.cont = ! d.fin;
|
||||
// Send frame
|
||||
d.state = d.remain == 0 ?
|
||||
do_upcall : do_nomask_frag + 1;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
do_upcall : do_nomask_frag + 2;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
buffer_cat(d.fh_buf.data(),
|
||||
prepare_buffers(n, d.cb)),
|
||||
@@ -261,27 +273,36 @@ operator()(error_code ec,
|
||||
return;
|
||||
}
|
||||
|
||||
case do_nomask_frag + 1:
|
||||
case do_nomask_frag + 2:
|
||||
d.cb.consume(
|
||||
bytes_transferred - d.fh_buf.size());
|
||||
d.fh_buf.reset();
|
||||
d.fh.op = opcode::cont;
|
||||
if(d.ws.wr_block_ == &d)
|
||||
d.ws.wr_block_ = nullptr;
|
||||
if(d.ws.rd_op_.maybe_invoke())
|
||||
// Allow outgoing control frames to
|
||||
// be sent in between message frames:
|
||||
if(d.ws.rd_op_.maybe_invoke() ||
|
||||
d.ws.ping_op_.maybe_invoke())
|
||||
{
|
||||
d.state = do_maybe_suspend;
|
||||
d.ws.get_io_service().post(
|
||||
std::move(*this));
|
||||
return;
|
||||
}
|
||||
d.state = d.entry;
|
||||
d.state = d.entry_state;
|
||||
break;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
case do_mask_nofrag:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
// [[fallthrough]]
|
||||
|
||||
case do_mask_nofrag + 1:
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.remain = buffer_size(d.cb);
|
||||
d.fh.fin = d.fin;
|
||||
d.fh.len = d.remain;
|
||||
@@ -299,16 +320,14 @@ operator()(error_code ec,
|
||||
d.ws.wr_.cont = ! d.fin;
|
||||
// Send frame header and partial payload
|
||||
d.state = d.remain == 0 ?
|
||||
do_upcall : do_mask_nofrag + 1;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
do_upcall : do_mask_nofrag + 2;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
buffer_cat(d.fh_buf.data(), b),
|
||||
std::move(*this));
|
||||
return;
|
||||
}
|
||||
|
||||
case do_mask_nofrag + 1:
|
||||
case do_mask_nofrag + 2:
|
||||
{
|
||||
d.cb.consume(d.ws.wr_.buf_size);
|
||||
auto const n =
|
||||
@@ -329,7 +348,13 @@ operator()(error_code ec,
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
case do_mask_frag:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
// [[fallthrough]]
|
||||
|
||||
case do_mask_frag + 1:
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
auto const n = clamp(
|
||||
d.remain, d.ws.wr_.buf_size);
|
||||
d.remain -= n;
|
||||
@@ -346,36 +371,43 @@ operator()(error_code ec,
|
||||
d.ws.wr_.cont = ! d.fin;
|
||||
// Send frame
|
||||
d.state = d.remain == 0 ?
|
||||
do_upcall : do_mask_frag + 1;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
do_upcall : do_mask_frag + 2;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
buffer_cat(d.fh_buf.data(), b),
|
||||
std::move(*this));
|
||||
return;
|
||||
}
|
||||
|
||||
case do_mask_frag + 1:
|
||||
case do_mask_frag + 2:
|
||||
d.cb.consume(
|
||||
bytes_transferred - d.fh_buf.size());
|
||||
d.fh_buf.reset();
|
||||
d.fh.op = opcode::cont;
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.ws.wr_block_ = nullptr;
|
||||
if(d.ws.rd_op_.maybe_invoke())
|
||||
// Allow outgoing control frames to
|
||||
// be sent in between message frames:
|
||||
if(d.ws.rd_op_.maybe_invoke() ||
|
||||
d.ws.ping_op_.maybe_invoke())
|
||||
{
|
||||
d.state = do_maybe_suspend;
|
||||
d.ws.get_io_service().post(
|
||||
std::move(*this));
|
||||
return;
|
||||
}
|
||||
d.state = d.entry;
|
||||
d.state = d.entry_state;
|
||||
break;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
case do_deflate:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
// [[fallthrough]]
|
||||
|
||||
case do_deflate + 1:
|
||||
{
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
auto b = buffer(d.ws.wr_.buf.get(),
|
||||
d.ws.wr_.buf_size);
|
||||
auto const more = detail::deflate(
|
||||
@@ -414,31 +446,32 @@ operator()(error_code ec,
|
||||
d.ws.wr_.cont = ! d.fin;
|
||||
// Send frame
|
||||
d.state = more ?
|
||||
do_deflate + 1 : do_deflate + 2;
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
do_deflate + 2 : do_deflate + 3;
|
||||
boost::asio::async_write(d.ws.stream_,
|
||||
buffer_cat(fh_buf.data(), b),
|
||||
std::move(*this));
|
||||
return;
|
||||
}
|
||||
|
||||
case do_deflate + 1:
|
||||
case do_deflate + 2:
|
||||
d.fh.op = opcode::cont;
|
||||
d.fh.rsv1 = false;
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
d.ws.wr_block_ = nullptr;
|
||||
if(d.ws.rd_op_.maybe_invoke())
|
||||
// Allow outgoing control frames to
|
||||
// be sent in between message frames:
|
||||
if(d.ws.rd_op_.maybe_invoke() ||
|
||||
d.ws.ping_op_.maybe_invoke())
|
||||
{
|
||||
d.state = do_maybe_suspend;
|
||||
d.ws.get_io_service().post(
|
||||
std::move(*this));
|
||||
return;
|
||||
}
|
||||
d.state = d.entry;
|
||||
d.state = d.entry_state;
|
||||
break;
|
||||
|
||||
case do_deflate + 2:
|
||||
case do_deflate + 3:
|
||||
if(d.fh.fin && (
|
||||
(d.ws.role_ == detail::role_type::client &&
|
||||
d.ws.pmd_config_.client_no_context_takeover) ||
|
||||
@@ -468,24 +501,32 @@ operator()(error_code ec,
|
||||
boost::asio::error::operation_aborted));
|
||||
return;
|
||||
}
|
||||
d.state = d.entry;
|
||||
d.state = d.entry_state;
|
||||
break;
|
||||
}
|
||||
|
||||
case do_maybe_suspend + 1:
|
||||
BOOST_ASSERT(! d.ws.wr_block_);
|
||||
d.ws.wr_block_ = &d;
|
||||
d.state = do_maybe_suspend + 2;
|
||||
// The current context is safe but might not be
|
||||
// the same as the one for this operation (since
|
||||
// we are being called from a write operation).
|
||||
// Call post to make sure we are invoked the same
|
||||
// way as the final handler for this operation.
|
||||
d.ws.get_io_service().post(bind_handler(
|
||||
std::move(*this), ec));
|
||||
return;
|
||||
|
||||
case do_maybe_suspend + 2:
|
||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||
if(d.ws.failed_ || d.ws.wr_close_)
|
||||
{
|
||||
// call handler
|
||||
ec = boost::asio::error::operation_aborted;
|
||||
goto upcall;
|
||||
}
|
||||
d.state = d.entry;
|
||||
d.state = d.entry_state + 1;
|
||||
break;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -497,7 +538,8 @@ operator()(error_code ec,
|
||||
upcall:
|
||||
if(d.ws.wr_block_ == &d)
|
||||
d.ws.wr_block_ = nullptr;
|
||||
d.ws.rd_op_.maybe_invoke();
|
||||
d.ws.rd_op_.maybe_invoke() ||
|
||||
d.ws.ping_op_.maybe_invoke();
|
||||
d_.invoke(ec);
|
||||
}
|
||||
|
||||
|
||||
@@ -985,6 +985,10 @@ public:
|
||||
<em>composed operation</em>. The program must ensure that the
|
||||
stream performs no other writes until this operation completes.
|
||||
|
||||
If a close frame is sent or received before the ping frame is
|
||||
sent, the completion handler will be called with the error
|
||||
set to `boost::asio::error::operation_aborted`.
|
||||
|
||||
@param payload The payload of the ping message, which may be empty.
|
||||
|
||||
@param handler The handler to be called when the read operation
|
||||
@@ -1078,6 +1082,10 @@ public:
|
||||
order to send a pong. The remote peer may use the receipt of a
|
||||
pong frame as an indication that the connection is not dead.
|
||||
|
||||
If a close frame is sent or received before the pong frame is
|
||||
sent, the completion handler will be called with the error
|
||||
set to `boost::asio::error::operation_aborted`.
|
||||
|
||||
@param payload The payload of the pong message, which may be empty.
|
||||
|
||||
@param handler The handler to be called when the read operation
|
||||
|
||||
Reference in New Issue
Block a user