Example #1
0
def socket():
    ws = request.environ.get('wsgi.websocket')
    if not ws:
        print "! WebSocket failed to initialize"
        return "WebSocket failed to initialize"

    token, email = None, None

    try:
        # Await client confirmation
        data = ws.receive()
        try:
            message = json.loads(data)
            token = message['token']
            email = message['email']
        except:
            raise WebSocketError("WebSocket data missing or incorrect type")

        if not db.get_email_by_token(token):
            ws.send(
                json.dumps({
                    'success': False,
                    'message': "You are not signed in."
                }))
            raise WebSocketError("User is not signed in")

        # Save connection
        sockets.add(token, email, ws)
        print "+ Connected with:", email, '({})'.format(request.remote_addr)

        sockets.success(token, "Connection established.")
        sockets.update_online_status()

        # Await client closing connection
        while True:
            data = ws.receive()
            if data == None:
                sockets.remove(token)
                break

    except WebSocketError as error:
        print "! WebSocketError:", error
    finally:
        print "- Disconnected from:", email
        ws.close()
        sockets.update_online_status()

    return ''
Example #2
0
    def send(self, message, opcode=OPCODE_TEXT):
        """Send a frame over the websocket with message as its payload

        Keyword args:
        opcode -- the opcode to use (default OPCODE_TEXT)
        """

        if self.fobj is None:
            return

        if not self._is_valid_opcode(opcode):
            raise ValueError('Invalid opcode %d' % opcode)

        if opcode == self.OPCODE_TEXT:
            message = self._encode_text(message)

        # TODO: implement fragmented messages
        mask_bit = 0
        fin = 1

        ## +-+-+-+-+-------+
        ## |F|R|R|R| opcode|
        ## |I|S|S|S|  (4)  |
        ## |N|V|V|V|       |
        ## | |1|2|3|       |
        ## +-+-+-+-+-------+
        header = chr((fin << 7) | (0 << 6) |  # RSV1
                     (0 << 5) |  # RSV2
                     (0 << 4) |  # RSV3
                     opcode)

        ##                 +-+-------------+-------------------------------+
        ##                 |M| Payload len |    Extended payload length    |
        ##                 |A|     (7)     |             (16/63)           |
        ##                 |S|             |   (if payload len==126/127)   |
        ##                 |K|             |                               |
        ## +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
        ## |     Extended payload length continued, if payload len == 127  |
        ## + - - - - - - - - - - - - - - - +-------------------------------+

        msg_length = len(message)

        if opcode == self.OPCODE_TEXT:
            message = struct.pack('!%ds' % msg_length, message)

        if msg_length < 126:
            header += chr(mask_bit | msg_length)
        elif msg_length < (1 << 16):
            header += chr(mask_bit | 126) + struct.pack('!H', msg_length)
        elif msg_length < (1 << 63):
            header += chr(mask_bit | 127) + struct.pack('!Q', msg_length)
        else:
            raise FrameTooLargeException()

        with self._writelock:
            try:
                self._write(header + message)
            except socket_error:
                self._close()
                raise WebSocketError()
Example #3
0
def proxy_user_websocket(ipaddr, port, path):
    def c2s(client, server):
        while True:
            inp = client.receive()
            if inp is None:
                raise WebSocketError()
            server.send(inp)

    def get_headers():
        headers = []
        #for header in request.environ:
        #    if not header.startswith('HTTP_'):
        #        continue
        #    if not header.startswith('HTTP_SEC_') \
        #            and not header.startswith('HTTP_ACCEPT_') \
        #            and not header.startswith('HTTP_USER_AGENT'):
        #        continue
        #    upper = True
        #    k = ''
        #    for c in header[5:].replace('_', '-').lower():
        #        if upper:
        #            k += c.upper()
        #            upper = False
        #        else:
        #            k += c
        #        if c == '-':
        #            upper = True
        #    headers.append('%s: %s' % (k, request.environ[header]))
        return headers

    #https://stackoverflow.com/questions/18240358/html5-websocket-connecting-to-python
    client = request.environ['wsgi.websocket']
    url = '%s:%d' % (ipaddr, port)
    if len(path) > 0:
        url += '/' + path
    logging.info('websocket: ' + url)
    headers = []
    #headers = get_headers()
    #logging.info('headers: ' + str(headers))
    server = websocket.create_connection("ws://" + url, header=headers)
    try:
        spawn(c2s, client, server)
        while True:
            inp = server.recv()
            if inp is None:
                raise WebSocketError()
            client.send(inp)
    except WebSocketError as e:
        logging.error(e)
    except client.WebSocketConnectionClosedException:
        pass
    return json.dumps({'status': 200})
