# HG changeset patch # User Paul Aurich # Date 1241038673 0 # Node ID f424f26dd32951aa90ab95b9cde4753e55375e9c # Parent 3ebd399dd81e921cfcd15d856f1a7ec439138d74 *** Plucked rev d34a1589 (darkrain42@pidgin.im): Feed a fake to the XMPP parser to silence warnings. Upgrading to TLS and disconnecting should no longer emit 'Extra content at the end of the document' References #8830. *** Plucked rev ca9f6d5b (darkrain42@pidgin.im): Add xmlnode and bonjour structured error handlers. Various libraries may set global structured error handlers and libxml2 prefers those to a per-context normal error handler. This causes us to break badly. References #8830. *** Plucked rev 34f4897e (darkrain42@pidgin.im): xmlCtxtGetLastError may return NULL, especially with other misbehaving libraries in our address space. References #8136. diff -r 3ebd399dd81e -r f424f26dd329 ChangeLog --- a/ChangeLog Wed Apr 29 19:39:11 2009 +0000 +++ b/ChangeLog Wed Apr 29 20:57:53 2009 +0000 @@ -5,6 +5,9 @@ * Improve sleep behavior by aggregation of longer timeouts on second boundaries to allow better power saving. (Arunan Balasubramaniam) * Fix various crashes on exit. + * Make XML parsing more resilient to interactions with other libraries. + This, along with the fix for libxml2 bug 564217, fixes the crashes + on connect in XMPP with recent gst-plugins-bad (see #8830 for details). IRC: * Correctly handle WHOIS for users who are joined to a large number of diff -r 3ebd399dd81e -r f424f26dd329 libpurple/protocols/bonjour/parser.c --- a/libpurple/protocols/bonjour/parser.c Wed Apr 29 19:39:11 2009 +0000 +++ b/libpurple/protocols/bonjour/parser.c Wed Apr 29 20:57:53 2009 +0000 @@ -156,6 +156,18 @@ xmlnode_insert_data(bconv->current, (const char*) text, text_len); } +static void +bonjour_parser_structured_error_handler(void *user_data, xmlErrorPtr error) +{ + BonjourJabberConversation *bconv = user_data; + + purple_debug_error("jabber", "XML parser error for BonjourJabberConversation %p: " + "Domain %i, code %i, level %i: %s", + bconv, + error->domain, error->code, error->level, + (error->message ? error->message : "(null)\n")); +} + static xmlSAXHandler bonjour_parser_libxml = { NULL, /*internalSubset*/ NULL, /*isStandalone*/ @@ -188,7 +200,7 @@ NULL, /*_private*/ bonjour_parser_element_start_libxml, /*startElementNs*/ bonjour_parser_element_end_libxml, /*endElementNs*/ - NULL /*serror*/ + bonjour_parser_structured_error_handler /*serror*/ }; void diff -r 3ebd399dd81e -r f424f26dd329 libpurple/protocols/jabber/jabber.c --- a/libpurple/protocols/jabber/jabber.c Wed Apr 29 19:39:11 2009 +0000 +++ b/libpurple/protocols/jabber/jabber.c Wed Apr 29 20:57:53 2009 +0000 @@ -77,6 +77,10 @@ "xmlns:stream='http://etherx.jabber.org/streams' " "version='1.0'>", js->user->domain); + if (js->reinit) + /* Close down the current stream to keep the XML parser happy */ + jabber_parser_close_stream(js); + /* setup the parser fresh for each stream */ jabber_parser_setup(js); jabber_send_raw(js, open_stream, -1); @@ -636,6 +640,9 @@ static void tls_init(JabberStream *js) { + /* Close down the current stream to keep the XML parser happy */ + jabber_parser_close_stream(js); + purple_input_remove(js->gc->inpa); js->gc->inpa = 0; js->gsc = purple_ssl_connect_with_host_fd(js->gc->account, js->fd, @@ -1327,6 +1334,16 @@ if (!gc->disconnect_timeout) jabber_send_raw(js, "", -1); + if (!purple_account_get_current_error(purple_connection_get_account(gc))) { + /* + * The common case is user-triggered, so we never receive a + * from the server when disconnecting, so silence the + * parser's warnings. On errors, though, the server terminated the + * connection, so we should have received a real . + */ + jabber_parser_close_stream(js); + } + if (js->srv_query_data) purple_srv_cancel(js->srv_query_data); diff -r 3ebd399dd81e -r f424f26dd329 libpurple/protocols/jabber/parser.c --- a/libpurple/protocols/jabber/parser.c Wed Apr 29 19:39:11 2009 +0000 +++ b/libpurple/protocols/jabber/parser.c Wed Apr 29 20:57:53 2009 +0000 @@ -205,6 +205,12 @@ jabber_parser_free(js); } +void +jabber_parser_close_stream(JabberStream *js) +{ + xmlParseChunk(js->context, "", 16 /* length */, 0); +} + void jabber_parser_free(JabberStream *js) { if (js->context) { xmlParseChunk(js->context, NULL,0,1); @@ -224,8 +230,17 @@ xmlParseChunk(js->context, "", 0, 0); } else if ((ret = xmlParseChunk(js->context, buf, len, 0)) != XML_ERR_OK) { xmlError *err = xmlCtxtGetLastError(js->context); + /* + * libxml2 uses a global setting to determine whether or not to store + * warnings. Other libraries may set this, which causes err to be + * NULL. See #8136 for details. + */ + xmlErrorLevel level = XML_ERR_WARNING; - switch (err->level) { + if (err) + level = err->level; + + switch (level) { case XML_ERR_NONE: purple_debug_info("jabber", "xmlParseChunk returned info %i\n", ret); break; diff -r 3ebd399dd81e -r f424f26dd329 libpurple/protocols/jabber/parser.h --- a/libpurple/protocols/jabber/parser.h Wed Apr 29 19:39:11 2009 +0000 +++ b/libpurple/protocols/jabber/parser.h Wed Apr 29 20:57:53 2009 +0000 @@ -25,6 +25,7 @@ #include "jabber.h" void jabber_parser_setup(JabberStream *js); +void jabber_parser_close_stream(JabberStream *js); void jabber_parser_free(JabberStream *js); void jabber_parser_process(JabberStream *js, const char *buf, int len); diff -r 3ebd399dd81e -r f424f26dd329 libpurple/xmlnode.c --- a/libpurple/xmlnode.c Wed Apr 29 19:39:11 2009 +0000 +++ b/libpurple/xmlnode.c Wed Apr 29 20:57:53 2009 +0000 @@ -665,6 +665,28 @@ purple_debug_error("xmlnode", "Error parsing xml file: %s", errmsg); } +static void +xmlnode_parser_structural_error_libxml(void *user_data, xmlErrorPtr error) +{ + struct _xmlnode_parser_data *xpd = user_data; + + if (error && (error->level == XML_ERR_ERROR || + error->level == XML_ERR_FATAL)) { + xpd->error = TRUE; + purple_debug_error("xmlnode", "XML parser error for xmlnode %p: " + "Domain %i, code %i, level %i: %s", + user_data, error->domain, error->code, error->level, + error->message ? error->message : "(null)\n"); + } else if (error) + purple_debug_warning("xmlnode", "XML parser error for xmlnode %p: " + "Domain %i, code %i, level %i: %s", + user_data, error->domain, error->code, error->level, + error->message ? error->message : "(null)\n"); + else + purple_debug_warning("xmlnode", "XML parser error for xmlnode %p\n", + user_data); +} + static xmlSAXHandler xmlnode_parser_libxml = { NULL, /* internalSubset */ NULL, /* isStandalone */ @@ -697,7 +719,7 @@ NULL, /* _private */ xmlnode_parser_element_start_libxml, /* startElementNs */ xmlnode_parser_element_end_libxml, /* endElementNs */ - NULL, /* serror */ + xmlnode_parser_structural_error_libxml, /* serror */ }; xmlnode *