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:
Lance Stout 2011-06-20 16:25:56 -07:00
parent 58aa944a5e
commit d8d9e8df16
3 changed files with 38 additions and 6 deletions

View file

@ -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

View file

@ -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

View file

@ -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."""