From 02c18de062510e8061598bf492c68cb5b0624831 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Tue, 24 Apr 2012 20:22:30 +0200
Subject: Make built-in expat ignore unbound prefix namespaces.

This works around a problem with broken servers relaying illegal
stanzas from broken clients. Obviously only works when using the
bundled Expat.
Note that the system OS X libXML also seems to behave this way.

diff --git a/3rdParty/Expat/ignore_unbound_prefix_namespaces.diff b/3rdParty/Expat/ignore_unbound_prefix_namespaces.diff
new file mode 100644
index 0000000..945e436
--- /dev/null
+++ b/3rdParty/Expat/ignore_unbound_prefix_namespaces.diff
@@ -0,0 +1,56 @@
+diff --git a/3rdParty/Expat/src/xmlparse.c b/3rdParty/Expat/src/xmlparse.c
+index 94e31de..ad5add2 100755
+--- a/src/xmlparse.c
++++ b/src/xmlparse.c
+@@ -2808,8 +2808,10 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
+         ((XML_Char *)s)[-1] = 0;  /* clear flag */
+         id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0);
+         b = id->prefix->binding;
+-        if (!b)
+-          return XML_ERROR_UNBOUND_PREFIX;
++        if (!b) {
++          //return XML_ERROR_UNBOUND_PREFIX;
++          continue;
++        }
+ 
+         /* as we expand the name we also calculate its hash value */
+         for (j = 0; j < b->uriLen; j++) {
+@@ -2887,7 +2889,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
+     return XML_ERROR_NONE;
+ 
+   /* expand the element type name */
+-  if (elementType->prefix) {
++  if (elementType->prefix && elementType->prefix->binding) {
+     binding = elementType->prefix->binding;
+     if (!binding)
+       return XML_ERROR_UNBOUND_PREFIX;
+@@ -2983,10 +2985,10 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+       && prefix->name[2] == XML_T(ASCII_l)) {
+ 
+     /* Not allowed to bind xmlns */
+-    if (prefix->name[3] == XML_T(ASCII_n)
++    /*if (prefix->name[3] == XML_T(ASCII_n)
+         && prefix->name[4] == XML_T(ASCII_s)
+         && prefix->name[5] == XML_T('\0'))
+-      return XML_ERROR_RESERVED_PREFIX_XMLNS;
++      return XML_ERROR_RESERVED_PREFIX_XMLNS;*/
+ 
+     if (prefix->name[3] == XML_T('\0'))
+       mustBeXML = XML_TRUE;
+@@ -3003,12 +3005,12 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+   isXML = isXML && len == xmlLen;
+   isXMLNS = isXMLNS && len == xmlnsLen;
+ 
+-  if (mustBeXML != isXML)
++  /*if (mustBeXML != isXML)
+     return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
+-                     : XML_ERROR_RESERVED_NAMESPACE_URI;
++                     : XML_ERROR_RESERVED_NAMESPACE_URI;*/
+ 
+-  if (isXMLNS)
+-    return XML_ERROR_RESERVED_NAMESPACE_URI;
++  /*if (isXMLNS)
++    return XML_ERROR_RESERVED_NAMESPACE_URI;*/
+ 
+   if (namespaceSeparator)
+     len++;
diff --git a/3rdParty/Expat/src/xmlparse.c b/3rdParty/Expat/src/xmlparse.c
index 94e31de..ad5add2 100755
--- a/3rdParty/Expat/src/xmlparse.c
+++ b/3rdParty/Expat/src/xmlparse.c
@@ -2808,8 +2808,10 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
         ((XML_Char *)s)[-1] = 0;  /* clear flag */
         id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0);
         b = id->prefix->binding;
-        if (!b)
-          return XML_ERROR_UNBOUND_PREFIX;
+        if (!b) {
+          //return XML_ERROR_UNBOUND_PREFIX;
+          continue;
+        }
 
         /* as we expand the name we also calculate its hash value */
         for (j = 0; j < b->uriLen; j++) {
@@ -2887,7 +2889,7 @@ storeAtts(XML_Parser parser, const ENCODING *enc,
     return XML_ERROR_NONE;
 
   /* expand the element type name */
-  if (elementType->prefix) {
+  if (elementType->prefix && elementType->prefix->binding) {
     binding = elementType->prefix->binding;
     if (!binding)
       return XML_ERROR_UNBOUND_PREFIX;
@@ -2983,10 +2985,10 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
       && prefix->name[2] == XML_T(ASCII_l)) {
 
     /* Not allowed to bind xmlns */
-    if (prefix->name[3] == XML_T(ASCII_n)
+    /*if (prefix->name[3] == XML_T(ASCII_n)
         && prefix->name[4] == XML_T(ASCII_s)
         && prefix->name[5] == XML_T('\0'))
-      return XML_ERROR_RESERVED_PREFIX_XMLNS;
+      return XML_ERROR_RESERVED_PREFIX_XMLNS;*/
 
     if (prefix->name[3] == XML_T('\0'))
       mustBeXML = XML_TRUE;
@@ -3003,12 +3005,12 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
   isXML = isXML && len == xmlLen;
   isXMLNS = isXMLNS && len == xmlnsLen;
 
-  if (mustBeXML != isXML)
+  /*if (mustBeXML != isXML)
     return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
-                     : XML_ERROR_RESERVED_NAMESPACE_URI;
+                     : XML_ERROR_RESERVED_NAMESPACE_URI;*/
 
-  if (isXMLNS)
-    return XML_ERROR_RESERVED_NAMESPACE_URI;
+  /*if (isXMLNS)
+    return XML_ERROR_RESERVED_NAMESPACE_URI;*/
 
   if (namespaceSeparator)
     len++;
diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp
index 8ff56c0..3c84220 100644
--- a/Swiften/Parser/UnitTest/XMLParserTest.cpp
+++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp
@@ -35,6 +35,8 @@ class XMLParserTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST(testParse_AttributeWithoutNamespace);
 		CPPUNIT_TEST(testParse_AttributeWithNamespace);
 		CPPUNIT_TEST(testParse_BillionLaughs);
+		//CPPUNIT_TEST(testParse_UndefinedPrefix);
+		//CPPUNIT_TEST(testParse_UndefinedAttributePrefix);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
@@ -271,6 +273,41 @@ class XMLParserTest : public CppUnit::TestFixture {
 				"<lolz>&lol9;</lolz>"
 			));
 		}
+
+		void testParse_UndefinedPrefix() {
+			ParserType testling(&client_);
+
+			CPPUNIT_ASSERT(testling.parse(
+				"<foo:bar><bla/></foo:bar>"));
+
+			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size());
+
+			CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type);
+			CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[0].data);
+			CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].ns);
+
+			CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type);
+			CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data);
+			CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[1].ns);
+
+			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type);
+			CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[2].data);
+			CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[2].ns);
+
+			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type);
+			CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[3].data);
+			CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[3].ns);
+		}
+
+		void testParse_UndefinedAttributePrefix() {
+			ParserType testling(&client_);
+
+			CPPUNIT_ASSERT(testling.parse(
+				"<foo bar:baz='bla'/>"));
+
+			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size());
+			CPPUNIT_ASSERT_EQUAL(std::string("bar:baz"), client_.events[0].attributes.getEntries()[0].getAttribute().getName());
+		}
 	
 	private:
 		class Client : public XMLParserClient {
-- 
cgit v0.10.2-6-g49f6