Skip to content

Commit b7c544f

Browse files
author
Michael Faust
committed
Fix messages are one-behind when using secure sockets (wss)
This fix tries to query the sockets directly for pending data if poller.poll() returns no file descriptors. In case of pending data, a special flag is set on the websocket, to ensure the whole buffer is processed in one go.
1 parent 4989bb7 commit b7c544f

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

ws4py/manager.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,22 @@ def stop(self):
284284
self.websockets.clear()
285285
self.poller.release()
286286

287+
def get_fds_with_pending_data( self ):
288+
"""
289+
Returns a list of file descriptors that have pending data.
290+
291+
This is a workaround for a bug where polling returns no file descriptor,
292+
even though we have sockets with pending data.
293+
"""
294+
fds = []
295+
with self.lock:
296+
for ws in ( ws for ws in self.websockets.values() if ws._is_secure ):
297+
if hasattr( ws.sock, 'pending' ) and ws.sock.pending():
298+
fds.append( ws.sock.fileno() )
299+
# set special handling flag
300+
ws._force_process_buffer = True
301+
return fds
302+
287303
def run(self):
288304
"""
289305
Manager's mainloop executed from within a thread.
@@ -309,6 +325,10 @@ def run(self):
309325
if not self.running:
310326
break
311327

328+
if not polled:
329+
# workaround WSS bug
330+
polled.extend( self.get_fds_with_pending_data() )
331+
312332
for fd in polled:
313333
if not self.running:
314334
break

ws4py/websocket.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ def __init__(self, sock, protocols=None, extensions=None, environ=None, heartbea
113113
Tell us if the socket is secure or not.
114114
"""
115115

116+
self._force_process_buffer = False
117+
"""
118+
Indicates special handling of the buffer, only relevant for secure sockets.
119+
"""
120+
116121
self.client_terminated = False
117122
"""
118123
Indicates if the client has been marked as terminated.
@@ -241,7 +246,7 @@ def close_connection(self):
241246
except:
242247
pass
243248
self.sock = None
244-
249+
245250

246251
def ping(self, message):
247252
"""
@@ -424,6 +429,15 @@ def once(self):
424429
if not self.process(self.buf[:requested]):
425430
return False
426431
self.buf = self.buf[requested:]
432+
if self.buf and self._force_process_buffer:
433+
self._force_process_buffer = False
434+
# if we are in special handling mode, we need to process
435+
# the buffer until it is empty
436+
while self.buf:
437+
requested = self.reading_buffer_size
438+
if not self.process(self.buf[:requested]):
439+
return False
440+
self.buf = self.buf[requested:]
427441

428442
return True
429443

0 commit comments

Comments
 (0)