Example #1
0
    def test_read_frame_on_full_frame(self):
        class FrameReader(Frame):
            @classmethod
            def type(self):
                return 45

            @classmethod
            def parse(self, channel_id, payload):
                return 'no_frame'

        FrameReader.register()

        self.mock(frame, 'Reader')
        reader = self.mock()
        payload = self.mock()

        expect(reader.read_octet).returns(45)  # frame type
        expect(reader.read_short).returns(32)  # channel id
        expect(reader.read_long).returns(42)  # size

        expect(reader.tell).returns(5)
        expect(frame.Reader).args(reader, 5, 42).returns(payload)
        expect(reader.seek).args(42, 1)

        expect(reader.read_octet).returns(0xce)
        expect(FrameReader.parse).args(32, payload).returns('a_frame')

        assertEquals('a_frame', Frame._read_frame(reader))
Example #2
0
    def dispatch(self, frame):
        '''
        Override the default dispatch since we don't need the rest of
        the stack.
        '''
        if frame.type() == HeartbeatFrame.type():
            self.send_heartbeat()

        elif frame.type() == MethodFrame.type():
            if frame.class_id == 10:
                cb = self._method_map.get(frame.method_id)
                if cb:
                    method = self.clear_synchronous_cb(cb)
                    method(frame)
                else:
                    raise Channel.InvalidMethod(
                        "unsupported method %d on channel %d",
                        frame.method_id, self.channel_id)
            else:
                raise Channel.InvalidClass(
                    "class %d is not supported on channel %d",
                    frame.class_id, self.channel_id)

        else:
            raise Frame.InvalidFrameType(
                "frame type %d is not supported on channel %d",
                frame.type(), self.channel_id)
Example #3
0
    def test_read_frame_on_full_frame(self):
        class FrameReader(Frame):

            @classmethod
            def type(self):
                return 45

            @classmethod
            def parse(self, channel_id, payload):
                return 'no_frame'
        FrameReader.register()

        self.mock(frame, 'Reader')
        reader = self.mock()
        payload = self.mock()

        expect(reader.read_octet).returns(45)  # frame type
        expect(reader.read_short).returns(32)  # channel id
        expect(reader.read_long).returns(42)  # size

        expect(reader.tell).returns(5)
        expect(frame.Reader).args(reader, 5, 42).returns(payload)
        expect(reader.seek).args(42, 1)

        expect(reader.read_octet).returns(0xce)
        expect(FrameReader.parse).args(32, payload).returns('a_frame')

        assertEquals('a_frame', Frame._read_frame(reader))
Example #4
0
    def read_frames(self):
        '''
        Read frames from the transport and process them. Some transports may
        choose to do this in the background, in several threads, and so on.
        '''
        # It's possible in a concurrent environment that our transport handle
        # has gone away, so handle that cleanly.
        # TODO: Consider moving this block into Translator base class. In many
        # ways it belongs there. One of the problems though is that this is
        # essentially the read loop. Each Transport has different rules for
        # how to kick this off, and in the case of gevent, this is how a
        # blocking call to read from the socket is kicked off.
        if self._transport is None:
            return

        # Send a heartbeat (if needed)
        self._channels[0].send_heartbeat()

        data = self._transport.read(self._heartbeat)
        if data is None:
            return

        reader = Reader(data)
        p_channels = set()

        try:
            for frame in Frame.read_frames(reader):
                if self._debug > 1:
                    self.logger.debug("READ: %s", frame)
                self._frames_read += 1
                ch = self.channel(frame.channel_id)
                ch.buffer_frame(frame)
                p_channels.add(ch)
        except Frame.FrameError as e:
            # Frame error in the peer, disconnect
            self.close(reply_code=501,
                       reply_text='frame error from %s : %s' %
                       (self._host, str(e)),
                       class_id=0,
                       method_id=0,
                       disconnect=True)
            raise ConnectionClosed("connection is closed: %s : %s" %
                                   (self._close_info['reply_code'],
                                    self._close_info['reply_text']))

        self._transport.process_channels(p_channels)

        # HACK: read the buffer contents and re-buffer.  Would prefer to pass
        # buffer back, but there's no good way of asking the total size of the
        # buffer, comparing to tell(), and then re-buffering.  There's also no
        # ability to clear the buffer up to the current position. It would be
        # awesome if we could free that memory without a new allocation.
        if reader.tell() < len(data):
            self._transport.buffer(data[reader.tell():])
