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
|
1.0.0-b28
|
||||||
|
|
||||||
* Split out and rename test stream classes
|
* Split out and rename test stream classes
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ This example demonstrates both synchronous and asynchronous
|
|||||||
WebSocket server implementations.
|
WebSocket server implementations.
|
||||||
|
|
||||||
* [@examples/websocket_async_echo_server.hpp]
|
* [@examples/websocket_async_echo_server.hpp]
|
||||||
* [@examples/websocket_ssync_echo_server.hpp]
|
* [@examples/websocket_sync_echo_server.hpp]
|
||||||
* [@examples/websocket_echo.cpp]
|
* [@examples/websocket_echo.cpp]
|
||||||
|
|
||||||
[heading Secure WebSocket]
|
[heading Secure WebSocket]
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ In this table:
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[`Body::reader`]
|
[`X::reader`]
|
||||||
[]
|
[]
|
||||||
[
|
[
|
||||||
If present, a type meeting the requirements of
|
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
|
If present, a type meeting the requirements of
|
||||||
|
|||||||
@@ -167,7 +167,8 @@ public:
|
|||||||
the writer must guarantee that the buffers remain valid until the
|
the writer must guarantee that the buffers remain valid until the
|
||||||
next member function is invoked, which may be the destructor.
|
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.
|
boost::indeterminate to suspend.
|
||||||
|
|
||||||
@note Undefined behavior if the callee takes ownership
|
@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
|
compete with caller-initiated write operations. For the purposes of
|
||||||
correctness with respect to the stream invariants, caller-initiated
|
correctness with respect to the stream invariants, caller-initiated
|
||||||
read operations still only count as a read. This means that callers can
|
read operations still only count as a read. This means that callers can
|
||||||
have a simultaneous active read and write operation in progress, while
|
have a simultaneously active read, write, and ping operation in progress,
|
||||||
the implementation also automatically handles control frames.
|
while the implementation also automatically handles control frames.
|
||||||
|
|
||||||
[heading Ping and Pong Frames]
|
[heading Ping and Pong Frames]
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public:
|
|||||||
: std::basic_ostream<CharT, Traits>(&buf_)
|
: std::basic_ostream<CharT, Traits>(&buf_)
|
||||||
, buf_(os)
|
, buf_(os)
|
||||||
{
|
{
|
||||||
if(os.flags() && std::ios::unitbuf)
|
if(os.flags() & std::ios::unitbuf)
|
||||||
std::unitbuf(*this);
|
std::unitbuf(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -283,7 +283,6 @@ reporter<_>::
|
|||||||
on_log(std::string const& s)
|
on_log(std::string const& s)
|
||||||
{
|
{
|
||||||
os_ << s;
|
os_ << s;
|
||||||
os_.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // detail
|
} // detail
|
||||||
|
|||||||
@@ -352,10 +352,7 @@ public:
|
|||||||
{
|
{
|
||||||
auto const& name = ss_.str();
|
auto const& name = ss_.str();
|
||||||
if(! name.empty())
|
if(! name.empty())
|
||||||
{
|
|
||||||
suite_.log.flush();
|
|
||||||
suite_.runner_->testcase(name);
|
suite_.runner_->testcase(name);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_testcase(suite& self, std::stringstream& ss)
|
scoped_testcase(suite& self, std::stringstream& ss)
|
||||||
@@ -394,7 +391,6 @@ suite::testcase_t::operator()(
|
|||||||
std::string const& name, abort_t abort)
|
std::string const& name, abort_t abort)
|
||||||
{
|
{
|
||||||
suite_.abort_ = abort == abort_on_fail;
|
suite_.abort_ = abort == abort_on_fail;
|
||||||
suite_.log.flush();
|
|
||||||
suite_.runner_->testcase(name);
|
suite_.runner_->testcase(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ class buffer_cat_helper<Bn...>::const_iterator
|
|||||||
iter_t<I>&
|
iter_t<I>&
|
||||||
iter()
|
iter()
|
||||||
{
|
{
|
||||||
|
// type-pun
|
||||||
return *reinterpret_cast<
|
return *reinterpret_cast<
|
||||||
iter_t<I>*>(static_cast<void*>(
|
iter_t<I>*>(static_cast<void*>(
|
||||||
buf_.data()));
|
buf_.data()));
|
||||||
@@ -91,6 +92,7 @@ class buffer_cat_helper<Bn...>::const_iterator
|
|||||||
iter_t<I> const&
|
iter_t<I> const&
|
||||||
iter() const
|
iter() const
|
||||||
{
|
{
|
||||||
|
// type-pun
|
||||||
return *reinterpret_cast<
|
return *reinterpret_cast<
|
||||||
iter_t<I> const*>(static_cast<
|
iter_t<I> const*>(static_cast<
|
||||||
void const*>(buf_.data()));
|
void const*>(buf_.data()));
|
||||||
|
|||||||
@@ -94,11 +94,11 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using list_t = typename boost::intrusive::make_list<
|
using list_t = boost::intrusive::make_list<element,
|
||||||
element, boost::intrusive::constant_time_size<false>>::type;
|
boost::intrusive::constant_time_size<false>>::type;
|
||||||
|
|
||||||
using set_t = typename boost::intrusive::make_multiset<
|
using set_t = boost::intrusive::make_multiset<element,
|
||||||
element, boost::intrusive::constant_time_size<true>,
|
boost::intrusive::constant_time_size<true>,
|
||||||
boost::intrusive::compare<less>>::type;
|
boost::intrusive::compare<less>>::type;
|
||||||
|
|
||||||
// data
|
// data
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#define BEAST_HTTP_DETAIL_RFC7230_HPP
|
#define BEAST_HTTP_DETAIL_RFC7230_HPP
|
||||||
|
|
||||||
#include <boost/utility/string_ref.hpp>
|
#include <boost/utility/string_ref.hpp>
|
||||||
#include <array>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -25,10 +24,10 @@ is_digit(char c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool
|
char
|
||||||
is_alpha(char c)
|
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, // 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, // 16
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
|
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
|
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
|
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
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 112
|
||||||
}};
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128
|
||||||
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, // 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
|
inline
|
||||||
bool
|
char
|
||||||
is_text(char c)
|
is_text(char c)
|
||||||
{
|
{
|
||||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
// 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, 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
|
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
|
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, // 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, // 224
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
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
|
inline
|
||||||
bool
|
char
|
||||||
is_tchar(char c)
|
is_tchar(char c)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -77,7 +86,7 @@ is_tchar(char c)
|
|||||||
"^" | "_" | "`" | "|" | "~" |
|
"^" | "_" | "`" | "|" | "~" |
|
||||||
DIGIT | ALPHA
|
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, // 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, // 16
|
||||||
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32
|
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, 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, 1, 1, 1, 1, 1, // 96
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
|
||||||
}};
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128
|
||||||
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, // 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
|
inline
|
||||||
bool
|
char
|
||||||
is_qdchar(char c)
|
is_qdchar(char c)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
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, 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
|
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
|
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, // 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, // 224
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
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)];
|
return tab[static_cast<std::uint8_t>(c)];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool
|
char
|
||||||
is_qpchar(char c)
|
is_qpchar(char c)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
||||||
obs-text = %x80-FF
|
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, 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
|
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
|
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, // 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, // 224
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
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)];
|
return tab[static_cast<std::uint8_t>(c)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +181,7 @@ to_field_char(char c)
|
|||||||
| "/" | "[" | "]" | "?" | "="
|
| "/" | "[" | "]" | "?" | "="
|
||||||
| "{" | "}" | SP | HT
|
| "{" | "}" | 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, 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',
|
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, '^', '_',
|
||||||
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
'`', '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)];
|
return tab[static_cast<std::uint8_t>(c)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +211,7 @@ char
|
|||||||
to_value_char(char c)
|
to_value_char(char c)
|
||||||
{
|
{
|
||||||
// TEXT = <any OCTET except CTLs, but including LWS>
|
// 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, 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
|
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
|
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
|
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
|
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
|
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)]);
|
return static_cast<char>(tab[static_cast<std::uint8_t>(c)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +237,7 @@ inline
|
|||||||
std::int8_t
|
std::int8_t
|
||||||
unhex(char c)
|
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, // 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, // 16
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
|
-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, 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, -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, 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)];
|
return tab[static_cast<std::uint8_t>(c)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,6 @@
|
|||||||
//
|
//
|
||||||
#define BEAST_VERSION 100000
|
#define BEAST_VERSION 100000
|
||||||
|
|
||||||
#define BEAST_VERSION_STRING "1.0.0-b28"
|
#define BEAST_VERSION_STRING "1.0.0-b30"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ public:
|
|||||||
{
|
{
|
||||||
if(other.base_)
|
if(other.base_)
|
||||||
{
|
{
|
||||||
|
// type-pun
|
||||||
base_ = reinterpret_cast<base*>(&buf_[0]);
|
base_ = reinterpret_cast<base*>(&buf_[0]);
|
||||||
other.base_->move(buf_);
|
other.base_->move(buf_);
|
||||||
other.base_ = nullptr;
|
other.base_ = nullptr;
|
||||||
@@ -109,11 +110,12 @@ public:
|
|||||||
{
|
{
|
||||||
// Engaged invokables must be invoked before
|
// Engaged invokables must be invoked before
|
||||||
// assignment otherwise the io_service
|
// assignment otherwise the io_service
|
||||||
// invariants are broken w.r.t completions.
|
// completion invariants are broken.
|
||||||
BOOST_ASSERT(! base_);
|
BOOST_ASSERT(! base_);
|
||||||
|
|
||||||
if(other.base_)
|
if(other.base_)
|
||||||
{
|
{
|
||||||
|
// type-pun
|
||||||
base_ = reinterpret_cast<base*>(&buf_[0]);
|
base_ = reinterpret_cast<base*>(&buf_[0]);
|
||||||
other.base_->move(buf_);
|
other.base_->move(buf_);
|
||||||
other.base_ = nullptr;
|
other.base_ = nullptr;
|
||||||
@@ -147,6 +149,7 @@ invokable::emplace(F&& f)
|
|||||||
"buffer too small");
|
"buffer too small");
|
||||||
BOOST_ASSERT(! base_);
|
BOOST_ASSERT(! base_);
|
||||||
::new(buf_) holder<F>(std::forward<F>(f));
|
::new(buf_) holder<F>(std::forward<F>(f));
|
||||||
|
// type-pun
|
||||||
base_ = reinterpret_cast<base*>(&buf_[0]);
|
base_ = reinterpret_cast<base*>(&buf_[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,8 +67,9 @@ protected:
|
|||||||
op* wr_block_; // op currenly writing
|
op* wr_block_; // op currenly writing
|
||||||
|
|
||||||
ping_data* ping_data_; // where to put the payload
|
ping_data* ping_data_; // where to put the payload
|
||||||
invokable rd_op_; // invoked after write completes
|
invokable rd_op_; // read parking
|
||||||
invokable wr_op_; // invoked after read completes
|
invokable wr_op_; // write parking
|
||||||
|
invokable ping_op_; // ping parking
|
||||||
close_reason cr_; // set from received close frame
|
close_reason cr_; // set from received close frame
|
||||||
|
|
||||||
// State information for the message being received
|
// State information for the message being received
|
||||||
|
|||||||
@@ -147,25 +147,33 @@ operator()(error_code ec, bool again)
|
|||||||
boost::asio::error::operation_aborted));
|
boost::asio::error::operation_aborted));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// fall through
|
d.ws.wr_block_ = &d;
|
||||||
|
// [[fallthrough]]
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
// send close frame
|
// send close frame
|
||||||
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
d.state = 99;
|
d.state = 99;
|
||||||
d.ws.wr_close_ = true;
|
d.ws.wr_close_ = true;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
d.fb.data(), std::move(*this));
|
d.fb.data(), std::move(*this));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
BOOST_ASSERT(! d.ws.wr_block_);
|
||||||
|
d.ws.wr_block_ = &d;
|
||||||
d.state = 3;
|
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(
|
d.ws.get_io_service().post(
|
||||||
bind_handler(std::move(*this), ec));
|
bind_handler(std::move(*this), ec));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
if(d.ws.failed_ || d.ws.wr_close_)
|
if(d.ws.failed_ || d.ws.wr_close_)
|
||||||
{
|
{
|
||||||
// call handler
|
// call handler
|
||||||
@@ -182,7 +190,8 @@ operator()(error_code ec, bool again)
|
|||||||
upcall:
|
upcall:
|
||||||
if(d.ws.wr_block_ == &d)
|
if(d.ws.wr_block_ == &d)
|
||||||
d.ws.wr_block_ = nullptr;
|
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);
|
d_.invoke(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ operator()(error_code ec, bool again)
|
|||||||
{
|
{
|
||||||
// suspend
|
// suspend
|
||||||
d.state = 2;
|
d.state = 2;
|
||||||
d.ws.wr_op_.template emplace<
|
d.ws.ping_op_.template emplace<
|
||||||
ping_op>(std::move(*this));
|
ping_op>(std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -146,24 +146,32 @@ operator()(error_code ec, bool again)
|
|||||||
boost::asio::error::operation_aborted));
|
boost::asio::error::operation_aborted));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// fall through
|
d.ws.wr_block_ = &d;
|
||||||
|
// [[fallthrough]]
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
// send ping frame
|
// send ping frame
|
||||||
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
d.state = 99;
|
d.state = 99;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
d.fb.data(), std::move(*this));
|
d.fb.data(), std::move(*this));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
BOOST_ASSERT(! d.ws.wr_block_);
|
||||||
|
d.ws.wr_block_ = &d;
|
||||||
d.state = 3;
|
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(
|
d.ws.get_io_service().post(
|
||||||
bind_handler(std::move(*this), ec));
|
bind_handler(std::move(*this), ec));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
if(d.ws.failed_ || d.ws.wr_close_)
|
if(d.ws.failed_ || d.ws.wr_close_)
|
||||||
{
|
{
|
||||||
// call handler
|
// call handler
|
||||||
@@ -180,7 +188,8 @@ operator()(error_code ec, bool again)
|
|||||||
upcall:
|
upcall:
|
||||||
if(d.ws.wr_block_ == &d)
|
if(d.ws.wr_block_ == &d)
|
||||||
d.ws.wr_block_ = nullptr;
|
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);
|
d_.invoke(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -499,6 +499,8 @@ operator()(error_code ec,
|
|||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
case do_pong_resume:
|
case do_pong_resume:
|
||||||
|
BOOST_ASSERT(! d.ws.wr_block_);
|
||||||
|
d.ws.wr_block_ = &d;
|
||||||
d.state = do_pong_resume + 1;
|
d.state = do_pong_resume + 1;
|
||||||
d.ws.get_io_service().post(bind_handler(
|
d.ws.get_io_service().post(bind_handler(
|
||||||
std::move(*this), ec, bytes_transferred));
|
std::move(*this), ec, bytes_transferred));
|
||||||
@@ -511,8 +513,7 @@ operator()(error_code ec,
|
|||||||
ec = boost::asio::error::operation_aborted;
|
ec = boost::asio::error::operation_aborted;
|
||||||
goto upcall;
|
goto upcall;
|
||||||
}
|
}
|
||||||
d.state = do_pong;
|
// [[fallthrough]]
|
||||||
break; // VFALCO fall through?
|
|
||||||
|
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -520,14 +521,21 @@ operator()(error_code ec,
|
|||||||
if(d.ws.wr_close_)
|
if(d.ws.wr_close_)
|
||||||
{
|
{
|
||||||
// ignore ping when closing
|
// 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.fb.reset();
|
||||||
d.state = do_read_fh;
|
d.state = do_read_fh;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// send pong
|
// 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;
|
d.state = do_pong + 1;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
d.fb.data(), std::move(*this));
|
d.fb.data(), std::move(*this));
|
||||||
return;
|
return;
|
||||||
@@ -541,18 +549,25 @@ operator()(error_code ec,
|
|||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
case do_close_resume:
|
case do_close_resume:
|
||||||
|
BOOST_ASSERT(! d.ws.wr_block_);
|
||||||
|
d.ws.wr_block_ = &d;
|
||||||
d.state = do_close_resume + 1;
|
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(
|
d.ws.get_io_service().post(bind_handler(
|
||||||
std::move(*this), ec, bytes_transferred));
|
std::move(*this), ec, bytes_transferred));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case do_close_resume + 1:
|
case do_close_resume + 1:
|
||||||
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
if(d.ws.failed_)
|
if(d.ws.failed_)
|
||||||
{
|
{
|
||||||
// call handler
|
// call handler
|
||||||
d.state = do_call_handler;
|
|
||||||
ec = boost::asio::error::operation_aborted;
|
ec = boost::asio::error::operation_aborted;
|
||||||
break;
|
goto upcall;
|
||||||
}
|
}
|
||||||
if(d.ws.wr_close_)
|
if(d.ws.wr_close_)
|
||||||
{
|
{
|
||||||
@@ -566,10 +581,12 @@ operator()(error_code ec,
|
|||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
|
||||||
case do_close:
|
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.state = do_teardown;
|
||||||
d.ws.wr_close_ = true;
|
d.ws.wr_close_ = true;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
d.fb.data(), std::move(*this));
|
d.fb.data(), std::move(*this));
|
||||||
return;
|
return;
|
||||||
@@ -656,7 +673,8 @@ operator()(error_code ec,
|
|||||||
upcall:
|
upcall:
|
||||||
if(d.ws.wr_block_ == &d)
|
if(d.ws.wr_block_ == &d)
|
||||||
d.ws.wr_block_ = nullptr;
|
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);
|
d_.invoke(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class stream<NextLayer>::write_frame_op
|
|||||||
detail::prepared_key key;
|
detail::prepared_key key;
|
||||||
std::uint64_t remain;
|
std::uint64_t remain;
|
||||||
int state = 0;
|
int state = 0;
|
||||||
int entry;
|
int entry_state;
|
||||||
|
|
||||||
data(Handler& handler_, stream<NextLayer>& ws_,
|
data(Handler& handler_, stream<NextLayer>& ws_,
|
||||||
bool fin_, Buffers const& bs)
|
bool fin_, Buffers const& bs)
|
||||||
@@ -179,40 +179,44 @@ operator()(error_code ec,
|
|||||||
d.fh.mask =
|
d.fh.mask =
|
||||||
d.ws.role_ == detail::role_type::client;
|
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)
|
if(d.ws.wr_.compress)
|
||||||
{
|
{
|
||||||
d.entry = do_deflate;
|
d.entry_state = do_deflate;
|
||||||
}
|
}
|
||||||
else if(! d.fh.mask)
|
else if(! d.fh.mask)
|
||||||
{
|
{
|
||||||
if(! d.ws.wr_.autofrag)
|
if(! d.ws.wr_.autofrag)
|
||||||
{
|
{
|
||||||
d.entry = do_nomask_nofrag;
|
d.entry_state = do_nomask_nofrag;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(d.ws.wr_.buf_size != 0);
|
BOOST_ASSERT(d.ws.wr_.buf_size != 0);
|
||||||
d.remain = buffer_size(d.cb);
|
d.remain = buffer_size(d.cb);
|
||||||
if(d.remain > d.ws.wr_.buf_size)
|
if(d.remain > d.ws.wr_.buf_size)
|
||||||
d.entry = do_nomask_frag;
|
d.entry_state = do_nomask_frag;
|
||||||
else
|
else
|
||||||
d.entry = do_nomask_nofrag;
|
d.entry_state = do_nomask_nofrag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(! d.ws.wr_.autofrag)
|
if(! d.ws.wr_.autofrag)
|
||||||
{
|
{
|
||||||
d.entry = do_mask_nofrag;
|
d.entry_state = do_mask_nofrag;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(d.ws.wr_.buf_size != 0);
|
BOOST_ASSERT(d.ws.wr_.buf_size != 0);
|
||||||
d.remain = buffer_size(d.cb);
|
d.remain = buffer_size(d.cb);
|
||||||
if(d.remain > d.ws.wr_.buf_size)
|
if(d.remain > d.ws.wr_.buf_size)
|
||||||
d.entry = do_mask_frag;
|
d.entry_state = do_mask_frag;
|
||||||
else
|
else
|
||||||
d.entry = do_mask_nofrag;
|
d.entry_state = do_mask_nofrag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.state = do_maybe_suspend;
|
d.state = do_maybe_suspend;
|
||||||
@@ -221,7 +225,13 @@ operator()(error_code ec,
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
case do_nomask_nofrag:
|
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.fin = d.fin;
|
||||||
d.fh.len = buffer_size(d.cb);
|
d.fh.len = buffer_size(d.cb);
|
||||||
detail::write<static_streambuf>(
|
detail::write<static_streambuf>(
|
||||||
@@ -229,8 +239,6 @@ operator()(error_code ec,
|
|||||||
d.ws.wr_.cont = ! d.fin;
|
d.ws.wr_.cont = ! d.fin;
|
||||||
// Send frame
|
// Send frame
|
||||||
d.state = do_upcall;
|
d.state = do_upcall;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
buffer_cat(d.fh_buf.data(), d.cb),
|
buffer_cat(d.fh_buf.data(), d.cb),
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
@@ -240,7 +248,13 @@ operator()(error_code ec,
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
case do_nomask_frag:
|
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(
|
auto const n = clamp(
|
||||||
d.remain, d.ws.wr_.buf_size);
|
d.remain, d.ws.wr_.buf_size);
|
||||||
d.remain -= n;
|
d.remain -= n;
|
||||||
@@ -251,9 +265,7 @@ operator()(error_code ec,
|
|||||||
d.ws.wr_.cont = ! d.fin;
|
d.ws.wr_.cont = ! d.fin;
|
||||||
// Send frame
|
// Send frame
|
||||||
d.state = d.remain == 0 ?
|
d.state = d.remain == 0 ?
|
||||||
do_upcall : do_nomask_frag + 1;
|
do_upcall : do_nomask_frag + 2;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
buffer_cat(d.fh_buf.data(),
|
buffer_cat(d.fh_buf.data(),
|
||||||
prepare_buffers(n, d.cb)),
|
prepare_buffers(n, d.cb)),
|
||||||
@@ -261,27 +273,36 @@ operator()(error_code ec,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case do_nomask_frag + 1:
|
case do_nomask_frag + 2:
|
||||||
d.cb.consume(
|
d.cb.consume(
|
||||||
bytes_transferred - d.fh_buf.size());
|
bytes_transferred - d.fh_buf.size());
|
||||||
d.fh_buf.reset();
|
d.fh_buf.reset();
|
||||||
d.fh.op = opcode::cont;
|
d.fh.op = opcode::cont;
|
||||||
if(d.ws.wr_block_ == &d)
|
if(d.ws.wr_block_ == &d)
|
||||||
d.ws.wr_block_ = nullptr;
|
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.state = do_maybe_suspend;
|
||||||
d.ws.get_io_service().post(
|
d.ws.get_io_service().post(
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d.state = d.entry;
|
d.state = d.entry_state;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
case do_mask_nofrag:
|
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.remain = buffer_size(d.cb);
|
||||||
d.fh.fin = d.fin;
|
d.fh.fin = d.fin;
|
||||||
d.fh.len = d.remain;
|
d.fh.len = d.remain;
|
||||||
@@ -299,16 +320,14 @@ operator()(error_code ec,
|
|||||||
d.ws.wr_.cont = ! d.fin;
|
d.ws.wr_.cont = ! d.fin;
|
||||||
// Send frame header and partial payload
|
// Send frame header and partial payload
|
||||||
d.state = d.remain == 0 ?
|
d.state = d.remain == 0 ?
|
||||||
do_upcall : do_mask_nofrag + 1;
|
do_upcall : do_mask_nofrag + 2;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
buffer_cat(d.fh_buf.data(), b),
|
buffer_cat(d.fh_buf.data(), b),
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case do_mask_nofrag + 1:
|
case do_mask_nofrag + 2:
|
||||||
{
|
{
|
||||||
d.cb.consume(d.ws.wr_.buf_size);
|
d.cb.consume(d.ws.wr_.buf_size);
|
||||||
auto const n =
|
auto const n =
|
||||||
@@ -329,7 +348,13 @@ operator()(error_code ec,
|
|||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
case do_mask_frag:
|
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(
|
auto const n = clamp(
|
||||||
d.remain, d.ws.wr_.buf_size);
|
d.remain, d.ws.wr_.buf_size);
|
||||||
d.remain -= n;
|
d.remain -= n;
|
||||||
@@ -346,36 +371,43 @@ operator()(error_code ec,
|
|||||||
d.ws.wr_.cont = ! d.fin;
|
d.ws.wr_.cont = ! d.fin;
|
||||||
// Send frame
|
// Send frame
|
||||||
d.state = d.remain == 0 ?
|
d.state = d.remain == 0 ?
|
||||||
do_upcall : do_mask_frag + 1;
|
do_upcall : do_mask_frag + 2;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
buffer_cat(d.fh_buf.data(), b),
|
buffer_cat(d.fh_buf.data(), b),
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case do_mask_frag + 1:
|
case do_mask_frag + 2:
|
||||||
d.cb.consume(
|
d.cb.consume(
|
||||||
bytes_transferred - d.fh_buf.size());
|
bytes_transferred - d.fh_buf.size());
|
||||||
d.fh_buf.reset();
|
d.fh_buf.reset();
|
||||||
d.fh.op = opcode::cont;
|
d.fh.op = opcode::cont;
|
||||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
d.ws.wr_block_ = nullptr;
|
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.state = do_maybe_suspend;
|
||||||
d.ws.get_io_service().post(
|
d.ws.get_io_service().post(
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d.state = d.entry;
|
d.state = d.entry_state;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
case do_deflate:
|
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(),
|
auto b = buffer(d.ws.wr_.buf.get(),
|
||||||
d.ws.wr_.buf_size);
|
d.ws.wr_.buf_size);
|
||||||
auto const more = detail::deflate(
|
auto const more = detail::deflate(
|
||||||
@@ -414,31 +446,32 @@ operator()(error_code ec,
|
|||||||
d.ws.wr_.cont = ! d.fin;
|
d.ws.wr_.cont = ! d.fin;
|
||||||
// Send frame
|
// Send frame
|
||||||
d.state = more ?
|
d.state = more ?
|
||||||
do_deflate + 1 : do_deflate + 2;
|
do_deflate + 2 : do_deflate + 3;
|
||||||
BOOST_ASSERT(! d.ws.wr_block_);
|
|
||||||
d.ws.wr_block_ = &d;
|
|
||||||
boost::asio::async_write(d.ws.stream_,
|
boost::asio::async_write(d.ws.stream_,
|
||||||
buffer_cat(fh_buf.data(), b),
|
buffer_cat(fh_buf.data(), b),
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case do_deflate + 1:
|
case do_deflate + 2:
|
||||||
d.fh.op = opcode::cont;
|
d.fh.op = opcode::cont;
|
||||||
d.fh.rsv1 = false;
|
d.fh.rsv1 = false;
|
||||||
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
d.ws.wr_block_ = nullptr;
|
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.state = do_maybe_suspend;
|
||||||
d.ws.get_io_service().post(
|
d.ws.get_io_service().post(
|
||||||
std::move(*this));
|
std::move(*this));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d.state = d.entry;
|
d.state = d.entry_state;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case do_deflate + 2:
|
case do_deflate + 3:
|
||||||
if(d.fh.fin && (
|
if(d.fh.fin && (
|
||||||
(d.ws.role_ == detail::role_type::client &&
|
(d.ws.role_ == detail::role_type::client &&
|
||||||
d.ws.pmd_config_.client_no_context_takeover) ||
|
d.ws.pmd_config_.client_no_context_takeover) ||
|
||||||
@@ -468,24 +501,32 @@ operator()(error_code ec,
|
|||||||
boost::asio::error::operation_aborted));
|
boost::asio::error::operation_aborted));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
d.state = d.entry;
|
d.state = d.entry_state;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case do_maybe_suspend + 1:
|
case do_maybe_suspend + 1:
|
||||||
|
BOOST_ASSERT(! d.ws.wr_block_);
|
||||||
|
d.ws.wr_block_ = &d;
|
||||||
d.state = do_maybe_suspend + 2;
|
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(
|
d.ws.get_io_service().post(bind_handler(
|
||||||
std::move(*this), ec));
|
std::move(*this), ec));
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case do_maybe_suspend + 2:
|
case do_maybe_suspend + 2:
|
||||||
|
BOOST_ASSERT(d.ws.wr_block_ == &d);
|
||||||
if(d.ws.failed_ || d.ws.wr_close_)
|
if(d.ws.failed_ || d.ws.wr_close_)
|
||||||
{
|
{
|
||||||
// call handler
|
// call handler
|
||||||
ec = boost::asio::error::operation_aborted;
|
ec = boost::asio::error::operation_aborted;
|
||||||
goto upcall;
|
goto upcall;
|
||||||
}
|
}
|
||||||
d.state = d.entry;
|
d.state = d.entry_state + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@@ -497,7 +538,8 @@ operator()(error_code ec,
|
|||||||
upcall:
|
upcall:
|
||||||
if(d.ws.wr_block_ == &d)
|
if(d.ws.wr_block_ == &d)
|
||||||
d.ws.wr_block_ = nullptr;
|
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);
|
d_.invoke(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -985,6 +985,10 @@ public:
|
|||||||
<em>composed operation</em>. The program must ensure that the
|
<em>composed operation</em>. The program must ensure that the
|
||||||
stream performs no other writes until this operation completes.
|
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 payload The payload of the ping message, which may be empty.
|
||||||
|
|
||||||
@param handler The handler to be called when the read operation
|
@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
|
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.
|
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 payload The payload of the pong message, which may be empty.
|
||||||
|
|
||||||
@param handler The handler to be called when the read operation
|
@param handler The handler to be called when the read operation
|
||||||
|
|||||||
Reference in New Issue
Block a user