Ticket #3407: xmpp-router.patch
| File xmpp-router.patch, 44.3 KB (added by ralphm, 5 years ago) |
|---|
-
twisted/plugins/twisted_words.py
diff -r 32bd907eefae -r e255d835eef1 twisted/plugins/twisted_words.py
a b 20 20 "A modern words server", 21 21 "words") 22 22 23 TwistedXMPPRouter = ServiceMaker( 24 "XMPP Router", 25 "twisted.words.xmpproutertap", 26 "An XMPP Router server", 27 "xmpp-router") 28 23 29 class RelayChatInterface(object): 24 30 classProvides(IPlugin, iwords.IProtocolPlugin) 25 31 -
twisted/words/protocols/jabber/client.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/protocols/jabber/client.py
a b 1 1 # -*- test-case-name: twisted.words.test.test_jabberclient -*- 2 2 # 3 # Copyright (c) 2001-200 5Twisted Matrix Laboratories.3 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. 4 4 # See LICENSE for details. 5 5 6 6 from twisted.internet import defer … … 17 17 PlaintextAuthQry = xpath.internQuery("/iq/query/password") 18 18 19 19 def basicClientFactory(jid, secret): 20 a = BasicAuthenticator(jid, secret) 21 return xmlstream.XmlStreamFactory(a) 20 return xmlstream.XmlStreamFactory(BasicAuthenticator, jid, secret) 22 21 23 22 class IQ(domish.Element): 24 23 """ … … 298 297 @return: XML stream factory. 299 298 @rtype: L{xmlstream.XmlStreamFactory} 300 299 """ 301 a = XMPPAuthenticator(jid, password) 302 return xmlstream.XmlStreamFactory(a) 300 return xmlstream.XmlStreamFactory(XMPPAuthenticator, jid, password) 303 301 304 302 305 303 … … 339 337 340 338 namespace = 'jabber:client' 341 339 342 def __init__(self, jid, password):343 xmlstream.ConnectAuthenticator.__init__(self, jid.host)340 def __init__(self, xs, jid, password): 341 xmlstream.ConnectAuthenticator.__init__(self, xs, jid.host) 344 342 self.jid = jid 345 343 self.password = password 346 347 348 def associateWithStream(self, xs):349 """350 Register with the XML stream.351 352 Populates stream's list of initializers, along with their353 requiredness. This list is used by354 L{ConnectAuthenticator.initializeStream} to perform the initalization355 steps.356 """357 xmlstream.ConnectAuthenticator.associateWithStream(self, xs)358 344 359 345 xs.initializers = [CheckVersionInitializer(xs)] 360 346 inits = [ (xmlstream.TLSInitiatingInitializer, False), -
twisted/words/protocols/jabber/component.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/protocols/jabber/component.py
a b 1 1 # -*- test-case-name: twisted.words.test.test_jabbercomponent -*- 2 2 # 3 # Copyright (c) 2001-200 7Twisted Matrix Laboratories.3 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. 4 4 # See LICENSE for details. 5 5 6 6 """ … … 21 21 from zope.interface import implements 22 22 23 23 from twisted.application import service 24 from twisted.internet import defer 24 from twisted.internet import defer, reactor 25 from twisted.python import log 25 26 from twisted.words.xish import domish 26 from twisted.words.protocols.jabber import ijabber, jstrports, xmlstream 27 from twisted.words.protocols.jabber import error, ijabber, jstrports, xmlstream 28 from twisted.words.protocols.jabber.jid import internJID as JID 29 30 NS_COMPONENT_ACCEPT = 'jabber:component:accept' 27 31 28 32 def componentFactory(componentid, password): 29 33 """ … … 34 38 @param password: password used to authenticate to the server. 35 39 @type password: L{str} 36 40 """ 37 a = ConnectComponentAuthenticator(componentid, password) 38 return xmlstream.XmlStreamFactory(a) 41 return xmlstream.XmlStreamFactory(ConnectComponentAuthenticator, 42 componentid, password) 43 44 39 45 40 46 class ComponentInitiatingInitializer(object): 41 47 """ … … 68 74 self.xmlstream.thisEntity = self.xmlstream.otherEntity 69 75 self._deferred.callback(None) 70 76 77 78 71 79 class ConnectComponentAuthenticator(xmlstream.ConnectAuthenticator): 72 80 """ 73 81 Authenticator to permit an XmlStream to authenticate against a Jabber 74 82 server as an external component (where the Authenticator is initiating the 75 83 stream). 76 84 """ 77 namespace = 'jabber:component:accept'85 namespace = NS_COMPONENT_ACCEPT 78 86 79 def __init__(self, componentjid, password):87 def __init__(self, xs, componentjid, password): 80 88 """ 81 89 @type componentjid: L{str} 82 90 @param componentjid: Jabber ID that this component wishes to bind to. … … 85 93 @param password: Password/secret this component uses to authenticate. 86 94 """ 87 95 # Note that we are sending 'to' our desired component JID. 88 xmlstream.ConnectAuthenticator.__init__(self, componentjid) 96 xs.version = (0, 0) 97 xmlstream.ConnectAuthenticator.__init__(self, xs, componentjid) 98 xs.initializers = [ComponentInitiatingInitializer(xs)] 89 99 self.password = password 90 100 91 def associateWithStream(self, xs): 101 102 103 class ListenComponentAuthenticator(xmlstream.ListenAuthenticator): 104 """ 105 Authenticator for accepting components. 106 """ 107 namespace = NS_COMPONENT_ACCEPT 108 109 def __init__(self, xs, secret): 92 110 xs.version = (0, 0) 93 xmlstream.ConnectAuthenticator.associateWithStream(self, xs) 111 self.secret = secret 112 xmlstream.ListenAuthenticator.__init__(self, xs) 94 113 95 xs.initializers = [ComponentInitiatingInitializer(xs)]96 114 97 class ListenComponentAuthenticator(xmlstream.Authenticator): 98 """ 99 Placeholder for listening components. 100 """ 115 def streamStarted(self, rootElement): 116 xmlstream.ListenAuthenticator.streamStarted(self, rootElement) 117 118 if rootElement.defaultUri != self.namespace: 119 exc = error.StreamError('invalid-namespace') 120 self.xmlstream.sendStreamError(exc) 121 return 122 123 # self.xmlstream.thisEntity is set to the address the component 124 # wants to assume. This should probably be checked. 125 if not self.xmlstream.thisEntity: 126 exc = error.StreamError('improper-addressing') 127 self.xmlstream.sendStreamError(exc) 128 return 129 130 self.xmlstream.sid = 'random' # FIXME 131 132 self.xmlstream.sendHeader() 133 self.xmlstream.addOnetimeObserver('/*', self.onElement) 134 135 136 def onElement(self, element): 137 if (element.uri, element.name) == (self.namespace, 'handshake'): 138 self.onHandshake(unicode(element)) 139 else: 140 exc = error.streamError('not-authorized') 141 self.xmlstream.sendStreamError(exc) 142 143 144 def onHandshake(self, handshake): 145 calculatedHash = xmlstream.hashPassword(self.xmlstream.sid, self.secret) 146 if handshake != calculatedHash: 147 exc = error.StreamError('not-authorized', text='Invalid hash') 148 self.xmlstream.sendStreamError(exc) 149 else: 150 self.xmlstream.send('<handshake/>') 151 self.xmlstream.dispatch(self.xmlstream, 152 xmlstream.STREAM_AUTHD_EVENT) 153 154 101 155 102 156 class Service(service.Service): 103 157 """ … … 227 281 client_svc = jstrports.client(strport, svc.getFactory()) 228 282 client_svc.setServiceParent(svc) 229 283 return svc 284 285 286 287 class RouterService(service.Service): 288 """ 289 XMPP Server's Router Service. 290 291 This service connects the different components of the XMPP service and 292 routes messages between them based on the given routing table. 293 294 Connected components are trusted to have correct addressing in the 295 stanzas they offer for routing. 296 297 A route destination of C{None} adds a default route. Traffic for which no 298 specific route exists, will be routed to this default route. 299 300 @ivar routes: Routes based on the host part of JIDs. Maps host names to the 301 L{EventDispatcher<utility.EventDispatcher>}s that should 302 receive the traffic. A key of C{None} means the default 303 route. 304 @type routes: C{dict} 305 """ 306 307 def __init__(self): 308 self.routes = {} 309 310 311 def addRoute(self, destination, xs): 312 """ 313 Add a new route. 314 315 The passed XML Stream C{xs} will have an observer for all stanzas 316 added to route its outgoing traffic. In turn, traffic for 317 C{destination} will be passed to this stream. 318 319 @param destination: Destination of the route to be added as a host name 320 or C{None} for the default route. 321 @type destination: C{str} or C{NoneType}. 322 @param xs: XML Stream to register the route for. 323 @type xs: L{EventDispatcher<utility.EventDispatcher>}. 324 """ 325 self.routes[destination] = xs 326 xs.addObserver('/*', self.route) 327 328 329 def removeRoute(self, destination, xs): 330 """ 331 Remove a route. 332 333 @param destination: Destination of the route that should be removed. 334 @type destination: C{str}. 335 @param xs: XML Stream to remove the route for. 336 @type xs: L{EventDispatcher<utility.EventDispatcher>}. 337 """ 338 xs.removeObserver('/*', self.route) 339 if (xs == self.routes[destination]): 340 del self.routes[destination] 341 342 343 def route(self, stanza): 344 """ 345 Route a stanza. 346 347 @param stanza: The stanza to be routed. 348 @type stanza: L{domish.Element}. 349 """ 350 if not list(stanza.elements()): 351 return 352 353 destination = JID(stanza['to']) 354 355 log.msg("Routing to %s: %r" % (destination.full(), stanza.toXml())) 356 357 if destination.host in self.routes: 358 self.routes[destination.host].send(stanza) 359 else: 360 self.routes[None].send(stanza) 361 362 363 364 class ComponentServer(service.Service): 365 """ 366 XMPP Component Server service. 367 368 This service accepts XMPP external component connections and makes 369 the router service route traffic for a component's bound domain 370 to that component. 371 """ 372 373 logTraffic = False 374 375 def __init__(self, router, port=5347, secret='secret'): 376 self.router = router 377 self.port = port 378 self.secret = secret 379 380 self.factory = xmlstream.XmlStreamServerFactory( 381 ListenComponentAuthenticator, self.secret) 382 self.factory.addBootstrap(xmlstream.STREAM_CONNECTED_EVENT, 383 self.makeConnection) 384 self.factory.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, 385 self.connectionInitialized) 386 387 self.serial = 0 388 389 390 def startService(self): 391 service.Service.startService(self) 392 reactor.listenTCP(self.port, self.factory) 393 394 395 def makeConnection(self, xs): 396 """ 397 Called when a component connection was made. 398 399 This enables traffic debugging on incoming streams. 400 """ 401 xs.serial = self.serial 402 self.serial += 1 403 404 def logDataIn(buf): 405 log.msg("RECV (%d): %r" % (xs.serial, buf)) 406 407 def logDataOut(buf): 408 log.msg("SEND (%d): %r" % (xs.serial, buf)) 409 410 if self.logTraffic: 411 xs.rawDataInFn = logDataIn 412 xs.rawDataOutFn = logDataOut 413 414 xs.addObserver(xmlstream.STREAM_ERROR_EVENT, self.onError) 415 416 417 def connectionInitialized(self, xs): 418 """ 419 Called when a component has succesfully authenticated. 420 421 Add the component to the routing table and establish a handler 422 for a closed connection. 423 """ 424 destination = xs.thisEntity.host 425 426 self.router.addRoute(destination, xs) 427 xs.addObserver(xmlstream.STREAM_END_EVENT, self.connectionLost, 0, 428 destination, xs) 429 430 431 def onError(self, reason): 432 log.err(reason, "Stream Error") 433 434 435 def connectionLost(self, destination, xs, reason): 436 self.router.removeRoute(destination, xs) -
twisted/words/protocols/jabber/xmlstream.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/protocols/jabber/xmlstream.py
a b 13 13 14 14 from zope.interface import directlyProvides, implements 15 15 16 from twisted.internet import defer 16 from twisted.internet import defer, protocol 17 17 from twisted.internet.error import ConnectionLost 18 18 from twisted.python import failure, log 19 19 from twisted.words.protocols.jabber import error, ijabber, jid … … 57 57 Rules: 58 58 1. The Authenticator MUST dispatch a L{STREAM_AUTHD_EVENT} when the 59 59 stream has been completely initialized. 60 2. The Authenticator SHOULD reset all state information when 61 L{associateWithStream} is called. 62 3. The Authenticator SHOULD override L{streamStarted}, and start 60 2. The Authenticator SHOULD override L{streamStarted}, and start 63 61 initialization there. 64 62 65 63 @type xmlstream: L{XmlStream} … … 70 68 of XML stanzas. 71 69 """ 72 70 73 def __init__(self ):74 self.xmlstream = None71 def __init__(self, xs): 72 self.xmlstream = xs 75 73 76 74 77 75 def connectionMade(self): … … 116 114 self.xmlstream.version = min(self.xmlstream.version, version) 117 115 118 116 119 def associateWithStream(self, xmlstream):120 """121 Called by the XmlStreamFactory when a connection has been made122 to the requested peer, and an XmlStream object has been123 instantiated.124 125 The default implementation just saves a handle to the new126 XmlStream.127 128 @type xmlstream: L{XmlStream}129 @param xmlstream: The XmlStream that will be passing events to this130 Authenticator.131 132 """133 self.xmlstream = xmlstream134 135 136 117 137 118 class ConnectAuthenticator(Authenticator): 138 119 """ … … 141 122 142 123 namespace = None 143 124 144 def __init__(self, otherHost): 125 def __init__(self, xs, otherHost): 126 Authenticator.__init__(self, xs) 145 127 self.otherHost = otherHost 146 128 147 129 … … 240 222 241 223 namespace = None 242 224 243 def associateWithStream(self, xmlstream): 244 """ 245 Called by the XmlStreamFactory when a connection has been made. 246 247 Extend L{Authenticator.associateWithStream} to set the L{XmlStream} 248 to be non-initiating. 249 """ 250 Authenticator.associateWithStream(self, xmlstream) 251 self.xmlstream.initiating = False 225 def __init__(self, xs): 226 xs.initiating = False 227 Authenticator.__init__(self, xs) 252 228 253 229 254 230 def streamStarted(self, rootElement): … … 475 451 476 452 _headerSent = False # True if the stream header has been sent 477 453 478 def __init__(self, authenticator ):454 def __init__(self, authenticatorClass, *args, **kwargs): 479 455 xmlstream.XmlStream.__init__(self) 480 456 481 457 self.prefixes = {NS_STREAMS: 'stream'} 482 self.authenticator = authenticator483 458 self.initializers = [] 484 459 self.features = {} 485 486 # Reset the authenticator 487 authenticator.associateWithStream(self) 460 self.authenticator = authenticatorClass(self, *args, **kwargs) 488 461 489 462 490 463 def _callLater(self, *args, **kwargs): … … 639 612 class XmlStreamFactory(xmlstream.XmlStreamFactory): 640 613 """ 641 614 Factory for Jabber XmlStream objects as a reconnecting client. 642 643 Note that this differs from L{xmlstream.XmlStreamFactory} in that644 it generates Jabber specific L{XmlStream} instances that have645 authenticators.646 615 """ 647 616 648 617 protocol = XmlStream 649 618 650 def __init__(self, authenticator): 651 xmlstream.XmlStreamFactory.__init__(self, authenticator) 652 self.authenticator = authenticator 619 620 621 class XmlStreamServerFactory(xmlstream.XmlStreamFactoryMixin, 622 protocol.ServerFactory): 623 """ 624 Factory for Jabber XmlStream objects as a server. 625 """ 626 627 protocol = XmlStream 653 628 654 629 655 630 -
twisted/words/test/test_jabberclient.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/test/test_jabberclient.py
a b 1 # Copyright (c) 2001-200 7Twisted Matrix Laboratories.1 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. 2 2 # See LICENSE for details. 3 3 4 4 """ … … 12 12 13 13 class CheckVersionInitializerTest(unittest.TestCase): 14 14 def setUp(self): 15 a = xmlstream.Authenticator() 16 xs = xmlstream.XmlStream(a) 15 xs = xmlstream.XmlStream(xmlstream.Authenticator) 17 16 self.init = client.CheckVersionInitializer(xs) 18 17 19 18 def testSupported(self): … … 35 34 class InitiatingInitializerHarness(object): 36 35 def setUp(self): 37 36 self.output = [] 38 self. authenticator = xmlstream.ConnectAuthenticator('example.org')39 self.xmlstream = xmlstream.XmlStream(self.authenticator)37 self.xmlstream = xmlstream.XmlStream(xmlstream.ConnectAuthenticator, 38 'example.org') 40 39 self.xmlstream.send = self.output.append 41 40 self.xmlstream.connectionMade() 42 41 self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' " … … 48 47 def setUp(self): 49 48 super(IQAuthInitializerTest, self).setUp() 50 49 self.init = client.IQAuthInitializer(self.xmlstream) 51 self. authenticator.jid = jid.JID('user@example.com/resource')52 self. authenticator.password = 'secret'50 self.xmlstream.authenticator.jid = jid.JID('user@example.com/resource') 51 self.xmlstream.authenticator.password = 'secret' 53 52 54 53 def testBasic(self): 55 54 """ … … 158 157 def setUp(self): 159 158 super(BindInitializerTest, self).setUp() 160 159 self.init = client.BindInitializer(self.xmlstream) 161 self. authenticator.jid = jid.JID('user@example.com/resource')160 self.xmlstream.authenticator.jid = jid.JID('user@example.com/resource') 162 161 163 162 def testBasic(self): 164 163 """ … … 168 167 """ 169 168 def cb(result): 170 169 self.assertEquals(jid.JID('user@example.com/other resource'), 171 self. authenticator.jid)170 self.xmlstream.authenticator.jid) 172 171 173 172 d = self.init.start().addCallback(cb) 174 173 iq = self.output[-1] -
twisted/words/test/test_jabbercomponent.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/test/test_jabbercomponent.py
a b 1 # Copyright (c) 2001-200 7Twisted Matrix Laboratories.1 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. 2 2 # See LICENSE for details. 3 3 4 4 """ … … 6 6 """ 7 7 8 8 import sha 9 10 from twisted.python import failure 11 from twisted.test import proto_helpers 9 12 from twisted.trial import unittest 10 11 from twisted.words.protocols.jabber import component12 from twisted.words. protocols import jabber13 from twisted.words. protocols.jabber import xmlstream13 from twisted.words.protocols.jabber import component, xmlstream 14 from twisted.words.protocols.jabber.jid import JID 15 from twisted.words.xish import domish 16 from twisted.words.xish.utility import XmlPipe 14 17 15 18 class DummyTransport: 16 19 def __init__(self, list): … … 23 26 def setUp(self): 24 27 self.output = [] 25 28 26 self.authenticator = xmlstream.Authenticator() 27 self.authenticator.password = 'secret' 28 self.xmlstream = xmlstream.XmlStream(self.authenticator) 29 self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator) 30 self.xmlstream.authenticator.password = 'secret' 29 31 self.xmlstream.namespace = 'test:component' 30 32 self.xmlstream.send = self.output.append 31 33 self.xmlstream.connectionMade() … … 66 68 self.authComplete = False 67 69 outlist = [] 68 70 69 ca = component.ConnectComponentAuthenticator("cjid", "secret")70 xs = xmlstream.XmlStream(ca)71 xs = xmlstream.XmlStream(component.ConnectComponentAuthenticator, 72 "cjid", "secret") 71 73 xs.transport = DummyTransport(outlist) 72 74 73 75 xs.addObserver(xmlstream.STREAM_AUTHD_EVENT, … … 87 89 self.assertEquals(self.authComplete, True) 88 90 89 91 90 class JabberServiceHarness( jabber.component.Service):92 class JabberServiceHarness(component.Service): 91 93 def __init__(self): 92 94 self.componentConnectedFlag = False 93 95 self.componentDisconnectedFlag = False … … 106 108 class TestJabberServiceManager(unittest.TestCase): 107 109 def testSM(self): 108 110 # Setup service manager and test harnes 109 sm = jabber.component.ServiceManager("foo", "password")111 sm = component.ServiceManager("foo", "password") 110 112 svc = JabberServiceHarness() 111 113 svc.setServiceParent(sm) 112 114 … … 135 137 136 138 # Ensure the test service harness got notified 137 139 self.assertEquals(True, svc.componentDisconnectedFlag) 140 141 142 143 class RouterServiceTest(unittest.TestCase): 144 """ 145 Tests for L{component.RouterService}. 146 """ 147 148 def test_addRoute(self): 149 """ 150 Test route registration and routing on incoming stanzas. 151 """ 152 router = component.RouterService() 153 routed = [] 154 router.route = lambda element: routed.append(element) 155 156 pipe = XmlPipe() 157 router.addRoute('example.org', pipe.sink) 158 self.assertEquals(1, len(router.routes)) 159 self.assertEquals(pipe.sink, router.routes['example.org']) 160 161 element = domish.Element(('testns', 'test')) 162 pipe.source.send(element) 163 self.assertEquals([element], routed) 164 165 166 def test_route(self): 167 """ 168 Test routing of a message. 169 """ 170 component1 = XmlPipe() 171 component2 = XmlPipe() 172 router = component.RouterService() 173 router.addRoute('component1.example.org', component1.sink) 174 router.addRoute('component2.example.org', component2.sink) 175 176 outgoing = [] 177 component2.source.addObserver('/*', 178 lambda element: outgoing.append(element)) 179 stanza = domish.Element((None, 'route')) 180 stanza['from'] = 'component1.example.org' 181 stanza['to'] = 'component2.example.org' 182 stanza.addElement('presence') 183 component1.source.send(stanza) 184 self.assertEquals([stanza], outgoing) 185 186 187 def test_routeDefault(self): 188 """ 189 Test routing of a message using the default route. 190 191 The default route is the one with C{None} as its key in the 192 routing table. It is taken when there is no more specific route 193 in the routing table that matches the stanza's destination. 194 """ 195 component1 = XmlPipe() 196 s2s = XmlPipe() 197 router = component.RouterService() 198 router.addRoute('component1.example.org', component1.sink) 199 router.addRoute(None, s2s.sink) 200 201 outgoing = [] 202 s2s.source.addObserver('/*', lambda element: outgoing.append(element)) 203 stanza = domish.Element((None, 'route')) 204 stanza['from'] = 'component1.example.org' 205 stanza['to'] = 'example.com' 206 stanza.addElement('presence') 207 component1.source.send(stanza) 208 self.assertEquals([stanza], outgoing) 209 210 211 212 class ListenComponentAuthenticatorTest(unittest.TestCase): 213 """ 214 Tests for L{component.ListenComponentAuthenticator}. 215 """ 216 217 def setUp(self): 218 self.output = [] 219 authenticator = component.ListenComponentAuthenticator 220 self.xmlstream = xmlstream.XmlStream(authenticator, 'secret') 221 self.xmlstream.send = self.output.append 222 223 224 def loseConnection(self): 225 """ 226 Stub loseConnection because we are a transport. 227 """ 228 self.xmlstream.connectionLost("no reason") 229 230 231 def test_streamStarted(self): 232 observers = [] 233 234 def addOnetimeObserver(event, observerfn): 235 observers.append((event, observerfn)) 236 237 xs = self.xmlstream 238 xs.addOnetimeObserver = addOnetimeObserver 239 240 xs.makeConnection(self) 241 self.assertIdentical(None, xs.sid) 242 self.assertFalse(xs._headerSent) 243 244 xs.dataReceived("<stream:stream xmlns='jabber:component:accept' " 245 "xmlns:stream='http://etherx.jabber.org/streams' " 246 "to='component.example.org'>") 247 self.assertEqual((0, 0), xs.version) 248 self.assertNotIdentical(None, xs.sid) 249 self.assertTrue(xs._headerSent) 250 self.assertEquals(('/*', xs.authenticator.onElement), observers[-1]) 251 252 253 def test_streamStartedWrongNamespace(self): 254 """ 255 The received stream header should have a correct namespace. 256 """ 257 streamErrors = [] 258 259 xs = self.xmlstream 260 xs.sendStreamError = streamErrors.append 261 xs.makeConnection(self) 262 xs.dataReceived("<stream:stream xmlns='jabber:client' " 263 "xmlns:stream='http://etherx.jabber.org/streams' " 264 "to='component.example.org'>") 265 self.assertEquals(1, len(streamErrors)) 266 self.assertEquals('invalid-namespace', streamErrors[-1].condition) 267 268 269 def test_streamStartedNoTo(self): 270 streamErrors = [] 271 272 xs = self.xmlstream 273 xs.sendStreamError = streamErrors.append 274 xs.makeConnection(self) 275 xs.dataReceived("<stream:stream xmlns='jabber:component:accept' " 276 "xmlns:stream='http://etherx.jabber.org/streams'>") 277 self.assertEquals(1, len(streamErrors)) 278 self.assertEquals('improper-addressing', streamErrors[-1].condition) 279 280 281 def test_onElement(self): 282 """ 283 We expect a handshake element with a hash. 284 """ 285 handshakes = [] 286 287 xs = self.xmlstream 288 xs.authenticator.onHandshake = handshakes.append 289 290 handshake = domish.Element(('jabber:component:accept', 'handshake')) 291 handshake.addContent('1234') 292 xs.authenticator.onElement(handshake) 293 self.assertEqual('1234', handshakes[-1]) 294 295 def test_onHandshake(self): 296 xs = self.xmlstream 297 xs.sid = '1234' 298 theHash = '32532c0f7dbf1253c095b18b18e36d38d94c1256' 299 xs.authenticator.onHandshake(theHash) 300 self.assertEqual('<handshake/>', self.output[-1]) 301 302 303 def test_onHandshakeWrongHash(self): 304 streamErrors = [] 305 authd = [] 306 307 def authenticated(self, xs): 308 authd.append(xs) 309 310 xs = self.xmlstream 311 xs.addOnetimeObserver(xmlstream.STREAM_AUTHD_EVENT, authenticated) 312 xs.sendStreamError = streamErrors.append 313 314 xs.sid = '1234' 315 theHash = '1234' 316 xs.authenticator.onHandshake(theHash) 317 self.assertEquals('not-authorized', streamErrors[-1].condition) 318 self.assertEquals(0, len(authd)) 319 320 321 322 class ComponentServerTest(unittest.TestCase): 323 """ 324 Tests for L{component.ComponentServer}. 325 """ 326 327 def setUp(self): 328 self.router = component.RouterService() 329 self.server = component.ComponentServer(self.router) 330 self.xmlstream = self.server.factory.buildProtocol(None) 331 self.xmlstream.thisEntity = JID('component.example.org') 332 333 334 def test_makeConnection(self): 335 """ 336 A new connection increases the stream serial count. No logs by default. 337 """ 338 self.xmlstream.dispatch(self.xmlstream, 339 xmlstream.STREAM_CONNECTED_EVENT) 340 self.assertEqual(0, self.xmlstream.serial) 341 self.assertEqual(1, self.server.serial) 342 self.assertIdentical(None, self.xmlstream.rawDataInFn) 343 self.assertIdentical(None, self.xmlstream.rawDataOutFn) 344 345 346 def test_makeConnectionLogTraffic(self): 347 """ 348 Setting logTraffic should set up raw data loggers. 349 """ 350 self.server.logTraffic = True 351 self.xmlstream.dispatch(self.xmlstream, 352 xmlstream.STREAM_CONNECTED_EVENT) 353 self.assertNotIdentical(None, self.xmlstream.rawDataInFn) 354 self.assertNotIdentical(None, self.xmlstream.rawDataOutFn) 355 356 357 def test_onError(self): 358 """ 359 An observer for stream errors should trigger onError to log it. 360 """ 361 self.xmlstream.dispatch(self.xmlstream, 362 xmlstream.STREAM_CONNECTED_EVENT) 363 364 class TestError(Exception): 365 pass 366 367 reason = failure.Failure(TestError()) 368 self.xmlstream.dispatch(reason, xmlstream.STREAM_ERROR_EVENT) 369 self.assertEqual(1, len(self.flushLoggedErrors(TestError))) 370 371 372 def test_connectionInitialized(self): 373 """ 374 Make sure a new stream is added to the routing table. 375 """ 376 self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT) 377 self.assertIn('component.example.org', self.router.routes) 378 self.assertIdentical(self.xmlstream, 379 self.router.routes['component.example.org']) 380 381 382 def test_connectionLost(self): 383 """ 384 Make sure a stream is removed from the routing table on disconnect. 385 """ 386 self.xmlstream.dispatch(self.xmlstream, xmlstream.STREAM_AUTHD_EVENT) 387 self.xmlstream.dispatch(None, xmlstream.STREAM_END_EVENT) 388 self.assertNotIn('component.example.org', self.router.routes) -
twisted/words/test/test_jabbersasl.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/test/test_jabbersasl.py
a b 1 # Copyright (c) 2001-200 7Twisted Matrix Laboratories.1 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. 2 2 # See LICENSE for details. 3 3 4 4 from zope.interface import implements … … 60 60 def setUp(self): 61 61 self.output = [] 62 62 63 self.authenticator = xmlstream.Authenticator() 64 self.xmlstream = xmlstream.XmlStream(self.authenticator) 63 self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator) 65 64 self.xmlstream.send = self.output.append 66 65 self.xmlstream.connectionMade() 67 66 self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' " -
twisted/words/test/test_jabberxmlstream.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/test/test_jabberxmlstream.py
a b 27 27 """ 28 28 29 29 def setUp(self): 30 authenticator = xmlstream.ConnectAuthenticator('otherhost') 31 authenticator.namespace = 'testns' 32 self.xmlstream = xmlstream.XmlStream(authenticator) 30 self.xmlstream = xmlstream.XmlStream(xmlstream.ConnectAuthenticator, 31 'otherhost') 33 32 self.clock = task.Clock() 33 self.xmlstream.authenticator.namespace = 'testns' 34 34 self.xmlstream._callLater = self.clock.callLater 35 35 self.xmlstream.makeConnection(proto_helpers.StringTransport()) 36 36 self.xmlstream.dataReceived( … … 206 206 self.gotStreamStart = False 207 207 self.gotStreamEnd = False 208 208 self.gotStreamError = False 209 xs = xmlstream.XmlStream(xmlstream.Authenticator ())209 xs = xmlstream.XmlStream(xmlstream.Authenticator) 210 210 xs.addObserver('//event/stream/start', self.onStreamStart) 211 211 xs.addObserver('//event/stream/end', self.onStreamEnd) 212 212 xs.addObserver('//event/stream/error', self.onStreamError) … … 395 395 streamStartedCalls = [] 396 396 associateWithStreamCalls = [] 397 397 398 class TestAuthenticator :398 class TestAuthenticator(xmlstream.Authenticator): 399 399 def connectionMade(self): 400 400 connectionMadeCalls.append(None) 401 401 402 402 def streamStarted(self, rootElement): 403 403 streamStartedCalls.append(rootElement) 404 404 405 def associateWithStream(self, xs): 406 associateWithStreamCalls.append(xs) 407 408 a = TestAuthenticator() 409 xs = xmlstream.XmlStream(a) 410 self.assertEqual([xs], associateWithStreamCalls) 405 xs = xmlstream.XmlStream(TestAuthenticator) 411 406 xs.connectionMade() 412 407 self.assertEqual([None], connectionMadeCalls) 413 408 xs.dataReceived("<stream:stream xmlns='jabber:client' " … … 426 421 427 422 class AuthenticatorTest(unittest.TestCase): 428 423 def setUp(self): 429 self.authenticator = xmlstream.ListenAuthenticator() 430 self.xmlstream = xmlstream.XmlStream(self.authenticator) 424 self.xmlstream = xmlstream.XmlStream(xmlstream.ListenAuthenticator) 431 425 432 426 433 427 def test_streamStart(self): … … 493 487 def setUp(self): 494 488 self.gotAuthenticated = False 495 489 self.initFailure = None 496 self. authenticator = xmlstream.ConnectAuthenticator('otherHost')497 self.xmlstream = xmlstream.XmlStream(self.authenticator)490 self.xmlstream = xmlstream.XmlStream(xmlstream.ConnectAuthenticator, 491 'otherHost') 498 492 self.xmlstream.addObserver('//event/stream/authd', self.onAuthenticated) 499 493 self.xmlstream.addObserver('//event/xmpp/initfailed', self.onInitFailed) 500 494 … … 518 512 init = Initializer() 519 513 self.xmlstream.initializers = [init] 520 514 521 self. authenticator.initializeStream()515 self.xmlstream.authenticator.initializeStream() 522 516 self.assertEqual([], self.xmlstream.initializers) 523 517 self.assertTrue(self.gotAuthenticated) 524 518 … … 534 528 init = Initializer() 535 529 self.xmlstream.initializers = [init] 536 530 537 self. authenticator.initializeStream()531 self.xmlstream.authenticator.initializeStream() 538 532 self.assertEqual([init], self.xmlstream.initializers) 539 533 self.assertFalse(self.gotAuthenticated) 540 534 self.assertNotIdentical(None, self.initFailure) … … 546 540 Test streamStart to fill the appropriate attributes from the 547 541 stream header. 548 542 """ 549 self. authenticator.namespace = 'testns'543 self.xmlstream.authenticator.namespace = 'testns' 550 544 xs = self.xmlstream 551 545 xs.makeConnection(proto_helpers.StringTransport()) 552 546 xs.dataReceived("<stream:stream xmlns='jabber:client' " … … 569 563 570 564 class ListenAuthenticatorTest(unittest.TestCase): 571 565 def setUp(self): 572 self.authenticator = xmlstream.ListenAuthenticator() 573 self.xmlstream = xmlstream.XmlStream(self.authenticator) 566 self.xmlstream = xmlstream.XmlStream(xmlstream.ListenAuthenticator) 574 567 575 568 576 569 def test_streamStart(self): … … 599 592 600 593 self.savedSSL = xmlstream.ssl 601 594 602 self.authenticator = xmlstream.Authenticator() 603 self.xmlstream = xmlstream.XmlStream(self.authenticator) 595 self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator) 604 596 self.xmlstream.send = self.output.append 605 597 self.xmlstream.connectionMade() 606 598 self.xmlstream.dataReceived("<stream:stream xmlns='jabber:client' " … … 720 712 class BaseFeatureInitiatingInitializerTest(unittest.TestCase): 721 713 722 714 def setUp(self): 723 self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator ())715 self.xmlstream = xmlstream.XmlStream(xmlstream.Authenticator) 724 716 self.init = TestFeatureInitializer(self.xmlstream) 725 717 726 718 … … 894 886 self.doneMade = True 895 887 896 888 handler = TestXMPPHandler() 897 xs = xmlstream.XmlStream(xmlstream.Authenticator ())889 xs = xmlstream.XmlStream(xmlstream.Authenticator) 898 890 handler.makeConnection(xs) 899 891 self.assertTrue(handler.doneMade) 900 892 self.assertIdentical(xs, handler.xmlstream) … … 905 897 Test that connectionLost forgets the XML stream. 906 898 """ 907 899 handler = xmlstream.XMPPHandler() 908 xs = xmlstream.XmlStream(xmlstream.Authenticator ())900 xs = xmlstream.XmlStream(xmlstream.Authenticator) 909 901 handler.makeConnection(xs) 910 902 handler.connectionLost(Exception()) 911 903 self.assertIdentical(None, handler.xmlstream) … … 985 977 sm = self.streamManager 986 978 handler = DummyXMPPHandler() 987 979 handler.setHandlerParent(sm) 988 xs = xmlstream.XmlStream(xmlstream.Authenticator ())980 xs = xmlstream.XmlStream(xmlstream.Authenticator) 989 981 sm._connected(xs) 990 982 self.assertEquals(1, handler.doneMade) 991 983 self.assertEquals(0, handler.doneInitialized) … … 999 991 sm = self.streamManager 1000 992 handler = DummyXMPPHandler() 1001 993 handler.setHandlerParent(sm) 1002 xs = xmlstream.XmlStream(xmlstream.Authenticator ())994 xs = xmlstream.XmlStream(xmlstream.Authenticator) 1003 995 sm._connected(xs) 1004 996 self.assertIdentical(None, xs.rawDataInFn) 1005 997 self.assertIdentical(None, xs.rawDataOutFn) … … 1013 1005 sm.logTraffic = True 1014 1006 handler = DummyXMPPHandler() 1015 1007 handler.setHandlerParent(sm) 1016 xs = xmlstream.XmlStream(xmlstream.Authenticator ())1008 xs = xmlstream.XmlStream(xmlstream.Authenticator) 1017 1009 sm._connected(xs) 1018 1010 self.assertNotIdentical(None, xs.rawDataInFn) 1019 1011 self.assertNotIdentical(None, xs.rawDataOutFn) … … 1027 1019 sm = self.streamManager 1028 1020 handler = DummyXMPPHandler() 1029 1021 handler.setHandlerParent(sm) 1030 xs = xmlstream.XmlStream(xmlstream.Authenticator ())1022 xs = xmlstream.XmlStream(xmlstream.Authenticator) 1031 1023 sm._authd(xs) 1032 1024 self.assertEquals(0, handler.doneMade) 1033 1025 self.assertEquals(1, handler.doneInitialized) … … 1042 1034 sm = self.streamManager 1043 1035 handler = DummyXMPPHandler() 1044 1036 handler.setHandlerParent(sm) 1045 xs = xmlstream.XmlStream(xmlstream.Authenticator ())1037 xs = xmlstream.XmlStream(xmlstream.Authenticator) 1046 1038 sm._disconnected(xs) 1047 1039 self.assertEquals(0, handler.doneMade) 1048 1040 self.assertEquals(0, handler.doneInitialized) … … 1072 1064 called. 1073 1065 """ 1074 1066 sm = self.streamManager 1075 xs = xmlstream.XmlStream(xmlstream.Authenticator ())1067 xs = xmlstream.XmlStream(xmlstream.Authenticator) 1076 1068 sm._connected(xs) 1077 1069 sm._authd(xs) 1078 1070 handler = DummyXMPPHandler() … … 1089 1081 1090 1082 The data should be sent directly over the XML stream. 1091 1083 """ 1092 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator ())1084 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator) 1093 1085 sm = xmlstream.StreamManager(factory) 1094 1086 xs = factory.buildProtocol(None) 1095 1087 xs.transport = proto_helpers.StringTransport() … … 1109 1101 The data should be cached until an XML stream has been established and 1110 1102 initialized. 1111 1103 """ 1112 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator ())1104 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator) 1113 1105 sm = xmlstream.StreamManager(factory) 1114 1106 handler = DummyXMPPHandler() 1115 1107 sm.addHandler(handler) … … 1139 1131 1140 1132 The data should be cached until the XML stream has been initialized. 1141 1133 """ 1142 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator ())1134 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator) 1143 1135 sm = xmlstream.StreamManager(factory) 1144 1136 xs = factory.buildProtocol(None) 1145 1137 xs.transport = proto_helpers.StringTransport() … … 1159 1151 The data should be cached until a new XML stream has been established 1160 1152 and initialized. 1161 1153 """ 1162 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator ())1154 factory = xmlstream.XmlStreamFactory(xmlstream.Authenticator) 1163 1155 sm = xmlstream.StreamManager(factory) 1164 1156 handler = DummyXMPPHandler() 1165 1157 sm.addHandler(handler) -
twisted/words/test/test_xmlstream.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/test/test_xmlstream.py
a b 1 # Copyright (c) 2001-200 7Twisted Matrix Laboratories.1 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. 2 2 # See LICENSE for details. 3 3 4 4 """ … … 7 7 8 8 from twisted.internet import defer, protocol 9 9 from twisted.trial import unittest 10 from twisted.words.xish import utility, xmlstream10 from twisted.words.xish import domish, utility, xmlstream 11 11 12 12 class XmlStreamTest(unittest.TestCase): 13 13 def setUp(self): 14 self.errorOccurred = False15 self.streamStarted = False16 self.streamEnded = False17 14 self.outlist = [] 18 15 self.xmlstream = xmlstream.XmlStream() 19 16 self.xmlstream.transport = self 20 17 self.xmlstream.transport.write = self.outlist.append 21 18 22 # Auxilary methods 19 23 20 def loseConnection(self): 21 """ 22 Stub loseConnection because we are a transport. 23 """ 24 24 self.xmlstream.connectionLost("no reason") 25 25 26 def streamStartEvent(self, rootelem):27 self.streamStarted = True28 26 29 def streamErrorEvent(self, errelem): 30 self.errorOccurred = True 31 32 def streamEndEvent(self, _): 33 self.streamEnded = True 34 35 def testBasicOp(self): 36 xs = self.xmlstream 37 xs.addObserver(xmlstream.STREAM_START_EVENT, 38 self.streamStartEvent) 39 xs.addObserver(xmlstream.STREAM_ERROR_EVENT, 40 self.streamErrorEvent) 41 xs.addObserver(xmlstream.STREAM_END_EVENT, 42 self.streamEndEvent) 43 44 # Go... 45 xs.connectionMade() 46 xs.send("<root>") 27 def test_send(self): 28 """ 29 Sending data should result into it being written to the transport. 30 """ 31 self.xmlstream.connectionMade() 32 self.xmlstream.send("<root>") 47 33 self.assertEquals(self.outlist[0], "<root>") 48 34 49 xs.dataReceived("<root>")50 self.assertEquals(self.streamStarted, True)51 35 52 self.assertEquals(self.errorOccurred, False) 53 self.assertEquals(self.streamEnded, False) 54 xs.dataReceived("<child><unclosed></child>") 55 self.assertEquals(self.errorOccurred, True) 56 self.assertEquals(self.streamEnded, True) 36 def test_receiveRoot(self): 37 """ 38 Receiving the starttag of the root element results in stream start. 39 """ 40 streamStarted = [] 41 42 def streamStartEvent(rootelem): 43 streamStarted.append(None) 44 45 self.xmlstream.addObserver(xmlstream.STREAM_START_EVENT, 46 streamStartEvent) 47 self.xmlstream.connectionMade() 48 self.xmlstream.dataReceived("<root>") 49 self.assertEquals(1, len(streamStarted)) 50 51 52 def test_receiveBadXML(self): 53 """ 54 Receiving malformed XML should result in in error. 55 """ 56 streamError = [] 57 streamEnd = [] 58 59 def streamErrorEvent(reason): 60 streamError.append(reason) 61 62 def streamEndEvent(_): 63 streamEnd.append(None) 64 65 self.xmlstream.addObserver(xmlstream.STREAM_ERROR_EVENT, 66 streamErrorEvent) 67 self.xmlstream.addObserver(xmlstream.STREAM_END_EVENT, 68 streamEndEvent) 69 self.xmlstream.connectionMade() 70 71 self.xmlstream.dataReceived("<root>") 72 self.assertEquals(0, len(streamError)) 73 self.assertEquals(0, len(streamEnd)) 74 75 self.xmlstream.dataReceived("<child><unclosed></child>") 76 self.assertEquals(1, len(streamError)) 77 self.assertTrue(streamError[0].check(domish.ParserError)) 78 self.assertEquals(1, len(streamEnd)) 79 57 80 58 81 59 82 class DummyProtocol(protocol.Protocol, utility.EventDispatcher): -
twisted/words/xish/xmlstream.py
diff -r 32bd907eefae -r e255d835eef1 twisted/words/xish/xmlstream.py
a b 1 1 # -*- test-case-name: twisted.words.test.test_xmlstream -*- 2 2 # 3 # Copyright (c) 2001-200 7Twisted Matrix Laboratories.3 # Copyright (c) 2001-2008 Twisted Matrix Laboratories. 4 4 # See LICENSE for details. 5 5 6 6 """ … … 16 16 Maintainer: Ralph Meijer 17 17 """ 18 18 19 from twisted.python import failure 19 20 from twisted.internet import protocol 20 21 from twisted.words.xish import domish, utility 21 22 … … 73 74 self.rawDataInFn(data) 74 75 self.stream.parse(data) 75 76 except domish.ParserError: 76 self.dispatch( self, STREAM_ERROR_EVENT)77 self.dispatch(failure.Failure(), STREAM_ERROR_EVENT) 77 78 self.transport.loseConnection() 78 79 79 80 def connectionLost(self, reason):