Example #5
0
    def read_frames(self):
        '''
        Read frames from the transport and process them. Some transports may
        choose to do this in the background, in several threads, and so on.
        '''
        # It's possible in a concurrent environment that our transport handle
        # has gone away, so handle that cleanly.
        # TODO: Consider moving this block into Translator base class. In many
        # ways it belongs there. One of the problems though is that this is
        # essentially the read loop. Each Transport has different rules for
        # how to kick this off, and in the case of gevent, this is how a
        # blocking call to read from the socket is kicked off.
        if self._transport is None:
            return

        # Send a heartbeat (if needed)
        self._channels[0].send_heartbeat()

        data = self._transport.read(self._heartbeat)
        if data is None:
            return

        reader = Reader(data)
        p_channels = set()

        try:
            for frame in Frame.read_frames(reader):
                if self._debug > 1:
                    self.logger.debug("READ: %s", frame)
                self._frames_read += 1
                ch = self.channel(frame.channel_id)
                ch.buffer_frame(frame)
                p_channels.add(ch)
        except Frame.FrameError as e:
            # Frame error in the peer, disconnect
            self.close(reply_code=501,
                       reply_text='frame error from %s : %s' % (
                           self._host, str(e)),
                       class_id=0, method_id=0, disconnect=True)
            raise ConnectionClosed("connection is closed: %s : %s" %
                                   (self._close_info['reply_code'],
                                    self._close_info['reply_text']))

        self._transport.process_channels(p_channels)

        # HACK: read the buffer contents and re-buffer.  Would prefer to pass
        # buffer back, but there's no good way of asking the total size of the
        # buffer, comparing to tell(), and then re-buffering.  There's also no
        # ability to clear the buffer up to the current position. It would be
        # awesome if we could free that memory without a new allocation.
        if reader.tell() < len(data):
            self._transport.buffer(data[reader.tell():])
Example #6
0
    def test_read_frames_reads_until_buffer_underflow(self):
        reader = mock()

        expect(reader.tell).returns(0)
        expect(Frame._read_frame).args(reader).returns('frame1')

        expect(reader.tell).returns(2)
        expect(Frame._read_frame).args(reader).returns('frame2')

        expect(reader.tell).returns(3)
        expect(Frame._read_frame).args(reader).raises(Reader.BufferUnderflow)

        expect(reader.seek).args(3)

        assertEquals(deque(['frame1', 'frame2']), Frame.read_frames(reader))
Example #7
0
    def test_read_frames_reads_until_buffer_underflow(self):
        reader = mock()

        expect(reader.tell).returns(0)
        expect(Frame._read_frame).args(reader).returns('frame1')

        expect(reader.tell).returns(2)
        expect(Frame._read_frame).args(reader).returns('frame2')

        expect(reader.tell).returns(3)
        expect(Frame._read_frame).args(reader).raises(Reader.BufferUnderflow)

        expect(reader.seek).args(3)

        assertEquals(deque(['frame1', 'frame2']), Frame.read_frames(reader))
Example #8
0
 def __init__(self, *args, **kwargs):
   Frame.__init__(self, *args, **kwargs)
Example #9
0
 def __init__(self, channel_id, class_id, method_id, args=None):
     Frame.__init__(self, channel_id)
     self._class_id = class_id
     self._method_id = method_id
     self._args = args
Example #10
0
    def read_frames(self):
        '''
        Read frames from the transport and process them. Some transports may
        choose to do this in the background, in several threads, and so on.
        '''
        # It's possible in a concurrent environment that our transport handle
        # has gone away, so handle that cleanly.
        # TODO: Consider moving this block into Translator base class. In many
        # ways it belongs there. One of the problems though is that this is
        # essentially the read loop. Each Transport has different rules for
        # how to kick this off, and in the case of gevent, this is how a
        # blocking call to read from the socket is kicked off.
        if self._transport is None:
            return

        # Send a heartbeat (if needed)
        self._channels[0].send_heartbeat()

        data = self._transport.read(self._heartbeat)
        current_time = time.time()

        if data is None:
            # Wait for 2 heartbeat intervals before giving up. See AMQP 4.2.7:
            # "If a peer detects no incoming traffic (i.e. received octets) for two heartbeat intervals or longer,
            # it should close the connection"
            if self._heartbeat and (current_time-self._last_octet_time > 2*self._heartbeat):
                msg = 'Heartbeats not received from %s for %d seconds' % (self._host, 2*self._heartbeat)
                self.transport_closed(msg=msg)
                raise ConnectionClosed('Connection is closed: ' + msg)
            return
        self._last_octet_time = current_time
        reader = Reader(data)
        p_channels = set()

        try:
            for frame in Frame.read_frames(reader):
                if self._debug > 1:
                    self.logger.debug("READ: %s", frame)
                self._frames_read += 1
                ch = self.channel(frame.channel_id)
                ch.buffer_frame(frame)
                p_channels.add(ch)
        except Frame.FrameError as e:
            # Frame error in the peer, disconnect
            self.close(reply_code=501,
                       reply_text='frame error from %s : %s' % (
                           self._host, str(e)),
                       class_id=0, method_id=0, disconnect=True)
            raise ConnectionClosed("connection is closed: %s : %s" %
                                   (self._close_info['reply_code'],
                                    self._close_info['reply_text']))

        # NOTE: we process channels after buffering unused data in order to
        # preserve the integrity of the input stream in case a channel needs to
        # read input, such as when a channel framing error necessitates the use
        # of the synchronous channel.close method. See `Channel.process_frames`.
        #
        # HACK: read the buffer contents and re-buffer.  Would prefer to pass
        # buffer back, but there's no good way of asking the total size of the
        # buffer, comparing to tell(), and then re-buffering.  There's also no
        # ability to clear the buffer up to the current position. It would be
        # awesome if we could free that memory without a new allocation.
        if reader.tell() < len(data):
            self._transport.buffer(data[reader.tell():])

        self._transport.process_channels(p_channels)
