提交 cfd621a3 编写于 作者: B Ben Darnell

websocket: Make ping() argument optional

Also accept both bytes and str, and add a client-side ping() method.

Fixes #2295
上级 8a73d592
......@@ -621,6 +621,34 @@ class ClientPeriodicPingTest(WebSocketBaseTestCase):
# TODO: test that the connection gets closed if ping responses stop.
class ManualPingTest(WebSocketBaseTestCase):
def get_app(self):
class PingHandler(TestWebSocketHandler):
def on_ping(self, data):
self.write_message(data, binary=isinstance(data, bytes))
self.close_future = Future()
return Application([
('/', PingHandler, dict(close_future=self.close_future)),
])
@gen_test
def test_manual_ping(self):
ws = yield self.ws_connect('/')
self.assertRaises(ValueError, ws.ping, 'a' * 126)
ws.ping('hello')
resp = yield ws.read_message()
# on_ping always sees bytes.
self.assertEqual(resp, b'hello')
ws.ping(b'binary hello')
resp = yield ws.read_message()
self.assertEqual(resp, b'binary hello')
yield self.close(ws)
class MaxMessageSizeTest(WebSocketBaseTestCase):
def get_app(self):
self.close_future = Future()
......
......@@ -312,8 +312,23 @@ class WebSocketHandler(tornado.web.RequestHandler):
"""
raise NotImplementedError
def ping(self, data):
"""Send ping frame to the remote end."""
def ping(self, data=b''):
"""Send ping frame to the remote end.
The data argument allows a small amount of data (up to 125
bytes) to be sent as a part of the ping message. Note that not
all websocket implementations expose this data to
applications.
Consider using the ``websocket_ping_interval`` application
setting instead of sending pings manually.
.. versionchanged:: 5.1
The data argument is now optional.
"""
data = utf8(data)
if self.ws_connection is None:
raise WebSocketClosedError()
self.ws_connection.write_ping(data)
......@@ -756,12 +771,19 @@ class WebSocketProtocol13(WebSocketProtocol):
**self._get_compressor_options(other_side, agreed_parameters, compression_options))
def _write_frame(self, fin, opcode, data, flags=0):
data_len = len(data)
if opcode & 0x8:
# All control frames MUST have a payload length of 125
# bytes or less and MUST NOT be fragmented.
if not fin:
raise ValueError("control frames may not be fragmented")
if data_len > 125:
raise ValueError("control frame payloads may not exceed 125 bytes")
if fin:
finbit = self.FIN
else:
finbit = 0
frame = struct.pack("B", finbit | opcode | flags)
data_len = len(data)
if self.mask_outgoing:
mask_bit = 0x80
else:
......@@ -1205,6 +1227,25 @@ class WebSocketClientConnection(simple_httpclient._HTTPConnection):
else:
self.read_queue.append(message)
def ping(self, data=b''):
"""Send ping frame to the remote end.
The data argument allows a small amount of data (up to 125
bytes) to be sent as a part of the ping message. Note that not
all websocket implementations expose this data to
applications.
Consider using the ``ping_interval`` argument to
`websocket_connect` instead of sending pings manually.
.. versionadded:: 5.1
"""
data = utf8(data)
if self.protocol is None:
raise WebSocketClosedError()
self.protocol.write_ping(data)
def on_pong(self, data):
pass
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册