def handle_close(self, header, payload):
        """
        Called when a close frame has been decoded from the stream.

        :param header: The decoded `Header`.
        :param payload: The bytestring payload associated with the close frame.
        """
        if not payload:
            self.close(1000, None)
            return
        if len(payload) < 2:
            raise WebSocketError('Invalid close frame: {0} {1}'.format(
                header, payload))
        rv = payload[:2]
        if six.PY2:
            code = struct.unpack('!H', str(rv))[0]
        else:
            code = struct.unpack('!H', bytes(rv))[0]
        payload = payload[2:]
        if payload:
            validator = Utf8Validator()
            val = validator.validate(payload)
            if not val[0]:
                raise UnicodeError
        if not self._is_valid_close_code(code):
            raise WebSocketError('Invalid close code {0}'.format(code))
        self.close(code, payload)
Exemple #2
0
 def receive(self):
     if self._closed:
         raise WebSocketError("Connection is already closed")
     try:
         return uwsgi.websocket_recv_nb()
     except IOError, e:
         self.close()
         raise WebSocketError(e)
    def read_message(self):
        """
        Return the next text or binary message from the socket.

        This is an internal method as calling this will not cleanup correctly
        if an exception is called. Use `receive` instead.
        """
        opcode = None
        message = None
        while True:
            header, payload = self.read_frame()
            f_opcode = header.opcode
            if f_opcode in (self.OPCODE_TEXT, self.OPCODE_BINARY):
                # a new frame
                if opcode:
                    raise WebSocketError(
                        "The opcode in non-fin frame is expected to be zero, got {0!r}"
                        .format(f_opcode))
                # Start reading a new message, reset the validator
                self.utf8validator.reset()
                self.utf8validate_last = (True, True, 0, 0)
                opcode = f_opcode
            elif f_opcode == self.OPCODE_CONTINUATION:
                if not opcode:
                    raise WebSocketError("Unexpected frame with opcode=0")
            elif f_opcode == self.OPCODE_PING:
                self.handle_ping(header, payload)
                continue
            elif f_opcode == self.OPCODE_PONG:
                self.handle_pong(header, payload)
                continue
            elif f_opcode == self.OPCODE_CLOSE:
                self.handle_close(header, payload)
                return
            else:
                raise WebSocketError(
                    "Unexpected opcode={0!r}".format(f_opcode))
            if opcode == self.OPCODE_TEXT:
                self.validate_utf8(payload)
                if six.PY3:
                    payload = payload.decode()
            if message is None:
                message = six.text_type(
                ) if opcode == self.OPCODE_TEXT else six.binary_type()
            message += payload
            if header.fin:
                break
        if opcode == self.OPCODE_TEXT:
            if six.PY2:
                self.validate_utf8(message)
            else:
                self.validate_utf8(message.encode())
            return message
        else:
            return bytearray(message)
Exemple #4
0
 def send_frame(self, message, opcode):
     """
     Send a frame over the websocket with message as its payload
     """
     if self._closed:
         raise WebSocketError("Connection is already closed")
     if opcode == self.OPCODE_TEXT:
         message = self._encode_bytes(message)
     elif opcode == self.OPCODE_BINARY:
         message = six.binary_type(message)
     header = Header.encode_header(True, opcode, '', len(message), 0)
     try:
         self.stream.write(header + message)
     except socket_error:
         raise WebSocketError("Socket is dead")
Exemple #5
0
    def read_frame(self):
        """
        Block until a full frame has been read from the socket.

        This is an internal method as calling this will not cleanup correctly
        if an exception is called. Use `receive` instead.

        :return: The header and payload as a tuple.
        """
        header = Header.decode_header(self.stream)
        if header.flags:
            raise WebSocketError
        if not header.length:
            return header, ''
        try:
            payload = self.stream.read(header.length)
        except socket_error:
            payload = ''
        except Exception:
            # TODO log out this exception
            payload = ''
        if len(payload) != header.length:
            raise WebSocketError('Unexpected EOF reading frame payload')
        if header.mask:
            payload = header.unmask_payload(payload)
        return header, payload
 def get_file_descriptor(self):
     """Return the file descriptor for the given websocket"""
     try:
         return uwsgi.connection_fd()
     except IOError as e:
         self.close()
         raise WebSocketError(e)
Exemple #7
0
    def decode_header(cls, stream):
        """
        Decode a WebSocket header.

        :param stream: A file like object that can be 'read' from.
        :returns: A `Header` instance.
        """
        read = stream.read
        data = read(2)
        if len(data) != 2:
            raise WebSocketError("Unexpected EOF while decoding header")
        first_byte, second_byte = struct.unpack('!BB', data)
        header = cls(fin=first_byte & cls.FIN_MASK == cls.FIN_MASK,
                     opcode=first_byte & cls.OPCODE_MASK,
                     flags=first_byte & cls.HEADER_FLAG_MASK,
                     length=second_byte & cls.LENGTH_MASK)
        has_mask = second_byte & cls.MASK_MASK == cls.MASK_MASK
        if header.opcode > 0x07:
            if not header.fin:
                raise WebSocketError(
                    'Received fragmented control frame: {0!r}'.format(data))
            # Control frames MUST have a payload length of 125 bytes or less
            if header.length > 125:
                raise FrameTooLargeException(
                    'Control frame cannot be larger than 125 bytes: {0!r}'.
                    format(data))
        if header.length == 126:
            # 16 bit length
            data = read(2)
            if len(data) != 2:
                raise WebSocketError('Unexpected EOF while decoding header')
            header.length = struct.unpack('!H', data)[0]
        elif header.length == 127:
            # 64 bit length
            data = read(8)
            if len(data) != 8:
                raise WebSocketError('Unexpected EOF while decoding header')
            header.length = struct.unpack('!Q', data)[0]
        if has_mask:
            mask = read(4)
            if len(mask) != 4:
                raise WebSocketError('Unexpected EOF while decoding header')
            header.mask = mask
        return header
Exemple #8
0
 def send(self, message, binary=False):
     """
     Send a frame over the websocket with message as its payload
     """
     if binary is None:
         binary = not isinstance(message, six.string_types)
     opcode = self.OPCODE_BINARY if binary else self.OPCODE_TEXT
     try:
         self.send_frame(message, opcode)
     except WebSocketError:
         raise WebSocketError("Socket is dead")
Exemple #9
0
 def receive(self):
     """
     Read and return a message from the stream. If `None` is returned, then
     the socket is considered closed/errored.
     """
     if self._closed:
         raise WebSocketError("Connection is already closed")
     try:
         return self.read_message()
     except UnicodeError:
         logger.info('websocket.receive: UnicodeError')
         self.close(1007)
     except WebSocketError:
         logger.info('websocket.receive: WebSocketError')
         self.close(1002)
     except Exception as e:
         logger.info('websocket.receive: Unknown error %s', e)
         raise e
 def send(self, message, binary=None):
     try:
         uwsgi.websocket_send(message)
     except IOError as e:
         self.close()
         raise WebSocketError(e)