Fix stanza clobbering when replying to errors.
If a stanza handler raised an exception, the exception was processed and replied by the modified stanza, not a stanza with the original content. A copy is now made before handler processing, and if an exception occurs it is the copy that processes the exception using the original content.
This commit is contained in:
		| @@ -97,7 +97,7 @@ class Message(RootStanza): | ||||
|             clear -- Indicates if existing content should be removed | ||||
|                      before replying. Defaults to True. | ||||
|         """ | ||||
|         StanzaBase.reply(self) | ||||
|         StanzaBase.reply(self, clear) | ||||
|         if self['type'] == 'groupchat': | ||||
|             self['to'] = self['to'].bare | ||||
|  | ||||
|   | ||||
| @@ -944,13 +944,14 @@ class XMLStream(object): | ||||
|             func -- The event handler to execute. | ||||
|             args -- Arguments to the event handler. | ||||
|         """ | ||||
|         orig = copy.copy(args[0]) | ||||
|         try: | ||||
|             func(*args) | ||||
|         except Exception as e: | ||||
|             error_msg = 'Error processing event handler: %s' | ||||
|             log.exception(error_msg % str(func)) | ||||
|             if hasattr(args[0], 'exception'): | ||||
|                 args[0].exception(e) | ||||
|             if hasattr(orig, 'exception'): | ||||
|                 orig.exception(e) | ||||
|  | ||||
|     def _event_runner(self): | ||||
|         """ | ||||
| @@ -973,6 +974,7 @@ class XMLStream(object): | ||||
|  | ||||
|                 etype, handler = event[0:2] | ||||
|                 args = event[2:] | ||||
|                 orig = copy.copy(args[0]) | ||||
|  | ||||
|                 if etype == 'stanza': | ||||
|                     try: | ||||
| @@ -980,7 +982,7 @@ class XMLStream(object): | ||||
|                     except Exception as e: | ||||
|                         error_msg = 'Error processing stream handler: %s' | ||||
|                         log.exception(error_msg % handler.name) | ||||
|                         args[0].exception(e) | ||||
|                         orig.exception(e) | ||||
|                 elif etype == 'schedule': | ||||
|                     try: | ||||
|                         log.debug('Scheduled event: %s' % args) | ||||
| @@ -989,6 +991,7 @@ class XMLStream(object): | ||||
|                         log.exception('Error processing scheduled task') | ||||
|                 elif etype == 'event': | ||||
|                     func, threaded, disposable = handler | ||||
|                     orig = copy.copy(args[0]) | ||||
|                     try: | ||||
|                         if threaded: | ||||
|                             x = threading.Thread( | ||||
| @@ -1001,8 +1004,8 @@ class XMLStream(object): | ||||
|                     except Exception as e: | ||||
|                         error_msg = 'Error processing event handler: %s' | ||||
|                         log.exception(error_msg % str(func)) | ||||
|                         if hasattr(args[0], 'exception'): | ||||
|                             args[0].exception(e) | ||||
|                         if hasattr(orig, 'exception'): | ||||
|                             orig.exception(e) | ||||
|                 elif etype == 'quit': | ||||
|                     log.debug("Quitting event runner thread") | ||||
|                     return False | ||||
|   | ||||
| @@ -15,6 +15,35 @@ class TestStreamExceptions(SleekTest): | ||||
|         sys.excepthook = sys.__excepthook__ | ||||
|         self.stream_close() | ||||
|  | ||||
|     def testExceptionReply(self): | ||||
|         """Test that raising an exception replies with the original stanza.""" | ||||
|  | ||||
|         def message(msg): | ||||
|             msg.reply() | ||||
|             msg['body'] = 'Body changed' | ||||
|             raise XMPPError(clear=False) | ||||
|  | ||||
|  | ||||
|         sys.excepthook = lambda *args, **kwargs: None | ||||
|         self.stream_start() | ||||
|         self.xmpp.add_event_handler('message', message) | ||||
|  | ||||
|         self.recv(""" | ||||
|           <message> | ||||
|             <body>This is going to cause an error.</body> | ||||
|           </message> | ||||
|         """) | ||||
|  | ||||
|         self.send(""" | ||||
|           <message type="error"> | ||||
|             <body>This is going to cause an error.</body> | ||||
|             <error type="cancel" code="500"> | ||||
|               <undefined-condition | ||||
|                   xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /> | ||||
|             </error> | ||||
|           </message> | ||||
|         """) | ||||
|  | ||||
|     def testXMPPErrorException(self): | ||||
|         """Test raising an XMPPError exception.""" | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Lance Stout
					Lance Stout