Example #1
0
    def post(self, session_id):
        # Get session
        self.session = self._get_session(session_id)

        # Can not send messages to closed session or if preflight() failed
        if self.session.is_closed or not self.preflight():
            raise HTTPError(401)

        # Socket.io always send data utf-8 encoded.
        data = self.request.body

        # IE XDomainRequest support
        if not data.startswith('d='):
            logging.error('Malformed JSONP POST request')
            raise HTTPError(403)

        # Grab data
        data = urllib.unquote(data[2:]).decode('utf-8')

        # If starts with double quote, it is json encoded (socket.io workaround)
        if data.startswith(u'"'):
            data = proto.json_load(data)

        # Process packets one by one
        packets = proto.decode_frames(data)
        for p in packets:
            try:
                self.session.raw_message(p)
            except Exception:
                # Close session if something went wrong
                self.session.close()

        self.set_header('Content-Type', 'text/plain; charset=UTF-8')
        self.finish()
Example #2
0
    def post(self, session_id):
        try:
            # Stats
            self.server.stats.connection_opened()

            # Get session
            self.session = self._get_session(session_id)

            # Can not send messages to closed session or if preflight() failed
            if self.session.is_closed or not self.preflight():
                raise HTTPError(401)

            # Socket.io always send data utf-8 encoded.
            data = self.request.body

            # IE XDomainRequest support
            if not data.startswith('d='):
                logging.error('Malformed JSONP POST request')
                raise HTTPError(403)

            # Grab data
            data = urllib.unquote_plus(data[2:]).decode('utf-8')

            # If starts with double quote, it is json encoded (socket.io workaround)
            if data.startswith(u'"'):
                data = proto.json_load(data)

            # Process packets one by one
            packets = proto.decode_frames(data)

            # Tracking
            self.server.stats.on_packet_recv(len(packets))

            for p in packets:
                try:
                    self.session.raw_message(p)
                except Exception:
                    # Close session if something went wrong
                    self.session.close()

            self.set_header('Content-Type', 'text/plain; charset=UTF-8')
            self.finish()
        finally:
            self.server.stats.connection_closed()
Example #3
0
    def raw_message(self, msg):
        """Socket.IO message handler.

        `msg`
            Raw socket.io message to handle
        """
        try:
            logging.debug('>>> ' + msg)

            parts = msg.split(':', 3)
            if len(parts) == 3:
                msg_type, msg_id, msg_endpoint = parts
                msg_data = None
            else:
                msg_type, msg_id, msg_endpoint, msg_data = parts

            # Packets that don't require valid endpoint
            if msg_type == proto.DISCONNECT:
                if not msg_endpoint:
                    self.close()
                else:
                    self.disconnect_endpoint(msg_endpoint)
                return
            elif msg_type == proto.CONNECT:
                if msg_endpoint:
                    self.connect_endpoint(msg_endpoint)
                else:
                    # TODO: Disconnect?
                    logging.error('Invalid connect without endpoint')
                return

            # All other packets need endpoints
            conn = self.get_connection(msg_endpoint)
            if conn is None:
                logging.error('Invalid endpoint: %s' % msg_endpoint)
                return

            if msg_type == proto.HEARTBEAT:
                self._missed_heartbeats = 0
            elif msg_type == proto.MESSAGE:
                # Handle text message
                conn.on_message(msg_data)

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.JSON:
                # Handle json message
                conn.on_message(proto.json_load(msg_data))

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.EVENT:
                # Javascript event
                event = proto.json_load(msg_data)

                # TODO: Verify if args = event.get('args', []) won't be slower.
                args = event.get('args')
                if args is None:
                    args = []

                ack_response = None

                # It is kind of magic - if there's only one parameter
                # and it is dict, unpack dictionary. Otherwise, pass
                # in args
                if len(args) == 1 and isinstance(args[0], dict):
                    # Fix for the http://bugs.python.org/issue4978 for older Python versions
                    str_args = dict(
                        (str(x), y) for x, y in args[0].iteritems())

                    ack_response = conn.on_event(event['name'],
                                                 kwargs=str_args)
                else:
                    ack_response = conn.on_event(event['name'], args=args)

                if msg_id:
                    if msg_id.endswith('+'):
                        msg_id = msg_id[:-1]

                    self.send_message(
                        proto.ack(msg_endpoint, msg_id, ack_response))
            elif msg_type == proto.ACK:
                # Handle ACK
                ack_data = msg_data.split('+', 2)

                data = None
                if len(ack_data) > 1:
                    data = proto.json_load(ack_data[1])

                conn.deque_ack(int(ack_data[0]), data)
            elif msg_type == proto.ERROR:
                # TODO: Pass it to handler?
                logging.error('Incoming error: %s' % msg_data)
            elif msg_type == proto.NOOP:
                pass
        except Exception, ex:
            logging.exception(ex)

            # TODO: Add global exception callback?

            raise