Example #4
0
    def receive(self):
        read = self.fobj.read
        while self.fobj is not None:
            frame_str = read(1)
            if not frame_str:
                self.close()
                return
            else:
                frame_type = ord(frame_str)

            if frame_type == 0x00:
                bytes = self._read_until()
                return bytes.decode("utf-8", "replace")
            else:
                raise WebSocketError("Received an invalid "
                                     "frame_type=%r" % frame_type)
Example #5
0
    def _read_until(self):
        bytes = []

        read = self.fobj.read

        while True:
            if self.fobj is None:
                msg = ''.join(bytes)
                raise WebSocketError('Connection closed unexpectedly '
                                     'while reading message: %r' % msg)
            byte = read(1)
            if ord(byte) != 0xff:
                bytes.append(byte)
            else:
                break

        return ''.join(bytes)
Example #6
0
    def _message_length(self):
        length = 0

        while True:
            if self.fobj is None:
                raise WebSocketError('Connenction closed unexpectedly while'
                                     ' reading message length')
            byte_str = self.fobj.read(1)

            if not byte_str:
                return 0
            else:
                byte = ord(byte_str)

            if byte != 0x00:
                length = length * 128 + (byte & 0x7f)
                if (byte & 0x80) != 0x80:
                    break

        return length
Example #7
0
    def receive(self):
        """Return the next frame from the socket."""
        if self.fobj is None:
            raise WebSocketError('WS closed')

        while True:
            data0 = self._read(2)

            if data0 is None:
                self._close()
                raise WebSocketError('_read nothing')

            if not data0:
                # штатное закрытие по инициативе другой стороны
                break

            fin, opcode, mask, length = self._parse_header(data0)

            if length < 126:
                data1 = ''
            elif length == 126:
                data1 = self._read(2)
                if len(data1) != 2:
                    self._close()
                    raise WebSocketError('Incomplete read while reading '
                                         '2-byte length: %r' % (data0 + data1))
                length = struct.unpack('!H', data1)[0]
            elif length == 127:
                data1 = self._read(8)
                if len(data1) != 8:
                    self._close()
                    raise WebSocketError('Incomplete read while reading '
                                         '8-byte length: %r' % (data0 + data1))
                length = struct.unpack('!Q', data1)[0]
            else:
                self._close()
                raise WebSocketError('Invalid length: %r' % data0)

            # Unmask the payload if necessary
            if mask and length:
                data2 = self._read(4)
                if len(data2) != 4:
                    self._close()
                    raise WebSocketError('Incomplete read while reading '
                                         'mask: %r' % (data0 + data1 + data2))
                masking_key = struct.unpack('!BBBB', data2)
            else:
                data2 = ''

            if length:
                payload = self._read(length)
                if len(payload) != length:
                    self._close()
                    args = (length, data0 + data1 + data2, payload)
                    raise WebSocketError('Incomplete read (expected message '
                                         'of %s bytes): %r %r' % args)
            else:
                payload = ''

            if mask:
                # XXX message from client actually should always be masked
                masked_payload = bytearray(payload)

                for i in range(len(masked_payload)):
                    masked_payload[i] = masked_payload[i] ^ masking_key[i % 4]

                payload = masked_payload

            if opcode == self.OPCODE_TEXT:
                self._first_opcode = opcode
                if payload:
                    # XXX given that we have OPCODE_CONTINUATION,
                    # shouldn't we just reset _chunks here?
                    self._chunks.extend(payload)
            elif opcode == self.OPCODE_BINARY:
                self._first_opcode = opcode
                if payload:
                    self._chunks.extend(payload)
            elif opcode == self.OPCODE_CONTINUATION:
                self._chunks.extend(payload)
            elif opcode == self.OPCODE_CLOSE:
                if length >= 2:
                    reason, message = struct.unpack('!H%ds' % (length - 2),
                                                    buffer(payload))
                else:
                    reason = message = None
                self.close(self.REASON_NORMAL, '')
                return Closed(reason, message)
            elif opcode == self.OPCODE_PING:
                self.send(payload, opcode=self.OPCODE_PONG)
                continue
            elif opcode == self.OPCODE_PONG:
                continue
            else:
                self._close()
                raise WebSocketError("Unexpected opcode=%r" % (opcode, ))

            if fin == 1:
                if self._first_opcode == self.OPCODE_TEXT:
                    msg = self._chunks.decode("utf-8")
                else:
                    msg = self._chunks

                self._first_opcode = False
                self._chunks = bytearray()

                return msg
