mirror of
https://github.com/boostorg/beast.git
synced 2025-07-30 21:07:26 +02:00
control_callback replaces ping_callback (API Change):
fix #322 The new callback is informed of all frame types including close. Actions Required: * Change calls to websocket::stream::ping_callback to use websocket::stream::control_callback * Change user defined ping callbacks to have the new signature and adjust the callback definition appropriately.
This commit is contained in:
12
CHANGELOG.md
12
CHANGELOG.md
@ -5,6 +5,18 @@ Version 67:
|
|||||||
* Merge stream_base to stream and tidy
|
* Merge stream_base to stream and tidy
|
||||||
* Use boost::string_view
|
* Use boost::string_view
|
||||||
|
|
||||||
|
API Changes:
|
||||||
|
|
||||||
|
* control_callback replaces ping_callback
|
||||||
|
|
||||||
|
Actions Required:
|
||||||
|
|
||||||
|
* Change calls to websocket::stream::ping_callback to use
|
||||||
|
websocket::stream::control_callback
|
||||||
|
|
||||||
|
* Change user defined ping callbacks to have the new
|
||||||
|
signature and adjust the callback definition appropriately.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
Version 66:
|
Version 66:
|
||||||
|
@ -25,9 +25,10 @@ During read operations, Beast automatically reads and processes control
|
|||||||
frames. Pings are replied to as soon as possible with a pong, received
|
frames. Pings are replied to as soon as possible with a pong, received
|
||||||
ping and pongs are delivered to the ping callback. The receipt of a close
|
ping and pongs are delivered to the ping callback. The receipt of a close
|
||||||
frame initiates the WebSocket close procedure, eventually resulting in the
|
frame initiates the WebSocket close procedure, eventually resulting in the
|
||||||
error code [link beast.ref.beast__websocket__error `error::closed`] being delivered
|
error code
|
||||||
to the caller in a subsequent read operation, assuming no other error
|
[link beast.ref.beast__websocket__error `error::closed`]
|
||||||
takes place.
|
being delivered to the caller in a subsequent read operation, assuming
|
||||||
|
no other error takes place.
|
||||||
|
|
||||||
A consequence of this automatic behavior is that caller-initiated read
|
A consequence of this automatic behavior is that caller-initiated read
|
||||||
operations can cause socket writes. However, these writes will not
|
operations can cause socket writes. However, these writes will not
|
||||||
@ -37,16 +38,16 @@ read operations still only count as a read. This means that callers can
|
|||||||
have a simultaneously active read, write, and ping operation in progress,
|
have a simultaneously active read, write, and ping operation in progress,
|
||||||
while the implementation also automatically handles control frames.
|
while the implementation also automatically handles control frames.
|
||||||
|
|
||||||
[heading Ping and Pong Frames]
|
[heading Control Callback]
|
||||||
|
|
||||||
Ping and pong messages are control frames which may be sent at any time
|
Ping and pong messages are control frames which may be sent at any time
|
||||||
by either peer on an established WebSocket connection. They are sent
|
by either peer on an established WebSocket connection. They are sent
|
||||||
using the functions
|
using the functions
|
||||||
[link beast.ref.beast__websocket__stream.ping `ping`] and
|
[link beast.ref.beast__websocket__stream.ping `ping`] and
|
||||||
[link beast.ref.beast__websocket__stream.pong `pong`].
|
[link beast.ref.beast__websocket__stream.pong `pong`].
|
||||||
|
To be notified of control frames, including pings, pongs, and close frames,
|
||||||
To be notified of ping and pong control frames, callers may register a
|
callers may register a ['control callback] using
|
||||||
"ping callback" using [link beast.ref.beast__websocket__stream.set_option `set_option`].
|
[link beast.ref.beast__websocket__stream.control_callback `control_callback`].
|
||||||
The object provided with this option should be callable with the following
|
The object provided with this option should be callable with the following
|
||||||
signature:
|
signature:
|
||||||
|
|
||||||
@ -66,9 +67,10 @@ to receive pings and pongs, a synchronous or asynchronous stream read
|
|||||||
function must be active.
|
function must be active.
|
||||||
|
|
||||||
[note
|
[note
|
||||||
When an asynchronous read function receives a ping or pong, the
|
When an asynchronous read function receives a control frame, the
|
||||||
ping callback is invoked in the same manner as that used to invoke
|
control callback is invoked in the same manner as that used to
|
||||||
the final completion handler of the corresponding read function.
|
invoke the final completion handler of the corresponding read
|
||||||
|
function.
|
||||||
]
|
]
|
||||||
|
|
||||||
[heading Close Frames]
|
[heading Close Frames]
|
||||||
|
@ -132,6 +132,7 @@
|
|||||||
<simplelist type="vert" columns="1">
|
<simplelist type="vert" columns="1">
|
||||||
<member><link linkend="beast.ref.beast__websocket__close_code">close_code</link></member>
|
<member><link linkend="beast.ref.beast__websocket__close_code">close_code</link></member>
|
||||||
<member><link linkend="beast.ref.beast__websocket__error">error</link></member>
|
<member><link linkend="beast.ref.beast__websocket__error">error</link></member>
|
||||||
|
<member><link linkend="beast.ref.beast__websocket__frame_type">frame_type</link></member>
|
||||||
</simplelist>
|
</simplelist>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
|
@ -437,8 +437,9 @@ operator()(error_code ec,
|
|||||||
ping_data payload;
|
ping_data payload;
|
||||||
detail::read(payload, d.fb.data());
|
detail::read(payload, d.fb.data());
|
||||||
d.fb.consume(d.fb.size());
|
d.fb.consume(d.fb.size());
|
||||||
if(d.ws.ping_cb_)
|
if(d.ws.ctrl_cb_)
|
||||||
d.ws.ping_cb_(false, payload);
|
d.ws.ctrl_cb_(
|
||||||
|
frame_type::ping, payload);
|
||||||
if(d.ws.wr_close_)
|
if(d.ws.wr_close_)
|
||||||
{
|
{
|
||||||
// ignore ping when closing
|
// ignore ping when closing
|
||||||
@ -463,8 +464,9 @@ operator()(error_code ec,
|
|||||||
code = close_code::none;
|
code = close_code::none;
|
||||||
ping_data payload;
|
ping_data payload;
|
||||||
detail::read(payload, d.fb.data());
|
detail::read(payload, d.fb.data());
|
||||||
if(d.ws.ping_cb_)
|
if(d.ws.ctrl_cb_)
|
||||||
d.ws.ping_cb_(true, payload);
|
d.ws.ctrl_cb_(
|
||||||
|
frame_type::pong, payload);
|
||||||
d.fb.consume(d.fb.size());
|
d.fb.consume(d.fb.size());
|
||||||
d.state = do_read_fh;
|
d.state = do_read_fh;
|
||||||
break;
|
break;
|
||||||
@ -478,6 +480,9 @@ operator()(error_code ec,
|
|||||||
d.state = do_fail;
|
d.state = do_fail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(d.ws.ctrl_cb_)
|
||||||
|
d.ws.ctrl_cb_(frame_type::close,
|
||||||
|
d.ws.cr_.reason);
|
||||||
if(! d.ws.wr_close_)
|
if(! d.ws.wr_close_)
|
||||||
{
|
{
|
||||||
auto cr = d.ws.cr_;
|
auto cr = d.ws.cr_;
|
||||||
@ -791,8 +796,8 @@ read_frame(DynamicBuffer& dynabuf, error_code& ec)
|
|||||||
ping_data payload;
|
ping_data payload;
|
||||||
detail::read(payload, fb.data());
|
detail::read(payload, fb.data());
|
||||||
fb.consume(fb.size());
|
fb.consume(fb.size());
|
||||||
if(ping_cb_)
|
if(ctrl_cb_)
|
||||||
ping_cb_(false, payload);
|
ctrl_cb_(frame_type::ping, payload);
|
||||||
write_ping<static_buffer>(fb,
|
write_ping<static_buffer>(fb,
|
||||||
detail::opcode::pong, payload);
|
detail::opcode::pong, payload);
|
||||||
boost::asio::write(stream_, fb.data(), ec);
|
boost::asio::write(stream_, fb.data(), ec);
|
||||||
@ -805,8 +810,8 @@ read_frame(DynamicBuffer& dynabuf, error_code& ec)
|
|||||||
{
|
{
|
||||||
ping_data payload;
|
ping_data payload;
|
||||||
detail::read(payload, fb.data());
|
detail::read(payload, fb.data());
|
||||||
if(ping_cb_)
|
if(ctrl_cb_)
|
||||||
ping_cb_(true, payload);
|
ctrl_cb_(frame_type::pong, payload);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BOOST_ASSERT(fh.op == detail::opcode::close);
|
BOOST_ASSERT(fh.op == detail::opcode::close);
|
||||||
@ -814,6 +819,8 @@ read_frame(DynamicBuffer& dynabuf, error_code& ec)
|
|||||||
detail::read(cr_, fb.data(), code);
|
detail::read(cr_, fb.data(), code);
|
||||||
if(code != close_code::none)
|
if(code != close_code::none)
|
||||||
goto do_close;
|
goto do_close;
|
||||||
|
if(ctrl_cb_)
|
||||||
|
ctrl_cb_(frame_type::close, cr_.reason);
|
||||||
if(! wr_close_)
|
if(! wr_close_)
|
||||||
{
|
{
|
||||||
auto cr = cr_;
|
auto cr = cr_;
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
@ -47,6 +48,22 @@ using request_type = http::request<http::empty_body>;
|
|||||||
/// The type of object holding HTTP Upgrade responses
|
/// The type of object holding HTTP Upgrade responses
|
||||||
using response_type = http::response<http::string_body>;
|
using response_type = http::response<http::string_body>;
|
||||||
|
|
||||||
|
/** The type of received control frame.
|
||||||
|
|
||||||
|
Values of this type are passed to the control frame
|
||||||
|
callback set using @ref stream::control_callback.
|
||||||
|
*/
|
||||||
|
enum class frame_type
|
||||||
|
{
|
||||||
|
/// A close frame was received
|
||||||
|
close,
|
||||||
|
|
||||||
|
/// A ping frame was received
|
||||||
|
ping,
|
||||||
|
|
||||||
|
/// A pong frame was received
|
||||||
|
pong
|
||||||
|
};
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
@ -112,8 +129,8 @@ class stream
|
|||||||
|
|
||||||
friend class frame_test;
|
friend class frame_test;
|
||||||
|
|
||||||
using ping_callback_type =
|
using control_cb_type =
|
||||||
std::function<void(bool, ping_data const&)>;
|
std::function<void(frame_type, string_view)>;
|
||||||
|
|
||||||
struct op {};
|
struct op {};
|
||||||
|
|
||||||
@ -125,7 +142,7 @@ class stream
|
|||||||
std::size_t rd_buf_size_ = 4096; // read buffer size
|
std::size_t rd_buf_size_ = 4096; // read buffer size
|
||||||
detail::opcode wr_opcode_ =
|
detail::opcode wr_opcode_ =
|
||||||
detail::opcode::text; // outgoing message type
|
detail::opcode::text; // outgoing message type
|
||||||
ping_callback_type ping_cb_; // ping callback
|
control_cb_type ctrl_cb_; // control callback
|
||||||
role_type role_; // server or client
|
role_type role_; // server or client
|
||||||
bool failed_; // the connection failed
|
bool failed_; // the connection failed
|
||||||
|
|
||||||
@ -453,10 +470,11 @@ public:
|
|||||||
return wr_opcode_ == detail::opcode::binary;
|
return wr_opcode_ == detail::opcode::binary;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the ping callback.
|
/** Set the control frame callback.
|
||||||
|
|
||||||
Sets the callback to be invoked whenever a ping or pong is
|
Sets the callback to be invoked whenever a ping, pong,
|
||||||
received during a call to one of the following functions:
|
or close control frame is received during a call to one
|
||||||
|
of the following functions:
|
||||||
|
|
||||||
@li @ref beast::websocket::stream::read
|
@li @ref beast::websocket::stream::read
|
||||||
@li @ref beast::websocket::stream::read_frame
|
@li @ref beast::websocket::stream::read_frame
|
||||||
@ -464,33 +482,38 @@ public:
|
|||||||
@li @ref beast::websocket::stream::async_read_frame
|
@li @ref beast::websocket::stream::async_read_frame
|
||||||
|
|
||||||
Unlike completion handlers, the callback will be invoked
|
Unlike completion handlers, the callback will be invoked
|
||||||
for each received ping and pong during a call to any
|
for each control frame during a call to any synchronous
|
||||||
synchronous or asynchronous read function. The operation is
|
or asynchronous read function. The operation is passive,
|
||||||
passive, with no associated error code, and triggered by reads.
|
with no associated error code, and triggered by reads.
|
||||||
|
|
||||||
The signature of the callback must be:
|
The signature of the callback must be:
|
||||||
@code
|
@code
|
||||||
void
|
void
|
||||||
callback(
|
callback(
|
||||||
bool is_pong, // `true` if this is a pong
|
frame_type kind, // The type of frame
|
||||||
ping_data const& payload // Payload of the pong frame
|
string_view payload // The payload in the frame
|
||||||
);
|
);
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
The value of `is_pong` will be `true` if a pong control frame
|
For close frames, the close reason code may be obtained by
|
||||||
is received, and `false` if a ping control frame is received.
|
calling the function @ref reason.
|
||||||
|
|
||||||
If the read operation receiving a ping or pong frame is an
|
If the read operation which receives the control frame is
|
||||||
asynchronous operation, the callback will be invoked using
|
an asynchronous operation, the callback will be invoked using
|
||||||
the same method as that used to invoke the final handler.
|
the same method as that used to invoke the final handler.
|
||||||
|
|
||||||
|
@note It is not necessary to send a close frame upon receipt
|
||||||
|
of a close frame. The implementation does this automatically.
|
||||||
|
Attempting to send a close frame after a close frame is
|
||||||
|
received will result in undefined behavior.
|
||||||
|
|
||||||
@param cb The callback to set.
|
@param cb The callback to set.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ping_callback(
|
control_callback(
|
||||||
std::function<void(bool, ping_data const&)> cb)
|
std::function<void(frame_type, string_view)> cb)
|
||||||
{
|
{
|
||||||
ping_cb_ = std::move(cb);
|
ctrl_cb_ = std::move(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the read buffer size option.
|
/** Set the read buffer size option.
|
||||||
@ -2757,7 +2780,7 @@ public:
|
|||||||
|
|
||||||
@li A pong frame is sent when a ping frame is received.
|
@li A pong frame is sent when a ping frame is received.
|
||||||
|
|
||||||
@li The @ref ping_callback is invoked when a ping frame
|
@li The @ref control_callback is invoked when a ping frame
|
||||||
or pong frame is received.
|
or pong frame is received.
|
||||||
|
|
||||||
@li The WebSocket close procedure is started if a close frame
|
@li The WebSocket close procedure is started if a close frame
|
||||||
@ -2794,7 +2817,7 @@ public:
|
|||||||
During reads, the implementation handles control frames as
|
During reads, the implementation handles control frames as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
@li The @ref ping_callback is invoked when a ping frame
|
@li The @ref control_callback is invoked when a ping frame
|
||||||
or pong frame is received.
|
or pong frame is received.
|
||||||
|
|
||||||
@li A pong frame is sent when a ping frame is received.
|
@li A pong frame is sent when a ping frame is received.
|
||||||
@ -2838,7 +2861,7 @@ public:
|
|||||||
During reads, the implementation handles control frames as
|
During reads, the implementation handles control frames as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
@li The @ref ping_callback is invoked when a ping frame
|
@li The @ref control_callback is invoked when a ping frame
|
||||||
or pong frame is received.
|
or pong frame is received.
|
||||||
|
|
||||||
@li A pong frame is sent when a ping frame is received.
|
@li A pong frame is sent when a ping frame is received.
|
||||||
@ -2895,7 +2918,7 @@ public:
|
|||||||
During reads, the implementation handles control frames as
|
During reads, the implementation handles control frames as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
@li The @ref ping_callback is invoked when a ping frame
|
@li The @ref control_callback is invoked when a ping frame
|
||||||
or pong frame is received.
|
or pong frame is received.
|
||||||
|
|
||||||
@li A pong frame is sent when a ping frame is received.
|
@li A pong frame is sent when a ping frame is received.
|
||||||
@ -2931,7 +2954,7 @@ public:
|
|||||||
During reads, the implementation handles control frames as
|
During reads, the implementation handles control frames as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
@li The @ref ping_callback is invoked when a ping frame
|
@li The @ref control_callback is invoked when a ping frame
|
||||||
or pong frame is received.
|
or pong frame is received.
|
||||||
|
|
||||||
@li A pong frame is sent when a ping frame is received.
|
@li A pong frame is sent when a ping frame is received.
|
||||||
@ -2971,7 +2994,7 @@ public:
|
|||||||
During reads, the implementation handles control frames as
|
During reads, the implementation handles control frames as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
@li The @ref ping_callback is invoked when a ping frame
|
@li The @ref control_callback is invoked when a ping frame
|
||||||
or pong frame is received.
|
or pong frame is received.
|
||||||
|
|
||||||
@li A pong frame is sent when a ping frame is received.
|
@li A pong frame is sent when a ping frame is received.
|
||||||
|
@ -187,11 +187,11 @@ boost::asio::ip::tcp::socket sock{ios};
|
|||||||
{
|
{
|
||||||
stream<boost::asio::ip::tcp::socket> ws{ios};
|
stream<boost::asio::ip::tcp::socket> ws{ios};
|
||||||
//[ws_snippet_17
|
//[ws_snippet_17
|
||||||
ws.ping_callback(
|
ws.control_callback(
|
||||||
[](bool is_pong, ping_data const& payload)
|
[](frame_type kind, string_view payload)
|
||||||
{
|
{
|
||||||
// Do something with the payload
|
// Do something with the payload
|
||||||
boost::ignore_unused(is_pong, payload);
|
boost::ignore_unused(kind, payload);
|
||||||
});
|
});
|
||||||
//]
|
//]
|
||||||
|
|
||||||
|
@ -1656,15 +1656,17 @@ public:
|
|||||||
c.close(ws, {close_code::going_away, "Going away"});
|
c.close(ws, {close_code::going_away, "Going away"});
|
||||||
restart(error::closed);
|
restart(error::closed);
|
||||||
|
|
||||||
|
bool once;
|
||||||
|
|
||||||
// send ping and message
|
// send ping and message
|
||||||
bool pong = false;
|
once = false;
|
||||||
ws.ping_callback(
|
ws.control_callback(
|
||||||
[&](bool is_pong, ping_data const& payload)
|
[&](frame_type kind, string_view s)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(is_pong);
|
BEAST_EXPECT(kind == frame_type::pong);
|
||||||
BEAST_EXPECT(! pong);
|
BEAST_EXPECT(! once);
|
||||||
pong = true;
|
once = true;
|
||||||
BEAST_EXPECT(payload == "");
|
BEAST_EXPECT(s == "");
|
||||||
});
|
});
|
||||||
c.ping(ws, "");
|
c.ping(ws, "");
|
||||||
ws.binary(true);
|
ws.binary(true);
|
||||||
@ -1673,18 +1675,21 @@ public:
|
|||||||
// receive echoed message
|
// receive echoed message
|
||||||
multi_buffer db;
|
multi_buffer db;
|
||||||
c.read(ws, db);
|
c.read(ws, db);
|
||||||
BEAST_EXPECT(pong == 1);
|
BEAST_EXPECT(once);
|
||||||
BEAST_EXPECT(ws.got_binary());
|
BEAST_EXPECT(ws.got_binary());
|
||||||
BEAST_EXPECT(to_string(db.data()) == "Hello");
|
BEAST_EXPECT(to_string(db.data()) == "Hello");
|
||||||
}
|
}
|
||||||
ws.ping_callback({});
|
ws.control_callback({});
|
||||||
|
|
||||||
// send ping and fragmented message
|
// send ping and fragmented message
|
||||||
ws.ping_callback(
|
once = false;
|
||||||
[&](bool is_pong, ping_data const& payload)
|
ws.control_callback(
|
||||||
|
[&](frame_type kind, string_view s)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(is_pong);
|
BEAST_EXPECT(kind == frame_type::pong);
|
||||||
BEAST_EXPECT(payload == "payload");
|
BEAST_EXPECT(! once);
|
||||||
|
once = true;
|
||||||
|
BEAST_EXPECT(s == "payload");
|
||||||
});
|
});
|
||||||
ws.ping("payload");
|
ws.ping("payload");
|
||||||
c.write_frame(ws, false, sbuf("Hello, "));
|
c.write_frame(ws, false, sbuf("Hello, "));
|
||||||
@ -1694,10 +1699,10 @@ public:
|
|||||||
// receive echoed message
|
// receive echoed message
|
||||||
multi_buffer db;
|
multi_buffer db;
|
||||||
c.read(ws, db);
|
c.read(ws, db);
|
||||||
BEAST_EXPECT(pong == 1);
|
BEAST_EXPECT(once);
|
||||||
BEAST_EXPECT(to_string(db.data()) == "Hello, World!");
|
BEAST_EXPECT(to_string(db.data()) == "Hello, World!");
|
||||||
}
|
}
|
||||||
ws.ping_callback({});
|
ws.control_callback({});
|
||||||
|
|
||||||
// send pong
|
// send pong
|
||||||
c.pong(ws, "");
|
c.pong(ws, "");
|
||||||
|
Reference in New Issue
Block a user