Require same arguments on insufficient socket space
This matches the behaviour of SSLSocket, which we are trying to mimic. It also closely matches the behaviour of normal Socket which can be assumed to not have sent anything if an error occurs. We might actually send some data, but the caller cannot really see that and must call us again as if no data was sent.
This commit is contained in:
parent
6caf23c067
commit
01ef6a6a55
|
@ -93,6 +93,8 @@ class WebSocket(object):
|
||||||
self._recv_queue = []
|
self._recv_queue = []
|
||||||
self._send_buffer = ''.encode("ascii")
|
self._send_buffer = ''.encode("ascii")
|
||||||
|
|
||||||
|
self._previous_sendmsg = None
|
||||||
|
|
||||||
self._sent_close = False
|
self._sent_close = False
|
||||||
self._received_close = False
|
self._received_close = False
|
||||||
|
|
||||||
|
@ -254,8 +256,8 @@ class WebSocket(object):
|
||||||
the value "websocket" in such cases.
|
the value "websocket" in such cases.
|
||||||
|
|
||||||
WebSocketWantWriteError can be raised if the response cannot be
|
WebSocketWantWriteError can be raised if the response cannot be
|
||||||
sent right away. Repeated calls to accept() does not need to
|
sent right away. accept() must be called again once more space
|
||||||
retain the arguments.
|
is available using the same arguments.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This is a state machine in order to handle
|
# This is a state machine in order to handle
|
||||||
|
@ -419,7 +421,8 @@ class WebSocket(object):
|
||||||
data from other calls, or split it over multiple messages.
|
data from other calls, or split it over multiple messages.
|
||||||
|
|
||||||
WebSocketWantWriteError can be raised if there is insufficient
|
WebSocketWantWriteError can be raised if there is insufficient
|
||||||
space in the underlying socket.
|
space in the underlying socket. send() must be called again
|
||||||
|
once more space is available using the same arguments.
|
||||||
"""
|
"""
|
||||||
if len(bytes) == 0:
|
if len(bytes) == 0:
|
||||||
return 0
|
return 0
|
||||||
|
@ -434,31 +437,81 @@ class WebSocket(object):
|
||||||
single WebSocket message.
|
single WebSocket message.
|
||||||
|
|
||||||
WebSocketWantWriteError can be raised if there is insufficient
|
WebSocketWantWriteError can be raised if there is insufficient
|
||||||
space in the underlying socket.
|
space in the underlying socket. sendmsg() must be called again
|
||||||
|
once more space is available using the same arguments.
|
||||||
"""
|
"""
|
||||||
if not isinstance(msg, bytes):
|
if not isinstance(msg, bytes):
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
if not self._sent_close:
|
if self._sent_close:
|
||||||
# Only called to flush?
|
return 0
|
||||||
self._sendmsg(0x2, msg)
|
|
||||||
|
if self._previous_sendmsg is not None:
|
||||||
|
if self._previous_sendmsg != msg:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
self._flush()
|
||||||
|
self._previous_sendmsg = None
|
||||||
|
|
||||||
|
return len(msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._sendmsg(0x2, msg)
|
||||||
|
except WebSocketWantWriteError:
|
||||||
|
self._previous_sendmsg = msg
|
||||||
|
raise
|
||||||
|
|
||||||
self._flush()
|
|
||||||
return len(msg)
|
return len(msg)
|
||||||
|
|
||||||
def ping(self, data=''.encode('ascii')):
|
def ping(self, data=''.encode('ascii')):
|
||||||
"""Write a ping message to the WebSocket."""
|
"""Write a ping message to the WebSocket
|
||||||
|
|
||||||
|
WebSocketWantWriteError can be raised if there is insufficient
|
||||||
|
space in the underlying socket. ping() must be called again once
|
||||||
|
more space is available using the same arguments.
|
||||||
|
"""
|
||||||
if not isinstance(data, bytes):
|
if not isinstance(data, bytes):
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
self._sendmsg(0x9, data)
|
if self._previous_sendmsg is not None:
|
||||||
|
if self._previous_sendmsg != data:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
self._flush()
|
||||||
|
self._previous_sendmsg = None
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._sendmsg(0x9, data)
|
||||||
|
except WebSocketWantWriteError:
|
||||||
|
self._previous_sendmsg = data
|
||||||
|
raise
|
||||||
|
|
||||||
def pong(self, data=''.encode('ascii')):
|
def pong(self, data=''.encode('ascii')):
|
||||||
"""Write a pong message to the WebSocket."""
|
"""Write a pong message to the WebSocket
|
||||||
|
|
||||||
|
WebSocketWantWriteError can be raised if there is insufficient
|
||||||
|
space in the underlying socket. pong() must be called again once
|
||||||
|
more space is available using the same arguments.
|
||||||
|
"""
|
||||||
if not isinstance(data, bytes):
|
if not isinstance(data, bytes):
|
||||||
raise TypeError
|
raise TypeError
|
||||||
|
|
||||||
self._sendmsg(0xA, data)
|
if self._previous_sendmsg is not None:
|
||||||
|
if self._previous_sendmsg != data:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
|
self._flush()
|
||||||
|
self._previous_sendmsg = None
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
self._sendmsg(0xA, data)
|
||||||
|
except WebSocketWantWriteError:
|
||||||
|
self._previous_sendmsg = data
|
||||||
|
raise
|
||||||
|
|
||||||
def shutdown(self, how, code=1000, reason=None):
|
def shutdown(self, how, code=1000, reason=None):
|
||||||
"""Gracefully terminate the WebSocket connection.
|
"""Gracefully terminate the WebSocket connection.
|
||||||
|
@ -470,7 +523,9 @@ class WebSocket(object):
|
||||||
ignored.
|
ignored.
|
||||||
|
|
||||||
WebSocketWantWriteError can be raised if there is insufficient
|
WebSocketWantWriteError can be raised if there is insufficient
|
||||||
space in the underlying socket for the close message.
|
space in the underlying socket for the close message. shutdown()
|
||||||
|
must be called again once more space is available using the same
|
||||||
|
arguments.
|
||||||
|
|
||||||
The how argument is currently ignored.
|
The how argument is currently ignored.
|
||||||
"""
|
"""
|
||||||
|
@ -502,7 +557,9 @@ class WebSocket(object):
|
||||||
a close message to the peer.
|
a close message to the peer.
|
||||||
|
|
||||||
WebSocketWantWriteError can be raised if there is insufficient
|
WebSocketWantWriteError can be raised if there is insufficient
|
||||||
space in the underlying socket for the close message.
|
space in the underlying socket for the close message. close()
|
||||||
|
must be called again once more space is available using the same
|
||||||
|
arguments.
|
||||||
"""
|
"""
|
||||||
self.shutdown(socket.SHUT_RDWR, code, reason)
|
self.shutdown(socket.SHUT_RDWR, code, reason)
|
||||||
self._close()
|
self._close()
|
||||||
|
|
|
@ -146,20 +146,14 @@ class WebSockifyRequestHandler(WebSocketRequestHandlerMixIn, SimpleHTTPRequestHa
|
||||||
self.rec.write("'{{{0}{{{1}',\n".format(tdelta, bufstr))
|
self.rec.write("'{{{0}{{{1}',\n".format(tdelta, bufstr))
|
||||||
self.send_parts.append(buf)
|
self.send_parts.append(buf)
|
||||||
|
|
||||||
# Flush any previously queued data
|
|
||||||
try:
|
|
||||||
self.request.sendmsg('')
|
|
||||||
except WebSocketWantWriteError:
|
|
||||||
return True
|
|
||||||
|
|
||||||
while self.send_parts:
|
while self.send_parts:
|
||||||
# Send pending frames
|
# Send pending frames
|
||||||
buf = self.send_parts.pop(0)
|
|
||||||
try:
|
try:
|
||||||
self.request.sendmsg(buf)
|
self.request.sendmsg(self.send_parts[0])
|
||||||
except WebSocketWantWriteError:
|
except WebSocketWantWriteError:
|
||||||
self.print_traffic("<.")
|
self.print_traffic("<.")
|
||||||
return True
|
return True
|
||||||
|
self.send_parts.pop()
|
||||||
self.print_traffic("<")
|
self.print_traffic("<")
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
Loading…
Reference in New Issue