Example #8
0
 def _read(self, size):
     try:
         return self.fobj.read(size)
     except:
         raise WebSocketError("read failed")
Example #9
0
    def _parse_header(self, data):
        if len(data) != 2:
            self.close()
            raise WebSocketError('Incomplete read while reading header: %r' %
                                 data)
        first_byte, second_byte = struct.unpack('!BB', data)

        fin = (first_byte >> 7) & 1
        rsv1 = (first_byte >> 6) & 1
        rsv2 = (first_byte >> 5) & 1
        rsv3 = (first_byte >> 4) & 1
        opcode = first_byte & 0xf

        # frame-fin = %x0 ; more frames of this message follow
        #           / %x1 ; final frame of this message

        # frame-rsv1 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
        # frame-rsv2 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
        # frame-rsv3 = %x0 ; 1 bit, MUST be 0 unless negotiated otherwise
        if rsv1 or rsv2 or rsv3:
            self.close()
            raise WebSocketError('Reserved bits cannot be set: %r' % data)

        #if self._is_invalid_opcode(opcode):
        #    raise WebSocketError('Invalid opcode %x' % opcode)

        # control frames cannot be fragmented
        if opcode > 0x7 and fin == 0:
            self.close()
            raise WebSocketError('Control frames cannot be fragmented: %r' %
                                 data)

        if len(self._chunks) > 0 and fin == 0 \
                and opcode != self.OPCODE_CONTINUATION:
            self.close(self.REASON_PROTOCOL_ERROR,
                       'Received new fragment frame with non-zero opcode')
            raise WebSocketError('Received new fragment frame with '
                                 'non-zero opcode: %r' % data)

        if len(self._chunks) > 0 and fin == 1 \
                and (self.OPCODE_TEXT <= opcode <= self.OPCODE_BINARY):
            self.close(
                self.REASON_PROTOCOL_ERROR,
                'Received new unfragmented data frame during '
                'fragmented message')
            raise WebSocketError('Received new unfragmented data frame '
                                 'during fragmented message: %r' % data)

        mask = (second_byte >> 7) & 1
        length = (second_byte) & 0x7f

        #if not self.MASK & length_octet: # TODO: where is this in the docs?
        #    self.close(self.REASON_PROTOCOL_ERROR, 'MASK must be set')

        # Control frames MUST have a payload length of 125 bytes or less
        if opcode > 0x7 and length > 125:
            self.close()
            raise FrameTooLargeException("Control frame payload cannot "
                                         "be larger than 125 bytes: %r" % data)

        return fin, opcode, mask, length
Example #10
0
 def c2s(client, server):
     while True:
         inp = client.receive()
         if inp is None:
             raise WebSocketError()
         server.send(inp)