class StompRequestHandler(BaseRequestHandler, StompConnection): """ Class that will be instantiated to handle STOMP connections. This class will be instantiated once per connection to the server. In a multi-threaded context, that means that instances of this class are scoped to a single thread. It should be noted that while the L{coilmq.engine.StompEngine} instance will be thread-local, the storage containers configured into the engine are not thread-local (and hence must be thread-safe). @ivar buffer: A StompBuffer instance which buffers received data (to ensure we deal with complete STOMP messages. @type buffer: C{stompclient.util.FrameBuffer} @ivar engine: The STOMP protocol engine. @type engine: L{coilmq.engine.StompEngine} @ivar debug: Whether to enable extra-verbose debug logging. (Will be logged at debug level.) @type debug: C{bool} """ def setup(self): if self.server.timeout is not None: self.request.settimeout(self.server.timeout) self.debug = False self.log = logging.getLogger('%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = FrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager) def handle(self): """ Handle a new socket connection. """ # self.request is the TCP socket connected to the client try: while not self.server._shutdown_request_event.is_set(): try: data = self.request.recv(8192) if not data: break if self.debug: self.log.debug("RECV: %r" % data) self.buffer.append(data) for frame in self.buffer: self.log.debug("Processing frame: %s" % frame) self.engine.process_frame(frame) if not self.engine.connected: raise ClientDisconnected() except socket.timeout: pass except ClientDisconnected: self.log.debug("Client disconnected, discontinuing read loop.") except Exception, e: self.log.error("Error receiving data (unbinding): %s" % e) self.engine.unbind() raise
def setUp(self): self.qm = MockQueueManager() self.tm = MockTopicManager() self.conn = MockConnection() self.auth = MockAuthenticator() self.engine = StompEngine(connection=self.conn, queue_manager=self.qm, topic_manager=self.tm, authenticator=None)
def setup(self): self.debug = False self.log = logging.getLogger( '%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = StompFrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager)
class StompProtocol(Protocol, StompConnection): """ Subclass of C{twisted.internet.protocol.Protocol} for handling STOMP communications. An instance of this class will be created for each connecting client. @ivar buffer: A StompBuffer instance which buffers received data (to ensure we deal with complete STOMP messages. @type buffer: C{stomper.stompbuffer.StompBuffer} @ivar engine: The STOMP protocol engine. @type engine: L{coilmq.engine.StompEngine} """ def __init__(self, queue_manager, topic_manager): self.log = logging.getLogger( '%s.%s' % (self.__class__.__module__, self.__class__.__name__)) self.log.debug("Initializing StompProtocol.") self.buffer = StompFrameBuffer() self.engine = StompEngine( connection=self, authenticator=None, # FIXME: Add the authenticator queue_manager=queue_manager, topic_manager=topic_manager) def connectionLost(self, reason): Protocol.connectionLost(self, reason) self.log.debug("Connection lost.") self.engine.unbind() def connectionMade(self): self.log.debug("Connection made.") def dataReceived(self, data): """ Twisted calls this method when data is received. Note: The data may not be not be a complete frame or may be more than one frame. """ self.log.debug("Data received: %s" % data) self.buffer.append(data) # print '%r' % self.buffer for frame in self.buffer: self.log.debug("Processing frame: %s" % frame) self.engine.process_frame(frame) def send_frame(self, frame): """ Sends a frame to connected socket client. (Sorry, Twisted, our code is PEP-8.) @param frame: The frame to send. @type frame: L{coilmq.frame.StompFrame} """ self.transport.write(frame.pack())
def __init__(self, queue_manager, topic_manager): self.log = logging.getLogger( '%s.%s' % (self.__class__.__module__, self.__class__.__name__)) self.log.debug("Initializing StompProtocol.") self.buffer = StompFrameBuffer() self.engine = StompEngine( connection=self, authenticator=None, # FIXME: Add the authenticator queue_manager=queue_manager, topic_manager=topic_manager)
class StompProtocol(Protocol, StompConnection): """ Subclass of C{twisted.internet.protocol.Protocol} for handling STOMP communications. An instance of this class will be created for each connecting client. @ivar buffer: A StompBuffer instance which buffers received data (to ensure we deal with complete STOMP messages. @type buffer: C{stomper.stompbuffer.StompBuffer} @ivar engine: The STOMP protocol engine. @type engine: L{coilmq.engine.StompEngine} """ def __init__(self, queue_manager, topic_manager): self.log = logging.getLogger('%s.%s' % (self.__class__.__module__, self.__class__.__name__)) self.log.debug("Initializing StompProtocol.") self.buffer = StompFrameBuffer() self.engine = StompEngine(connection=self, authenticator=None, # FIXME: Add the authenticator queue_manager=queue_manager, topic_manager=topic_manager) def connectionLost(self, reason): Protocol.connectionLost(self, reason) self.log.debug("Connection lost.") self.engine.unbind() def connectionMade(self): self.log.debug("Connection made.") def dataReceived(self, data): """ Twisted calls this method when data is received. Note: The data may not be not be a complete frame or may be more than one frame. """ self.log.debug("Data received: %s" % data) self.buffer.append(data) # print '%r' % self.buffer for frame in self.buffer: self.log.debug("Processing frame: %s" % frame) self.engine.process_frame(frame) def send_frame(self, frame): """ Sends a frame to connected socket client. (Sorry, Twisted, our code is PEP-8.) @param frame: The frame to send. @type frame: L{coilmq.frame.StompFrame} """ self.transport.write(frame.pack())
def setup(self): if self.server.timeout is not None: self.request.settimeout(self.server.timeout) self.debug = False self.log = logging.getLogger( '%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = FrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager, protocol=self.server.protocol)
def setup(self): self.debug = False self.log = logging.getLogger('%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = StompFrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager)
def __init__(self, queue_manager, topic_manager): self.log = logging.getLogger('%s.%s' % (self.__class__.__module__, self.__class__.__name__)) self.log.debug("Initializing StompProtocol.") self.buffer = StompFrameBuffer() self.engine = StompEngine(connection=self, authenticator=None, # FIXME: Add the authenticator queue_manager=queue_manager, topic_manager=topic_manager)
def setup(self): if self.server.timeout is not None: self.request.settimeout(self.server.timeout) self.debug = False self.log = logging.getLogger('%s.%s' % (self.__module__, self.__class__.__name__)) self.buffer = FrameBuffer() self.engine = StompEngine(connection=self, authenticator=self.server.authenticator, queue_manager=self.server.queue_manager, topic_manager=self.server.topic_manager, protocol=self.server.protocol)
class ProtocolBaseTestCase(unittest.TestCase): def get_protocol(self): return STOMP12 def setUp(self): self.qm = MockQueueManager() self.tm = MockTopicManager() self.conn = MockConnection() self.auth = MockAuthenticator() self.engine = StompEngine(connection=self.conn, queue_manager=self.qm, topic_manager=self.tm, authenticator=None, protocol=self.get_protocol()) def feed_frame(self, cmd, headers=None, body=''): self.engine.process_frame(Frame(cmd, headers or {}, body)) return self.conn.frames[-1] def tearDown(self): self.conn.reset()
class EngineTest(unittest.TestCase): def setUp(self): self.qm = MockQueueManager() self.tm = MockTopicManager() self.conn = MockConnection() self.auth = MockAuthenticator() self.engine = StompEngine(connection=self.conn, queue_manager=self.qm, topic_manager=self.tm, authenticator=None) def tearDown(self): self.conn.reset() def _connect(self): """ Call the engine connect() method so that we have a valid 'session'. """ self.engine.connect(Frame('CONNECT')) def assertErrorFrame(self, frame, msgsub): """ Assert that the passed in frame is an error frame and that message contains specified string. """ assert frame.command == 'ERROR' assert msgsub.lower() in frame.headers['message'].lower() def test_connect_no_auth(self): """ Test the CONNECT command with no auth required. """ assert self.engine.connected == False self.engine.process_frame(Frame('CONNECT')) assert self.engine.connected == True def test_connect_auth(self): """ Test the CONNECT command when auth is required. """ self.engine.authenticator = self.auth assert self.engine.connected == False self.engine.process_frame(Frame('CONNECT')) self.assertErrorFrame(self.conn.frames[-1], 'Auth') assert self.engine.connected == False self.engine.process_frame( Frame('CONNECT', headers={ 'login': MockAuthenticator.LOGIN, 'passcode': MockAuthenticator.PASSCODE })) assert self.engine.connected == True def test_subscribe_noack(self): """ Test subscribing to topics and queues w/ no ACK. """ self._connect() self.engine.process_frame( Frame('SUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn in self.qm.queues['/queue/bar'] self.engine.process_frame( Frame('SUBSCRIBE', headers={'destination': '/foo/bar'})) assert self.conn in self.tm.topics['/foo/bar'] def test_send(self): """ Test sending to a topic and queue. """ self._connect() msg = Frame('SEND', headers={'destination': '/queue/foo'}, body='QUEUEMSG-BODY') self.engine.process_frame(msg) assert msg == self.qm.messages[-1] msg = Frame('SEND', headers={'destination': '/topic/foo'}, body='TOPICMSG-BODY') self.engine.process_frame(msg) assert msg == self.tm.messages[-1] msg = Frame('SEND', headers={}, body='TOPICMSG-BODY') self.engine.process_frame(msg) self.assertErrorFrame(self.conn.frames[-1], 'Missing destination') def test_receipt(self): """ Test pushing frames with a receipt specified. """ self._connect() receipt_id = 'FOOBAR' msg = Frame('SEND', headers={ 'destination': '/queue/foo', 'receipt': receipt_id }, body='QUEUEMSG-BODY') self.engine.process_frame(msg) rframe = self.conn.frames[-1] assert isinstance(rframe, ReceiptFrame) assert receipt_id == rframe.receipt_id receipt_id = 'FOOBAR2' self.engine.process_frame( Frame('SUBSCRIBE', headers={ 'destination': '/queue/bar', 'receipt': receipt_id })) rframe = self.conn.frames[-1] assert isinstance(rframe, ReceiptFrame) assert receipt_id == rframe.receipt_id def test_subscribe_ack(self): """ Test subscribing to a queue with ack=true """ self._connect() self.engine.process_frame( Frame('SUBSCRIBE', headers={ 'destination': '/queue/bar', 'ack': 'client' })) assert self.conn.reliable_subscriber == True assert self.conn in self.qm.queues['/queue/bar'] def test_unsubscribe(self): """ Test the UNSUBSCRIBE command. """ self._connect() self.engine.process_frame( Frame('SUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn in self.qm.queues['/queue/bar'] print self.conn.frames self.engine.process_frame( Frame('UNSUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn not in self.qm.queues['/queue/bar'] print self.conn.frames self.engine.process_frame( Frame('UNSUBSCRIBE', headers={'destination': '/invalid'})) print self.conn.frames[-1] def test_begin(self): """ Test transaction BEGIN. """ self._connect() self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) assert 'abc' in self.engine.transactions assert len(self.engine.transactions['abc']) == 0 def test_commit(self): """ Test transaction COMMIT. """ self._connect() self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('BEGIN', headers={'transaction': '123'})) self.engine.process_frame( Frame('SEND', headers={ 'destination': '/dest', 'transaction': 'abc' }, body='ASDF')) self.engine.process_frame( Frame('SEND', headers={ 'destination': '/dest', 'transaction': 'abc' }, body='ASDF')) self.engine.process_frame( Frame('SEND', headers={ 'destination': '/dest', 'transaction': '123' }, body='ASDF')) assert len(self.tm.messages) == 0 self.engine.process_frame( Frame('COMMIT', headers={'transaction': 'abc'})) print self.conn.frames assert len(self.tm.messages) == 2 assert len(self.engine.transactions) == 1 self.engine.process_frame( Frame('COMMIT', headers={'transaction': '123'})) assert len(self.tm.messages) == 3 assert len(self.engine.transactions) == 0 def test_commit_invalid(self): """ Test invalid states for transaction COMMIT. """ self._connect() # Send a message with invalid transaction f = Frame('SEND', headers={ 'destination': '/dest', 'transaction': '123' }, body='ASDF') self.engine.process_frame(f) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') # Attempt to commit invalid transaction self.engine.process_frame( Frame('COMMIT', headers={'transaction': 'abc'})) # Attempt to commit already-committed transaction self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('SEND', headers={ 'destination': '/dest', 'transaction': 'abc' }, body='FOO')) self.engine.process_frame( Frame('COMMIT', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('COMMIT', headers={'transaction': 'abc'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') def test_abort(self): """ Test transaction ABORT. """ self._connect() self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('BEGIN', headers={'transaction': '123'})) f1 = Frame('SEND', headers={ 'destination': '/dest', 'transaction': 'abc' }, body='ASDF') self.engine.process_frame(f1) f2 = Frame('SEND', headers={ 'destination': '/dest', 'transaction': 'abc' }, body='ASDF') self.engine.process_frame(f2) f3 = Frame('SEND', headers={ 'destination': '/dest', 'transaction': '123' }, body='ASDF') self.engine.process_frame(f3) assert len(self.tm.messages) == 0 self.engine.process_frame( Frame('ABORT', headers={'transaction': 'abc'})) assert len(self.tm.messages) == 0 assert len(self.engine.transactions) == 1 def test_abort_invalid(self): """ Test invalid states for transaction ABORT. """ self._connect() self.engine.process_frame( Frame('ABORT', headers={'transaction': 'abc'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('ABORT', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('ABORT', headers={'transaction': 'abc2'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction')
class EngineTest(unittest.TestCase): def setUp(self): self.qm = MockQueueManager() self.tm = MockTopicManager() self.conn = MockConnection() self.auth = MockAuthenticator() self.engine = StompEngine(connection=self.conn, queue_manager=self.qm, topic_manager=self.tm, authenticator=None) def tearDown(self): self.conn.reset() def _connect(self): """ Call the engine connect() method so that we have a valid 'session'. """ self.engine.connect(Frame('CONNECT')) def assertErrorFrame(self, frame, msgsub): """ Assert that the passed in frame is an error frame and that message contains specified string. """ assert frame.command == 'ERROR' assert msgsub.lower() in frame.headers['message'].lower() def test_connect_no_auth(self): """ Test the CONNECT command with no auth required. """ assert self.engine.connected == False self.engine.process_frame(Frame('CONNECT')) assert self.engine.connected == True def test_connect_auth(self): """ Test the CONNECT command when auth is required. """ self.engine.authenticator = self.auth assert self.engine.connected == False self.engine.process_frame(Frame('CONNECT')) self.assertErrorFrame(self.conn.frames[-1], 'Auth') assert self.engine.connected == False self.engine.process_frame(Frame('CONNECT', headers={'login': MockAuthenticator.LOGIN, 'passcode': MockAuthenticator.PASSCODE})) assert self.engine.connected == True def test_subscribe_noack(self): """ Test subscribing to topics and queues w/ no ACK. """ self._connect() self.engine.process_frame(Frame('SUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn in self.qm.queues['/queue/bar'] self.engine.process_frame(Frame('SUBSCRIBE', headers={'destination': '/foo/bar'})) assert self.conn in self.tm.topics['/foo/bar'] def test_send(self): """ Test sending to a topic and queue. """ self._connect() msg = Frame('SEND', headers={'destination': '/queue/foo'}, body='QUEUEMSG-BODY') self.engine.process_frame(msg) assert msg == self.qm.messages[-1] msg = Frame('SEND', headers={'destination': '/topic/foo'}, body='TOPICMSG-BODY') self.engine.process_frame(msg) assert msg == self.tm.messages[-1] msg = Frame('SEND', headers={}, body='TOPICMSG-BODY') self.engine.process_frame(msg) self.assertErrorFrame(self.conn.frames[-1], 'Missing destination') def test_receipt(self): """ Test pushing frames with a receipt specified. """ self._connect() receipt_id = 'FOOBAR' msg = Frame('SEND', headers={'destination': '/queue/foo', 'receipt': receipt_id}, body='QUEUEMSG-BODY') self.engine.process_frame(msg) rframe = self.conn.frames[-1] assert isinstance(rframe, ReceiptFrame) assert receipt_id == rframe.receipt_id receipt_id = 'FOOBAR2' self.engine.process_frame(Frame('SUBSCRIBE', headers={'destination': '/queue/bar', 'receipt': receipt_id})) rframe = self.conn.frames[-1] assert isinstance(rframe, ReceiptFrame) assert receipt_id == rframe.receipt_id def test_subscribe_ack(self): """ Test subscribing to a queue with ack=true """ self._connect() self.engine.process_frame(Frame('SUBSCRIBE', headers={'destination': '/queue/bar', 'ack': 'client'})) assert self.conn.reliable_subscriber == True assert self.conn in self.qm.queues['/queue/bar'] def test_unsubscribe(self): """ Test the UNSUBSCRIBE command. """ self._connect() self.engine.process_frame(Frame('SUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn in self.qm.queues['/queue/bar'] print self.conn.frames self.engine.process_frame(Frame('UNSUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn not in self.qm.queues['/queue/bar'] print self.conn.frames self.engine.process_frame(Frame('UNSUBSCRIBE', headers={'destination': '/invalid'})) print self.conn.frames[-1] def test_begin(self): """ Test transaction BEGIN. """ self._connect() self.engine.process_frame(Frame('BEGIN', headers={'transaction': 'abc'})) assert 'abc' in self.engine.transactions assert len(self.engine.transactions['abc']) == 0 def test_commit(self): """ Test transaction COMMIT. """ self._connect() self.engine.process_frame(Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame(Frame('BEGIN', headers={'transaction': '123'})) self.engine.process_frame(Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF')) self.engine.process_frame(Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF')) self.engine.process_frame(Frame('SEND', headers={'destination': '/dest', 'transaction': '123'}, body='ASDF')) assert len(self.tm.messages) == 0 self.engine.process_frame(Frame('COMMIT', headers={'transaction': 'abc'})) print self.conn.frames assert len(self.tm.messages) == 2 assert len(self.engine.transactions) == 1 self.engine.process_frame(Frame('COMMIT', headers={'transaction': '123'})) assert len(self.tm.messages) == 3 assert len(self.engine.transactions) == 0 def test_commit_invalid(self): """ Test invalid states for transaction COMMIT. """ self._connect() # Send a message with invalid transaction f = Frame('SEND', headers={'destination': '/dest', 'transaction': '123'}, body='ASDF') self.engine.process_frame(f) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') # Attempt to commit invalid transaction self.engine.process_frame(Frame('COMMIT', headers={'transaction': 'abc'})) # Attempt to commit already-committed transaction self.engine.process_frame(Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame(Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='FOO')) self.engine.process_frame(Frame('COMMIT', headers={'transaction': 'abc'})) self.engine.process_frame(Frame('COMMIT', headers={'transaction': 'abc'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') def test_abort(self): """ Test transaction ABORT. """ self._connect() self.engine.process_frame(Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame(Frame('BEGIN', headers={'transaction': '123'})) f1 = Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF') self.engine.process_frame(f1) f2 = Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF') self.engine.process_frame(f2) f3 = Frame('SEND', headers={'destination': '/dest', 'transaction': '123'}, body='ASDF') self.engine.process_frame(f3) assert len(self.tm.messages) == 0 self.engine.process_frame(Frame('ABORT', headers={'transaction': 'abc'})) assert len(self.tm.messages) == 0 assert len(self.engine.transactions) == 1 def test_abort_invalid(self): """ Test invalid states for transaction ABORT. """ self._connect() self.engine.process_frame(Frame('ABORT', headers={'transaction': 'abc'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') self.engine.process_frame(Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame(Frame('ABORT', headers={'transaction': 'abc'})) self.engine.process_frame(Frame('ABORT', headers={'transaction': 'abc2'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction')