Report the original stream:error stanza to clients.
authorGlenn Maynard <glenn@zewt.org>
Thu, 28 Apr 2011 04:53:59 +0000 (00:53 -0400)
committerGlenn Maynard <glenn@zewt.org>
Thu, 28 Apr 2011 04:53:59 +0000 (00:53 -0400)
When a stream:error was received, the error was parsed, converted to a
StreamError exception, then XML was recreated from that.  This is roundabout
and lossy: it's parsing the XML, then attempting to recreate the same XML
that it already had.

Instead, keep the original XML node in the exception, and use it directly.
This ensures that the <stream:error> node in remote-stream-error is
unchanged from what we received from the remote server.  Any extensions
will be passed through unchanged, as should happen for all stanzas.

For example, the <stream:error> node reported by Jabber14 now correctly
reproduces its xmlns='jabber:client' attribute.

The simple patch in patches.py should eventually be sent upstream.

punjab/__init__.py
punjab/patches.py [new file with mode: 0644]
punjab/session.py

index 70bf013..d932699 100644 (file)
@@ -4,6 +4,7 @@ Punjab - multiple http interfaces to jabber.
 """
 from twisted.python import log
 from twisted.application import service
+import twisted_patches
 
 
 def uriCheck(elem, uri):
diff --git a/punjab/patches.py b/punjab/patches.py
new file mode 100644 (file)
index 0000000..73f71a3
--- /dev/null
@@ -0,0 +1,24 @@
+# XXX: All monkey patches should be sent upstream and eventually removed.
+
+import functools
+
+def patch(cls, attr):
+    """Patch the function named attr in the object cls with the decorated function."""
+    orig_func = getattr(cls, attr)
+    @wraps(orig_func)
+    def decorator(func):
+        def wrapped_func(*args, **kwargs):
+            return func(orig_func, *args, **kwargs)
+        setattr(cls, attr, wrapped_func)
+        return orig_func
+    return decorator
+
+# Modify jabber.error.exceptionFromStreamError to include the XML element in
+# the exception.
+from twisted.words.protocols.jabber import error as jabber_error
+@patch(jabber_error, "exceptionFromStreamError")
+def exceptionFromStreamError(orig, element):
+    exception = orig(element)
+    exception.element = element
+    return exception
+
index de49f20..0bb58a5 100644 (file)
@@ -517,11 +517,7 @@ class Session(jabber.JabberClientFactory, server.Session):
     def streamError(self, streamerror):
         """called when we get a stream:error stanza"""
         
-        try: # a workaround for a bug in twisted.words.protocols.jabber.error
-            err_elem = streamerror.value.getElement()
-            err_elem.toXml()
-        except: # no matter what the exception we just return None
-            err_elem = None
+        err_elem = getattr(streamerror.value, "element")
 
         e = self.buildRemoteError(err_elem)
         do_expire = True