def test_invalid_close_message_reason_encoding(self): payload = struct.pack("!H", 1000) + b'h\xc3llo' f = Frame(opcode=OPCODE_CLOSE, body=payload, fin=1, masking_key=os.urandom(4)).build() s = Stream() self.assertEqual(len(s.errors), 0) self.assertEqual(s.closing, None) s.parser.send(f) self.assertEqual(s.closing, None) self.assertEqual(type(s.errors[0]), CloseControlMessage) self.assertEqual(s.errors[0].code, 1007)
def __init__(self, sock, environ, protocols=None, extensions=None): self.stream = Stream() self.protocols = protocols self.extensions = extensions self.environ = environ self.sock = sock self.sock.settimeout(30.0) self.client_terminated = False self.server_terminated = False self._lock = Semaphore()
def __init__(self, sock, handshake_reply, protocols=None): self.stream = Stream(always_mask=False) self.handshake_reply = handshake_reply self.handshake_sent = False self.protocols = protocols self.sock = sock self.client_terminated = False self.server_terminated = False self.reading_buffer_size = DEFAULT_READING_SIZE self.sender = self.sock.sendall # This was initially a loop that used callbacks in ws4py # Here it was turned into a generator, the callback replaced by yield self.runner = self._run()
def test_protocol_exception_from_frame_parsing(self): payload = struct.pack("!H", 1000) + b'hello' f = Frame(opcode=OPCODE_CLOSE, body=payload, fin=1, masking_key=os.urandom(4)) f.rsv1 = 1 f = f.build() s = Stream() self.assertEqual(len(s.errors), 0) self.assertEqual(s.closing, None) s.parser.send(f) self.assertEqual(s.closing, None) self.assertEqual(type(s.errors[0]), CloseControlMessage) self.assertEqual(s.errors[0].code, 1002)
def test_too_large_close_message(self): payload = struct.pack("!H", 1000) + enc('*' * 330) f = Frame(opcode=OPCODE_CLOSE, body=payload, fin=1, masking_key=os.urandom(4)).build() s = Stream() self.assertEqual(len(s.errors), 0) self.assertEqual(s.closing, None) s.parser.send(enc(f)) self.assertEqual(s.closing, None) self.assertEqual(len(s.errors), 1) self.assertEqual(type(s.errors[0]), CloseControlMessage) self.assertEqual(s.errors[0].code, 1002)
def test_binary_and_text_messages_cannot_interleave(self): s = Stream() f = Frame(opcode=OPCODE_TEXT, body=b'hello', fin=0, masking_key=os.urandom(4)).build() s.parser.send(f) next(s.parser) f = Frame(opcode=OPCODE_BINARY, body=os.urandom(7), fin=1, masking_key=os.urandom(4)).build() s.parser.send(f) next(s.parser) self.assertNotEqual(s.errors, []) self.assertIsInstance(s.errors[0], CloseControlMessage) self.assertEqual(s.errors[0].code, 1002)
def test_invalid_encoded_bytes_on_continuation(self): s = Stream() f = Frame(opcode=OPCODE_TEXT, body=b'hello', fin=0, masking_key=os.urandom(4)).build() s.parser.send(f) next(s.parser) f = Frame(opcode=OPCODE_CONTINUATION, body=b'h\xc3llo', fin=1, masking_key=os.urandom(4)).build() s.parser.send(f) next(s.parser) self.assertNotEqual(s.errors, []) self.assertIsInstance(s.errors[0], CloseControlMessage) self.assertEqual(s.errors[0].code, 1007)
def test_text_message_with_continuation_received(self): msg = b'hello there' f = Frame(opcode=OPCODE_TEXT, body=msg, fin=0, masking_key=os.urandom(4)).build() s = Stream() self.assertEqual(s.has_message, False) s.parser.send(f) self.assertEqual(s.message.completed, False) for i in range(3): f = Frame(opcode=OPCODE_CONTINUATION, body=msg, fin=0, masking_key=os.urandom(4)).build() s.parser.send(f) self.assertEqual(s.has_message, False) self.assertEqual(s.message.completed, False) self.assertEqual(s.message.opcode, OPCODE_TEXT) f = Frame(opcode=OPCODE_CONTINUATION, body=msg, fin=1, masking_key=os.urandom(4)).build() s.parser.send(f) self.assertEqual(s.has_message, True) self.assertEqual(s.message.completed, True) self.assertEqual(s.message.opcode, OPCODE_TEXT)
def test_binary_message_with_continuation_received(self): msg = os.urandom(16) f = Frame(opcode=OPCODE_BINARY, body=msg, fin=0).build() s = Stream() self.assertEqual(s.has_message, False) s.parser.send(f) self.assertEqual(s.message.completed, False) for i in range(3): f = Frame(opcode=OPCODE_CONTINUATION, body=msg, fin=0).build() s.parser.send(f) self.assertEqual(s.has_message, False) self.assertEqual(s.message.completed, False) self.assertEqual(s.message.opcode, OPCODE_BINARY) f = Frame(opcode=OPCODE_CONTINUATION, body=msg, fin=1).build() s.parser.send(f) self.assertEqual(s.has_message, True) self.assertEqual(s.message.completed, True) self.assertEqual(s.message.opcode, OPCODE_BINARY)
def test_text_message_with_continuation_and_ping_in_between(self): msg = enc('hello there') key = os.urandom(4) f = Frame(opcode=OPCODE_TEXT, body=msg, fin=0, masking_key=os.urandom(4)).build() s = Stream() self.assertEqual(s.has_message, False) s.parser.send(enc(f)) self.assertEqual(s.message.completed, False) for i in range(3): f = Frame(opcode=OPCODE_CONTINUATION, body=msg, fin=0, masking_key=os.urandom(4)).build() s.parser.send(enc(f)) self.assertEqual(s.has_message, False) self.assertEqual(s.message.completed, False) self.assertEqual(s.message.opcode, OPCODE_TEXT) f = Frame(opcode=OPCODE_PING, body='ping me', fin=1, masking_key=os.urandom(4)).build() self.assertEqual(len(s.pings), i) s.parser.send(enc(f)) self.assertEqual(len(s.pings), i + 1) f = Frame(opcode=OPCODE_CONTINUATION, body=msg, fin=1, masking_key=os.urandom(4)).build() s.parser.send(enc(f)) self.assertEqual(s.has_message, True) self.assertEqual(s.message.opcode, OPCODE_TEXT) self.assertEqual(s.message.completed, True)
def __init__(self, sock, protocols, extensions): """ A handler appropriate for servers. This handler runs the connection's read and parsing in a thread, meaning that incoming messages will be alerted in a different thread from the one that created the handler. @param sock: opened connection after the websocket upgrade @param protocols: list of protocols from the handshake @param extensions: list of extensions from the handshake """ self.stream = Stream() self.protocols = protocols self.extensions = extensions self.sock = sock self.sock.settimeout(30.0) self.client_terminated = False self.server_terminated = False self._th = threading.Thread(target=self._receive)
def test_closing_parser_should_release_resources(self): f = Frame(opcode=OPCODE_TEXT, body=b'hello', fin=1, masking_key=os.urandom(4)).build() s = Stream() s.parser.send(f) s.parser.close()
def test_helper_masked_pong_message(self): s = Stream(always_mask=True) m = s.pong('sos') self.assertIsInstance(m, bytes) self.assertEqual(len(m), 9)
def test_helper_pong_message(self): s = Stream() m = s.pong('sos') self.assertIsInstance(m, bytes) self.assertEqual(len(m), 5)
def test_close_message_received(self): f = Frame(opcode=OPCODE_CLOSE, body='', fin=1).build() s = Stream() self.assertEqual(s.closing, None) s.parser.send(f) self.assertEqual(type(s.closing), CloseControlMessage)
def __init__(self, sock, protocols=None, extensions=None, environ=None, heartbeat_freq=None): """ The ``sock`` is an opened connection resulting from the websocket handshake. If ``protocols`` is provided, it is a list of protocols negotiated during the handshake as is ``extensions``. If ``environ`` is provided, it is a copy of the WSGI environ dictionnary from the underlying WSGI server. """ self.stream = Stream(always_mask=False) """ Underlying websocket stream that performs the websocket parsing to high level objects. By default this stream never masks its messages. Clients using this class should set the ``stream.always_mask`` fields to ``True`` and ``stream.expect_masking`` fields to ``False``. """ self.protocols = protocols """ List of protocols supported by this endpoint. Unused for now. """ self.extensions = extensions """ List of extensions supported by this endpoint. Unused for now. """ self.sock = sock """ Underlying connection. """ self.client_terminated = False """ Indicates if the client has been marked as terminated. """ self.server_terminated = False """ Indicates if the server has been marked as terminated. """ self.reading_buffer_size = DEFAULT_READING_SIZE """ Current connection reading buffer size. """ self.environ = environ """ WSGI environ dictionary. """ self.heartbeat_freq = heartbeat_freq """ At which interval the heartbeat will be running. Set this to `0` or `None` to disable it entirely. """ "Internal buffer to get around SSL problems" self.buf = b'' self._local_address = None self._peer_address = None
def test_empty_close_message(self): f = Frame(opcode=OPCODE_CLOSE, body=b'', fin=1, masking_key=os.urandom(4)).build() s = Stream() self.assertEqual(s.closing, None) s.parser.send(f) self.assertEqual(type(s.closing), CloseControlMessage)