def test_pipe(Poller): m = Manager() + Poller() a, b = Pipe("a", "b") a.register(m) b.register(m) a = Client(channel=a.channel).register(m) b = Client(channel=b.channel).register(m) m.start() try: assert pytest.wait_for(a, "ready") assert pytest.wait_for(b, "ready") a.fire(write(b"foo")) assert pytest.wait_for(b, "data", b"foo") b.fire(write(b"foo")) assert pytest.wait_for(a, "data", b"foo") a.fire(close()) assert pytest.wait_for(a, "disconnected") b.fire(close()) assert pytest.wait_for(b, "disconnected") finally: m.stop()
def test_basic(Poller, ipv6): m = Manager() + Poller() if ipv6: udp_server = UDP6Server(("::1", 0)) udp_client = UDP6Client(("::1", 0), channel="client") else: udp_server = UDPServer(0) udp_client = UDPClient(0, channel="client") server = Server() + udp_server client = Client() + udp_client server.register(m) client.register(m) m.start() try: assert pytest.wait_for(server, "ready") assert pytest.wait_for(client, "ready") wait_host(server) client.fire(write((server.host, server.port), b"foo")) assert pytest.wait_for(server, "data", b"foo") client.fire(close()) assert pytest.wait_for(client, "closed") server.fire(close()) assert pytest.wait_for(server, "closed") finally: m.stop()
def test_tcp_reconnect(Poller, ipv6): # XXX: Apparently this doesn't work on Windows either? # XXX: UPDATE: Apparently Broken on Windows + Python 3.2 # TODO: Need to look into this. Find out why... if pytest.PLATFORM == "win32" and pytest.PYVER[:2] >= (3, 2): pytest.skip("Broken on Windows on Python 3.2") m = Manager() + Poller() if ipv6: tcp_server = TCP6Server(("::1", 0)) tcp_client = TCP6Client() else: tcp_server = TCPServer(0) tcp_client = TCPClient() server = Server() + tcp_server client = Client() + tcp_client server.register(m) client.register(m) m.start() try: assert pytest.wait_for(client, "ready") assert pytest.wait_for(server, "ready") wait_host(server) # 1st connect client.fire(connect(server.host, server.port)) assert pytest.wait_for(client, "connected") assert pytest.wait_for(server, "connected") assert pytest.wait_for(client, "data", b"Ready") client.fire(write(b"foo")) assert pytest.wait_for(server, "data", b"foo") # disconnect client.fire(close()) assert pytest.wait_for(client, "disconnected") # 2nd reconnect client.fire(connect(server.host, server.port)) assert pytest.wait_for(client, "connected") assert pytest.wait_for(server, "connected") assert pytest.wait_for(client, "data", b"Ready") client.fire(write(b"foo")) assert pytest.wait_for(server, "data", b"foo") client.fire(close()) assert pytest.wait_for(client, "disconnected") assert pytest.wait_for(server, "disconnected") server.fire(close()) assert pytest.wait_for(server, "closed") finally: m.stop()
def _on_close(self, *args): if self._sock is not None: if args and (args[0] != self._sock): return if not self._close_sent: self._write(b"\x88\x00") self._close_sent = True if self._close_received and self._close_sent: if self._sock: self.fire(close(self._sock), self.parent.channel) else: self.fire(close(), self.parent.channel)
def test_tcp_bind(Poller, ipv6): m = Manager() + Poller() if ipv6: sock = socket(AF_INET6, SOCK_STREAM) sock.bind(("::1", 0)) sock.listen(5) _, bind_port, _, _ = sock.getsockname() sock.close() server = Server() + TCP6Server(("::1", 0)) client = Client() + TCP6Client() else: sock = socket(AF_INET, SOCK_STREAM) sock.bind(("", 0)) sock.listen(5) _, bind_port = sock.getsockname() sock.close() server = Server() + TCPServer(0) client = Client() + TCPClient() server.register(m) client.register(m) m.start() try: assert pytest.wait_for(client, "ready") assert pytest.wait_for(server, "ready") wait_host(server) client.fire(connect(server.host, server.port)) assert pytest.wait_for(client, "connected") assert pytest.wait_for(server, "connected") assert pytest.wait_for(client, "data", b"Ready") # assert server.client[1] == bind_port client.fire(write(b"foo")) assert pytest.wait_for(server, "data", b"foo") client.fire(close()) assert pytest.wait_for(client, "disconnected") assert pytest.wait_for(server, "disconnected") server.fire(close()) assert pytest.wait_for(server, "closed") finally: m.stop()
def _check_timeout(self, socket): try: from circuits import sleep except ImportError: return # wrong circuits version try: state = self._buffers[socket] except KeyError: # FIXME: does not exists yet on "connect" return # disconnected if state.tunnel: return timeout = state.timeout if timeout is not None: timeout.abort = True timeout.expiry = time() timeout = sleep(self.connection_idle_timeout) timeout.abort = False state.timeout = timeout yield timeout if timeout.abort or state.tunnel: return if all(client.done for client in state.requests): self.fire(close(socket))
def parse(data): # TODO: if we have a socket with TLS support we should try to use it instead so that we can speak HTTPS and redirect to the other port. # self.fire(write(socket, b'\x15\x03\x01\x00\x02\x02(')) self.fire(write(socket, b'\x15\x03\x01\x00\x02\x02G')) # self.fire(write(socket, b'<html><head><title>use plaintext HTTP</title></head><body></body>USE HTTP!</html>')) self.fire(close(socket)) return parser(b'')
def on_request(self, event, req, res): if req.selector and req.selector.startswith("URL:"): event.stop() _, url = req.selector.split(":", 1) req.stream = True self.fire(write(req.sock, TEMPLATE.format(timeout=self.timeout, url=url))) self.fire(close(req.sock))
def test_auto_reconnect(app, watcher, manager): # add client client = App().register(manager) node = Node().register(client) chan = node.add('client1', *app.bind, reconnect_delay=1, connect_timeout=1) assert watcher.wait('connected', channel=chan) watcher.clear() # close server app.fire(close(), app.channel) assert watcher.wait('closed', channel=app.channel) watcher.clear() # client gets an unreachable assert watcher.wait('connect', channel=chan) assert watcher.wait('unreachable', channel=chan) watcher.clear() # start a new server node2 = Node(port=app.bind[1], server_ip=app.bind[0]) node2.register(manager) assert watcher.wait('ready', channel=node2.channel) watcher.clear() assert watcher.wait('connected', channel=chan) client.unregister()
def http_through_ssl(self, socket): # If we receive a plain HTTP request and we're a TLS enabled socket # inform the user about his misusage and close the connection immediately. self.fire(write(socket, b"""Your browser sent a request that this server could not understand. Reason: You're speaking plain HTTP to an SSL-enabled server port. Instead use the HTTPS scheme to access this URL, please: https://%s""")) # TODO: add URI by parsing the data which were written into the socket self.fire(close(socket))
def test_tcps_basic(manager, watcher, client, Poller, ipv6): poller = Poller().register(manager) if ipv6: tcp_server = TCP6Server(("::1", 0), secure=True, certfile=CERT_FILE) else: tcp_server = TCPServer(0, secure=True, certfile=CERT_FILE) server = Server() + tcp_server server.register(manager) try: watcher.wait("ready", "server") client.connect(server.host, server.port) assert watcher.wait("connect", "server") assert client.recv() == b"Ready" client.send(b"foo") assert watcher.wait("read", "server") assert client.recv() == b"foo" client.disconnect() assert watcher.wait("disconnect", "server") server.fire(close()) assert watcher.wait("closed", "server") finally: poller.unregister() server.unregister()
def _on_stream(self, res, data): sock = res.request.sock if data is not None: if isinstance(data, text_type): data = data.encode(self._encoding) if res.chunked: buf = [ hex(len(data))[2:].encode(self._encoding), b"\r\n", data, b"\r\n" ] data = b"".join(buf) self.fire(write(sock, data)) if res.body and not res.done: try: data = next(res.body) while not data: # Skip over any null byte sequences data = next(res.body) except StopIteration: data = None self.fire(stream(res, data)) else: if res.body: res.body.close() if res.chunked: self.fire(write(sock, b"0\r\n\r\n")) if res.close: self.fire(close(sock)) if sock in self._clients: del self._clients[sock] res.done = True
def test_close(Poller, ipv6): m = Manager() + Poller() server = Server() + UDPServer(0) server.register(m) m.start() try: assert pytest.wait_for(server, "ready") wait_host(server) host, port = server.host, server.port server.fire(close()) assert pytest.wait_for(server, "disconnected") server.unregister() def test(obj, attr): return attr not in obj.components assert pytest.wait_for(m, server, value=test) server = Server() + UDPServer((host, port)) server.register(m) assert pytest.wait_for(server, "ready", timeout=30.0) finally: m.stop()
def test_auto_reconnect(app, watcher, manager): # add client client = App().register(manager) node = Node().register(client) chan = node.add('client1', *app.bind, reconnect_delay=1, connect_timeout=1) assert watcher.wait('connected', channel=chan) # close server app.fire(close(), app.channel) assert watcher.wait('closed', channel=app.channel) app.unregister() assert watcher.wait('unregistered', channel=app.channel) for _ in range(5): watcher.clear() assert watcher.wait('connect', channel=chan) assert watcher.wait('unreachable', channel=chan) # open server app = Node(port=app.bind[1], server_ip=app.bind[0]) app.register(manager) assert watcher.wait('registered', channel=app.channel) assert watcher.wait('connected_to', channel=app.channel) client.unregister()
def _on_response(self, response): self._response = response self._pending -= 1 if response.headers.get("Connection") == "Close" or response.status != 101: self.fire(close(), self._transport) raise NotConnected() WebSocketCodec(data=response.body.read(), channel=self._wschannel).register(self)
def _on_exception(self, *args, **kwargs): fevent = kwargs['fevent'] if fevent.name == '_read': socket = fevent.args[0] self.fire(close(socket)) elif isinstance(fevent, (read, RequestEvent, ResponseEvent, HTTPError)): pass # already handled elif fevent.name == 'response.body': socket = fevent.args[0].socket self.fire(close(socket)) elif fevent.name == 'httperror_success': self._on_httperror_failure(fevent.args[0], args) else: # TODO: log handler = reprhandler(kwargs['handler']) if kwargs['handler'] else 'Unknown' print('Exception in %s\nTraceback: %s' % (handler, ''.join(args[2])))
def _on_socket_error(self, socket, error): print('SocketError: %r: %s' % (socket, error)) if isinstance(error, SSLError): if error.errno == 1 and getattr(error, 'reason', None) == 'HTTP_REQUEST' or error.strerror.endswith(':http request'): self.http_through_ssl(socket) return self.fire(close(socket))
def parse(data): # TODO: if we have a socket with TLS support we should try to use it instead so that we can speak HTTPS and redirect to the other port. #self.fire(write(socket, b'\x15\x03\x01\x00\x02\x02(')) self.fire(write(socket, b'\x15\x03\x01\x00\x02\x02G')) #self.fire(write(socket, b'<html><head><title>use plaintext HTTP</title></head><body></body>USE HTTP!</html>')) self.fire(close(socket)) return parser(b'')
def test_auto_reconnect(app, watcher, manager): # add client client = App().register(manager) node = Node().register(client) chan = node.add('client1', *app.bind, reconnect_delay=1, connect_timeout=1) assert watcher.wait('connected', channel=chan) # close server app.fire(close(), app.channel) assert watcher.wait('closed', channel=app.channel) app.unregister() assert watcher.wait('unregistered', channel=app.channel) for i in range(5): watcher.clear() assert watcher.wait('connect', channel=chan) assert watcher.wait('unreachable', channel=chan) # open server app = Node(port=app.bind[1], server_ip=app.bind[0]) app.register(manager) assert watcher.wait('registered', channel=app.channel) assert watcher.wait('connected_to', channel=app.channel) client.unregister()
def file_eof(self, event): channel = event.channels[0] if channel in self.streams: req, file = self.streams[channel] self.fire(close(req.sock)) file.unregister() del self.streams[channel]
def _on_response(self, response): self._response = response self._pending -= 1 if response.headers.get("Connection", "").lower() == "close" \ or response.status != 101: self.fire(close(), self._transport) raise NotConnected() self._codec = WebSocketCodec(data=response.body.read(), channel=self._wschannel).register(self)
def _on_socket_error(self, socket, error): print('SocketError: %r: %s' % (socket, error)) if isinstance(error, SSLError): if error.errno == 1 and getattr( error, 'reason', None ) == 'HTTP_REQUEST' or error.strerror.endswith(':http request'): self.http_through_ssl(socket) return self.fire(close(socket))
def _on_exception(self, *args, **kwargs): fevent = kwargs['fevent'] if fevent.name == '_read': socket = fevent.args[0] self.fire(close(socket)) elif isinstance(fevent, (read, RequestEvent, ResponseEvent, HTTPError)): pass # already handled elif fevent.name == 'response.body': socket = fevent.args[0].socket self.fire(close(socket)) elif fevent.name == 'httperror_success': self._on_httperror_failure(fevent.args[0], args) else: # TODO: log handler = reprhandler( kwargs['handler']) if kwargs['handler'] else 'Unknown' print('Exception in %s\nTraceback: %s' % (handler, ''.join(args[2])))
def http_through_ssl(self, socket): # If we receive a plain HTTP request and we're a TLS enabled socket # inform the user about his misusage and close the connection immediately. self.fire( write( socket, b"""Your browser sent a request that this server could not understand. Reason: You're speaking plain HTTP to an SSL-enabled server port. Instead use the HTTPS scheme to access this URL, please: https://%s""") ) # TODO: add URI by parsing the data which were written into the socket self.fire(close(socket))
def test_tcps_basic(Poller, ipv6): from circuits import Debugger m = Manager() + Debugger() + Poller() if ipv6: tcp_server = TCP6Server(("::1", 0), secure=True, certfile=CERT_FILE) tcp_client = TCP6Client() else: tcp_server = TCPServer(0, secure=True, certfile=CERT_FILE) tcp_client = TCPClient() server = Server() + tcp_server client = Client() + tcp_client server.register(m) client.register(m) m.start() try: assert pytest.wait_for(client, "ready") assert pytest.wait_for(server, "ready") wait_host(server) client.fire(connect(server.host, server.port, secure=True)) assert pytest.wait_for(client, "connected") assert pytest.wait_for(server, "connected") assert pytest.wait_for(client, "data", b"Ready") client.fire(write(b"foo")) assert pytest.wait_for(server, "data", b"foo") assert pytest.wait_for(client, "data", b"foo") client.fire(close()) assert pytest.wait_for(client, "disconnected") assert pytest.wait_for(server, "disconnected") server.fire(close()) assert pytest.wait_for(server, "closed") finally: m.stop()
def test_tcp_basic(Poller, ipv6): m = Manager() + Poller() if ipv6: tcp_server = TCP6Server(("::1", 0)) tcp_client = TCP6Client() else: tcp_server = TCPServer(0) tcp_client = TCPClient() server = Server() + tcp_server client = Client() + tcp_client server.register(m) client.register(m) m.start() try: assert pytest.wait_for(client, "ready") assert pytest.wait_for(server, "ready") wait_host(server) client.fire(connect(server.host, server.port)) assert pytest.wait_for(client, "connected") assert pytest.wait_for(server, "connected") assert pytest.wait_for(client, "data", b"Ready") client.fire(write(b"foo")) assert pytest.wait_for(server, "data", b"foo") assert pytest.wait_for(client, "data", b"foo") client.fire(close()) assert pytest.wait_for(client, "disconnected") assert pytest.wait_for(server, "disconnected") server.fire(close()) assert pytest.wait_for(server, "closed") finally: m.stop()
def bind(manager, watcher): server = UDPServer(0).register(manager) assert watcher.wait('ready', channel='server') host, port = server.host, server.port server.fire(close()) assert watcher.wait('closed', channel='server') server.unregister() assert watcher.wait('unregistered', channel='server') return host, port
def bind(request, manager, watcher): server = UDPServer(0).register(manager) assert watcher.wait("ready") host, port = server.host, server.port server.fire(close()) assert watcher.wait("closed") server.unregister() assert watcher.wait("unregistered") return host, port
def bind(request, manager, watcher): server = UDPServer(0).register(manager) assert watcher.wait('ready') host, port = server.host, server.port server.fire(close()) assert watcher.wait('closed') server.unregister() assert watcher.wait('unregistered') return host, port
def kill(self, sock, source, target, reason=None): user = User.objects.filter(sock=sock).first() if not user.oper: return ERR_NOPRIVILEGES() nick = User.objects.filter(nick=target).first() if nick is None: return ERR_NOSUCHNICK(target) reason = u("Killed by {0}: {1}").format(user.nick, reason or nick.nick) self.fire(response.create("quit", nick.sock, nick.source, reason, disconnect=False)) self.fire(reply(nick.sock, ERROR(nick.host, reason)), "server") Timer(1, close(nick.sock), "server").register(self)
def quit(self, sock, source, reason="Leaving"): user = self.users[sock] channels = [self.channels[channel] for channel in user.channels] for channel in channels: channel.users.remove(user) if not channel.users: del self.channels[channel.name] users = chain(*map(attrgetter("users"), channels)) self.fire(close(sock)) self._notify(users, Message("QUIT", reason, prefix=user.prefix), user)
def poll(self): now = int(time()) reason = u("Ping timeout: {0} seconds") for user in User.objects.all(): if user.lastping and not user.lastpong and ((now - user.lastping) > self.timeout): delta = now - user.lastping self.fire(response.create("quit", user.sock, user.source, reason.format(delta))) self.fire(reply(user.sock, ERROR(user.host, reason.format(delta))), "server") Timer(1, close(user.sock), "server").register(self) else: self.fire(write(user.sock, bytes(PING(self.server.host)))) user.lastping = int(time()) user.lastpong = None user.save()
def _on_target_disconnected(self, event): """Disconnected Event Handler This unbound function will be later added as an event handler to a dynamically created and registered client instance and used to process Disconnected events of a connected client. """ channel = event.channels[0] sock = self._sockets[channel] self.fire(close(sock), "source") del self._sockets[channel] del self._clients[sock]
def _on_httperror_failure(self, evt, error): client = evt.args[0] socket = client.socket try: state = self._buffers[socket] except KeyError: self._premature_client_disconnect(client) return if client in state.responses: return print('Exception in httperror_failure: %s, %r' % (error, client)) self.default_internal_server_error(client, error) self.fire(write(socket, bytes(client.response))) self.fire(write(socket, bytes(client.response.headers))) self.fire(write(socket, bytes(client.response.body))) self.fire(close(socket))
def restart(self, sock, source): user = User.objects.filter(sock=sock).first() if not user.oper: yield ERR_NOPRIVILEGES() return yield self.call(close(), "server") args = sys.argv[:] self.parent.logger.info(u("Restarting... Args: {0}".format(args))) args.insert(0, sys.executable) if sys.platform == 'win32': args = ["\"{0}\"".format(arg) for arg in args] os.execv(sys.executable, args)
def quit(self, sock, source, reason="Leaving"): user = self.users[sock] channels = [self.channels[channel] for channel in user.channels] for channel in channels: channel.users.remove(user) if not channel.users: del self.channels[channel.name] users = chain(*map(attrgetter("users"), channels)) self.fire(close(sock)) self._notify( users, Message("QUIT", reason, prefix=user.prefix), user )
def kill(self, sock, source, target, reason=None): user = User.objects.filter(sock=sock).first() if not user.oper: return ERR_NOPRIVILEGES() nick = User.objects.filter(nick=target).first() if nick is None: return ERR_NOSUCHNICK(target) reason = u("Killed: {0}").format(reason) if reason else nick.nick self.fire( response.create("quit", nick.sock, nick.source, reason, disconnect=False)) self.fire(reply(nick.sock, ERROR(reason)), "server") Timer(1, close(nick.sock), "server").register(self)
def _on_response_complete(self, client): socket = client.socket try: state = self._buffers[socket] except KeyError: # client disconnected self._premature_client_disconnect(client) return pipeline = state.requests assert pipeline and pipeline[0] is client pipeline.pop(0) try: client_ = pipeline[0] except IndexError: # no further request if state.composed[client].close: # FIXME: composed self.fire(close(socket)) else: if client_ in state.responses and client_ not in state.response_started: self.fire(_ResponseStart(client_))
def init(self, server, sock, addr): self.server = server self.sock = sock self.addr = addr self.__buffer = "" self.__state = self.COMMAND self.__greeting = 0 self.__mailfrom = None self.__rcpttos = [] self.__data = "" self.__fqdn = socket.getfqdn() try: self.__peer = self.sock.getpeername() except socket.error, err: # a race condition may occur if the other end is closing # before we can get the peername self.fire(close(self.sock)) if err[0] != errno.ENOTCONN: raise return
def _on_response(self, response): self._response = response if response.headers.get("Connection", "").lower() == "close": self.fire(close(), self._transport) return response
def close(self): if self._transport.connected: self.fire(close(), self._transport)
def _on_read(self, sock, data): """Read Event Handler Process any incoming data appending it to an internal buffer. Split the buffer by the standard HTTP delimiter CRLF and create Raw Event per line. Any unfinished lines of text, leave in the buffer. """ if sock in self._buffers: parser = self._buffers[sock] else: self._buffers[sock] = parser = HttpParser(0, True) # If we receive an SSL handshake at the start of a request # and we're not a secure server, then immediately close the # client connection since we can't respond to it anyway. if is_ssl_handshake(data) and not self._server.secure: if sock in self._buffers: del self._buffers[sock] if sock in self._clients: del self._clients[sock] return self.fire(close(sock)) _scheme = "https" if self._server.secure else "http" parser.execute(data, len(data)) if not parser.is_headers_complete(): if parser.errno is not None: if parser.errno == BAD_FIRST_LINE: req = wrappers.Request(sock, server=self._server) else: req = wrappers.Request(sock, parser.get_method(), parser.get_scheme() or _scheme, parser.get_path(), parser.get_version(), parser.get_query_string(), server=self._server) req.server = self._server res = wrappers.Response(req, encoding=self._encoding) del self._buffers[sock] return self.fire(httperror(req, res, 400)) return if sock in self._clients: req, res = self._clients[sock] else: method = parser.get_method() scheme = parser.get_scheme() or _scheme path = parser.get_path() version = parser.get_version() query_string = parser.get_query_string() req = wrappers.Request(sock, method, scheme, path, version, query_string, headers=parser.get_headers(), server=self._server) res = wrappers.Response(req, encoding=self._encoding) self._clients[sock] = (req, res) rp = req.protocol sp = self.protocol if rp[0] != sp[0]: # the major HTTP version differs return self.fire(httperror(req, res, 505)) res.protocol = "HTTP/{0:d}.{1:d}".format(*min(rp, sp)) res.close = not parser.should_keep_alive() clen = int(req.headers.get("Content-Length", "0")) if clen and not parser.is_message_complete(): return if hasattr(sock, "getpeercert"): peer_cert = sock.getpeercert() if peer_cert: e = request(req, res, peer_cert) else: e = request(req, res) else: e = request(req, res) # Guard against unwanted request paths (SECURITY). path = req.path _path = req.uri._path if (path.encode(self._encoding) != _path) and (quote(path).encode( self._encoding) != _path): return self.fire(redirect(req, res, [req.uri.utf8()], 301)) req.body = BytesIO(parser.recv_body()) del self._buffers[sock] self.fire(e)
def _on_response(self, res): """``Response`` Event Handler :param response: the ``Response`` object created when the HTTP request was initially received. :type response: :class:`~circuits.web.wrappers.Response` This handler builds an HTTP response data stream from the information contained in the *response* object and sends it to the client (firing ``write`` events). """ # send HTTP response status line and headers req = res.request headers = res.headers sock = req.sock if req.method == "HEAD": self.fire(write(sock, bytes(res))) self.fire(write(sock, bytes(headers))) elif res.stream and res.body: try: data = next(res.body) except StopIteration: data = None self.fire(write(sock, bytes(res))) self.fire(write(sock, bytes(headers))) self.fire(stream(res, data)) else: self.fire(write(sock, bytes(res))) self.fire(write(sock, bytes(headers))) if isinstance(res.body, bytes): body = res.body elif isinstance(res.body, text_type): body = res.body.encode(self._encoding) else: parts = (s if isinstance(s, bytes) else s.encode(self._encoding) for s in res.body if s is not None) body = b"".join(parts) if body: if res.chunked: buf = [ hex(len(body))[2:].encode(self._encoding), b"\r\n", body, b"\r\n" ] body = b"".join(buf) self.fire(write(sock, body)) if res.chunked: self.fire(write(sock, b"0\r\n\r\n")) if not res.stream: if res.close: self.fire(close(sock)) # Delete the request/response objects if present if sock in self._clients: del self._clients[sock] res.done = True
def _parse_messages(self, data): msgs = [] # one chunk of bytes may result in several messages if self._close_received: return msgs while data: # extract final flag, opcode and masking final = bool(data[0] & 0x80 != 0) opcode = data[0] & 0xf masking = bool(data[1] & 0x80 != 0) # evaluate payload length payload_length = data[1] & 0x7f offset = 2 if payload_length >= 126: payload_bytes = 2 if payload_length == 126 else 8 payload_length = 0 for _ in range(payload_bytes): payload_length = payload_length * 256 \ + data[offset] offset += 1 # retrieve optional masking key if masking: masking_key = data[offset:offset + 4] offset += 4 # if not enough bytes available yet, retry after next read if len(data) - offset < payload_length: break # rest of _buffer is payload msg = data[offset:offset + payload_length] if masking: # unmask msg = list(msg) for i, c in enumerate(msg): msg[i] = c ^ masking_key[i % 4] msg = bytearray(msg) # remove bytes of processed frame from byte _buffer offset += payload_length data = data[offset:] # if there have been parts already, combine msg = self._pending_payload + msg if final: if opcode < 8: # if text or continuation of text, convert if opcode == 1 \ or opcode == 0 and self._pending_type == 1: msg = msg.decode("utf-8", "replace") self._pending_type = None self._pending_payload = bytearray() msgs.append(msg) # check for client closing the connection elif opcode == 8: self._close_received = True if self._sock: self.fire(close(self._sock)) else: self.fire(close()) break # check for Ping elif opcode == 9: if self._close_sent: return frame = bytearray(b'\x8a') frame += self._encode_tail(msg, self._sock is None) self._write(frame) else: self._pending_payload = msg if opcode != 0: self._pending_type = opcode return msgs