Example #11
0
 def __init__(self, channel_id, class_id, weight, size, properties={}):
     Frame.__init__(self, channel_id)
     self._class_id = class_id
     self._weight = weight
     self._size = size
     self._properties = properties
Example #12
0
 def test_str(self):
     frame = Frame(42)
     assert_equals('Frame[channel: 42]', str(frame))
Example #13
0
 def test_properties(self):
     frame = Frame('channel_id')
     assert_equals('channel_id', frame.channel_id)
Example #14
0
    def read_frames(self):
        '''
        Read frames from the transport and process them. Some transports may
        choose to do this in the background, in several threads, and so on.
        '''
        # It's possible in a concurrent environment that our transport handle
        # has gone away, so handle that cleanly.
        # TODO: Consider moving this block into Translator base class. In many
        # ways it belongs there. One of the problems though is that this is
        # essentially the read loop. Each Transport has different rules for
        # how to kick this off, and in the case of gevent, this is how a
        # blocking call to read from the socket is kicked off.
        if self._transport is None:
            return

        # Send a heartbeat (if needed)
        self._channels[0].send_heartbeat()

        data = self._transport.read(self._heartbeat)
        current_time = time.time()

        if data is None:
            # Wait for 2 heartbeat intervals before giving up. See AMQP 4.2.7:
            # "If a peer detects no incoming traffic (i.e. received octets) for two heartbeat intervals or longer,
            # it should close the connection"
            if self._heartbeat and (current_time-self._last_octet_time > 2*self._heartbeat):
                msg = 'Heartbeats not received from %s for %d seconds' % (self._host, 2*self._heartbeat)
                self.transport_closed(msg=msg)
                raise ConnectionClosed('Connection is closed: ' + msg)
            return
        self._last_octet_time = current_time
        reader = Reader(data)
        p_channels = set()

        try:
            for frame in Frame.read_frames(reader):
                if self._debug > 1:
                    self.logger.debug("READ: %s", frame)
                self._frames_read += 1
                ch = self.channel(frame.channel_id)
                ch.buffer_frame(frame)
                p_channels.add(ch)
        except Frame.FrameError as e:
            # Frame error in the peer, disconnect
            self.close(reply_code=501,
                       reply_text='frame error from %s : %s' % (
                           self._host, str(e)),
                       class_id=0, method_id=0, disconnect=True)
            raise ConnectionClosed("connection is closed: %s : %s" %
                                   (self._close_info['reply_code'],
                                    self._close_info['reply_text']))

        # NOTE: we process channels after buffering unused data in order to
        # preserve the integrity of the input stream in case a channel needs to
        # read input, such as when a channel framing error necessitates the use
        # of the synchronous channel.close method. See `Channel.process_frames`.
        #
        # HACK: read the buffer contents and re-buffer.  Would prefer to pass
        # buffer back, but there's no good way of asking the total size of the
        # buffer, comparing to tell(), and then re-buffering.  There's also no
        # ability to clear the buffer up to the current position. It would be
        # awesome if we could free that memory without a new allocation.
        if reader.tell() < len(data):
            self._transport.buffer(data[reader.tell():])

        self._transport.process_channels(p_channels)
Example #15
0
 def __init__(self, channel_id, payload):
   Frame.__init__(self, channel_id)
   self._payload = payload
Example #16
0
 def __init__(self, channel_id, class_id, weight, size, properties={}):
     Frame.__init__(self, channel_id)
     self._class_id = class_id
     self._weight = weight
     self._size = size
     self._properties = properties
Example #17
0
 def test_repr(self):
     expect(Frame.__str__).returns('foo')
     frame = Frame(42)
     assert_equals('foo', repr(frame))
Example #18
0
 def __init__(self, channel_id, class_id, method_id, args=None):
   Frame.__init__(self, channel_id)
   self._class_id = class_id
   self._method_id = method_id
   self._args = args
Example #19
0
 def test_write_frame(self):
     frame = Frame(42)
     assert_raises(NotImplementedError, frame.write_frame, 'stream')