Example #4
0
    def raw_message(self, msg):
        """Socket.IO message handler.

        `msg`
            Raw socket.io message to handle
        """
        try:
            logging.debug('>>> ' + msg)

            parts = msg.split(':', 3)
            if len(parts) == 3:
                msg_type, msg_id, msg_endpoint = parts
                msg_data = None
            else:
                msg_type, msg_id, msg_endpoint, msg_data = parts

            # Packets that don't require valid endpoint
            if msg_type == proto.DISCONNECT:
                if not msg_endpoint:
                    self.close()
                else:
                    self.disconnect_endpoint(msg_endpoint)
                return
            elif msg_type == proto.CONNECT:
                if msg_endpoint:
                    self.connect_endpoint(msg_endpoint)
                else:
                    # TODO: Disconnect?
                    logging.error('Invalid connect without endpoint')
                return

            # All other packets need endpoints
            conn = self.get_connection(msg_endpoint)
            if conn is None:
                logging.error('Invalid endpoint: %s' % msg_endpoint)
                return

            if msg_type == proto.HEARTBEAT:
                self._missed_heartbeats = 0
            elif msg_type == proto.MESSAGE:
                # Handle text message
                conn.on_message(msg_data)

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.JSON:
                # Handle json message
                conn.on_message(proto.json_load(msg_data))

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.EVENT:
                # Javascript event
                event = proto.json_load(msg_data)

                # TODO: Verify if args = event.get('args', []) won't be slower.
                args = event.get('args')
                if args is None:
                    args = []

                ack_response = None

                # It is kind of magic - if there's only one parameter
                # and it is dict, unpack dictionary. Otherwise, pass
                # in args
                if len(args) == 1 and isinstance(args[0], dict):
                    # Fix for the http://bugs.python.org/issue4978 for older Python versions
                    str_args = dict((str(x), y) for x, y in args[0].iteritems())

                    ack_response = conn.on_event(event['name'], kwargs=str_args)
                else:
                    ack_response = conn.on_event(event['name'], args=args)

                if msg_id:
                    if msg_id.endswith('+'):
                        msg_id = msg_id[:-1]

                    self.send_message(proto.ack(msg_endpoint, msg_id, ack_response))
            elif msg_type == proto.ACK:
                # Handle ACK
                ack_data = msg_data.split('+', 2)

                data = None
                if len(ack_data) > 1:
                    data = proto.json_load(ack_data[1])

                conn.deque_ack(int(ack_data[0]), data)
            elif msg_type == proto.ERROR:
                # TODO: Pass it to handler?
                logging.error('Incoming error: %s' % msg_data)
            elif msg_type == proto.NOOP:
                pass
        except Exception, ex:
            logging.exception(ex)

            # TODO: Add global exception callback?

            raise
Example #5
0
    def raw_message(self, msg):
        """Socket.IO message handler.

        `msg`
            Raw socket.io message to process.
        """
        try:
            logging.debug('>>> ' + msg)

            parts = msg.split(':', 3)
            if len(parts) == 3:
                msg_type, msg_id, msg_endpoint = parts
                msg_data = None
            else:
                msg_type, msg_id, msg_endpoint, msg_data = parts

            # Packets that don't require valid endpoint
            if msg_type == proto.DISCONNECT:
                if not msg_endpoint:
                    self.close()
                else:
                    self.disconnect_endpoint(msg_endpoint)
                return
            elif msg_type == proto.CONNECT:
                if msg_endpoint:
                    self.connect_endpoint(msg_endpoint)
                else:
                    # TODO: Disconnect?
                    logging.error('Invalid connect without endpoint')
                return

            # All other packets need endpoints
            conn = self.get_connection(msg_endpoint)
            if conn is None:
                logging.error('Invalid endpoint: %s' % msg_endpoint)
                return

            if msg_type == proto.HEARTBEAT:
                self._missed_heartbeats = 0
            elif msg_type == proto.MESSAGE:
                # Handle text message
                conn.on_message(msg_data)

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.JSON:
                # Handle json message
                conn.on_message(proto.json_load(msg_data))

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.EVENT:
                # Javascript event
                event = proto.json_load(msg_data)

                args = event['args']

                # It is kind of magic - if there's only one parameter
                # and it is dict, unpack dictionary. Otherwise, pass
                # as *args
                if len(args) == 1 and isinstance(args[0], dict):
                    conn.on_event(event['name'], **args[0])
                else:
                    conn.on_event(event['name'], *args)

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.ACK:
                # Handle ACK
                ack_data = msg_data.split('+', 2)

                # TODO: Support custom data sent from the server
                conn.deque_ack(int(ack_data[0]))
            elif msg_type == proto.ERROR:
                # TODO: Pass it to handler?
                logging.error('Incoming error: %s' % msg_data)
            elif msg_type == proto.NOOP:
                pass
        except Exception, ex:
            logging.exception(ex)

            # TODO: Add global exception callback?

            raise
Example #6
0
    def raw_message(self, msg):
        """Socket.IO message handler.

        `msg`
            Raw socket.io message to process.
        """
        try:
            logging.debug('>>> ' + msg)

            parts = msg.split(':', 3)
            if len(parts) == 3:
                msg_type, msg_id, msg_endpoint = parts
                msg_data = None
            else:
                msg_type, msg_id, msg_endpoint, msg_data = parts

            # Packets that don't require valid endpoint
            if msg_type == proto.DISCONNECT:
                if not msg_endpoint:
                    self.close()
                else:
                    self.disconnect_endpoint(msg_endpoint)
                return
            elif msg_type == proto.CONNECT:
                if msg_endpoint:
                    self.connect_endpoint(msg_endpoint)
                else:
                    # TODO: Disconnect?
                    logging.error('Invalid connect without endpoint')
                return

            # All other packets need endpoints
            conn = self.get_connection(msg_endpoint)
            if conn is None:
                logging.error('Invalid endpoint: %s' % msg_endpoint)
                return

            if msg_type == proto.HEARTBEAT:
                self._missed_heartbeats = 0
            elif msg_type == proto.MESSAGE:
                # Handle text message
                conn.on_message(msg_data)

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.JSON:
                # Handle json message
                conn.on_message(proto.json_load(msg_data))

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.EVENT:
                # Javascript event
                event = proto.json_load(msg_data)

                args = event['args']

                # It is kind of magic - if there's only one parameter
                # and it is dict, unpack dictionary. Otherwise, pass
                # as *args
                if len(args) == 1 and isinstance(args[0], dict):
                    conn.on_event(event['name'], **args[0])
                else:
                    conn.on_event(event['name'], *args)

                if msg_id:
                    self.send_message(proto.ack(msg_endpoint, msg_id))
            elif msg_type == proto.ACK:
                # Handle ACK
                ack_data = msg_data.split('+', 2)

                # TODO: Support custom data sent from the server
                conn.deque_ack(int(ack_data[0]))
            elif msg_type == proto.ERROR:
                # TODO: Pass it to handler?
                logging.error('Incoming error: %s' % msg_data)
            elif msg_type == proto.NOOP:
                pass
        except Exception, ex:
            logging.exception(ex)

            # TODO: Add global exception callback?

            raise