Changeset 99:2c8dc93fbef4


Ignore:
Timestamp:
Mar 7, 2011, 7:40:16 PM (10 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Message:

Fix race condition and nesting errors when adding a new subprotocol handler.

This fixes two related issues with adding a new subprotocol handler:

  • Adding a handler when the stream is not yet initialized (authenticated) does not cause connectionMade to be called.
  • Adding a handler in connectionMade, connectionInitialized, or connectionLost modifies the lists of handlers iterated over, causing some methods being called too often.

Author: ff, kandaurovoleg, ralphm.
Fixes: #48.

Location:
wokkel
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • wokkel/subprotocols.py

    r98 r99  
    186186        # get protocol handler up to speed when a connection has already
    187187        # been established
    188         if self.xmlstream and self._initialized:
     188        if self.xmlstream:
    189189            handler.makeConnection(self.xmlstream)
     190        if self._initialized:
    190191            handler.connectionInitialized()
    191192
     
    211212        self.xmlstream = xs
    212213
    213         for e in self:
     214        for e in list(self):
    214215            e.makeConnection(xs)
    215216
     
    230231        # Notify all child services which implement
    231232        # the IService interface
    232         for e in self:
     233        for e in list(self):
    233234            e.connectionInitialized()
    234235
     
    265266        # Notify all child services which implement
    266267        # the IService interface
    267         for e in self:
     268        for e in list(self):
    268269            e.connectionLost(reason)
    269270
  • wokkel/test/test_subprotocols.py

    r98 r99  
    287287
    288288
     289    def test_addHandlerConnected(self):
     290        """
     291        Adding a handler when connected doesn't call connectionInitialized.
     292        """
     293        sm = self.streamManager
     294        xs = xmlstream.XmlStream(xmlstream.Authenticator())
     295        sm._connected(xs)
     296        handler = DummyXMPPHandler()
     297        handler.setHandlerParent(sm)
     298
     299        self.assertEquals(1, handler.doneMade)
     300        self.assertEquals(0, handler.doneInitialized)
     301        self.assertEquals(0, handler.doneLost)
     302
     303
     304    def test_addHandlerConnectedNested(self):
     305        """
     306        Adding a handler in connectionMade doesn't cause 2nd call.
     307        """
     308        class NestingHandler(DummyXMPPHandler):
     309            nestedHandler = None
     310
     311            def connectionMade(self):
     312                DummyXMPPHandler.connectionMade(self)
     313                self.nestedHandler = DummyXMPPHandler()
     314                self.nestedHandler.setHandlerParent(self.parent)
     315
     316        sm = self.streamManager
     317        xs = xmlstream.XmlStream(xmlstream.Authenticator())
     318        handler = NestingHandler()
     319        handler.setHandlerParent(sm)
     320        sm._connected(xs)
     321
     322        self.assertEquals(1, handler.doneMade)
     323        self.assertEquals(0, handler.doneInitialized)
     324        self.assertEquals(0, handler.doneLost)
     325
     326        self.assertEquals(1, handler.nestedHandler.doneMade)
     327        self.assertEquals(0, handler.nestedHandler.doneInitialized)
     328        self.assertEquals(0, handler.nestedHandler.doneLost)
     329
     330
     331
    289332    def test_addHandlerInitialized(self):
    290333        """
     
    306349        self.assertEquals(1, handler.doneInitialized)
    307350        self.assertEquals(0, handler.doneLost)
     351
     352
     353    def test_addHandlerInitializedNested(self):
     354        """
     355        Adding a handler in connectionInitialized doesn't cause 2nd call.
     356        """
     357        class NestingHandler(DummyXMPPHandler):
     358            nestedHandler = None
     359
     360            def connectionInitialized(self):
     361                DummyXMPPHandler.connectionInitialized(self)
     362                self.nestedHandler = DummyXMPPHandler()
     363                self.nestedHandler.setHandlerParent(self.parent)
     364
     365        sm = self.streamManager
     366        xs = xmlstream.XmlStream(xmlstream.Authenticator())
     367        handler = NestingHandler()
     368        handler.setHandlerParent(sm)
     369        sm._connected(xs)
     370        sm._authd(xs)
     371
     372        self.assertEquals(1, handler.doneMade)
     373        self.assertEquals(1, handler.doneInitialized)
     374        self.assertEquals(0, handler.doneLost)
     375
     376        self.assertEquals(1, handler.nestedHandler.doneMade)
     377        self.assertEquals(1, handler.nestedHandler.doneInitialized)
     378        self.assertEquals(0, handler.nestedHandler.doneLost)
     379
     380
     381    def test_addHandlerConnectionLostNested(self):
     382        """
     383        Adding a handler in connectionLost doesn't call connectionLost there.
     384        """
     385        class NestingHandler(DummyXMPPHandler):
     386            nestedHandler = None
     387
     388            def connectionLost(self, reason):
     389                DummyXMPPHandler.connectionLost(self, reason)
     390                self.nestedHandler = DummyXMPPHandler()
     391                self.nestedHandler.setHandlerParent(self.parent)
     392
     393        sm = self.streamManager
     394        xs = xmlstream.XmlStream(xmlstream.Authenticator())
     395        handler = NestingHandler()
     396        handler.setHandlerParent(sm)
     397        sm._connected(xs)
     398        sm._authd(xs)
     399        sm._disconnected(xs)
     400
     401        self.assertEquals(1, handler.doneMade)
     402        self.assertEquals(1, handler.doneInitialized)
     403        self.assertEquals(1, handler.doneLost)
     404
     405        self.assertEquals(0, handler.nestedHandler.doneMade)
     406        self.assertEquals(0, handler.nestedHandler.doneInitialized)
     407        self.assertEquals(0, handler.nestedHandler.doneLost)
     408
    308409
    309410    def test_removeHandler(self):
Note: See TracChangeset for help on using the changeset viewer.