/** * $RCSfile$ * $Revision: $ * $Date: $ * * Copyright (C) 2006 Jive Software. All rights reserved. * * This software is published under the terms of the GNU Public License (GPL), * a copy of which is included in this distribution. */ package org.jivesoftware.multiplexer.net; import junit.framework.Assert; import junit.framework.TestCase; import org.apache.mina.common.ByteBuffer; import org.dom4j.Element; import org.dom4j.io.SAXReader; import org.dom4j.io.XMPPPacketReader; import org.xmlpull.v1.XmlPullParserFactory; import java.io.StringReader; import java.nio.charset.Charset; /** * Simple test of XMLLightweightParser. * * @author Gaston Dombiak */ public class XMLLightweightParserTest extends TestCase { private final static String CHARSET = "UTF-8"; private XMLLightweightParser parser; private ByteBuffer in; public void testHeader() throws Exception { String msg1 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("Stream header is not being correctly parsed", parser.areThereMsgs()); assertEquals("Wrong stanza was parsed", msg1, parser.getMsgs()[0]); } public void testHeaderWithXMLVersion() throws Exception { String msg1 = "<?xml version=\"1.0\"?>"; String msg2 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; in.putString(msg1 + msg2, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("Stream header is not being correctly parsed", parser.areThereMsgs()); String[] values = parser.getMsgs(); assertEquals("Wrong number of parsed stanzas", 2, values.length); assertEquals("Wrong stanza was parsed", msg1, values[0]); assertEquals("Wrong stanza was parsed", msg2, values[1]); } public void testStanzas() throws Exception { String msg1 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; String msg2 = "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"; String msg3 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; String msg4 = "<iq id=\"428qP-0\" to=\"localhost\" type=\"get\"><query xmlns=\"jabber:iq:register\"></query></iq>"; String msg5 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; String msg6 = "<presence id=\"428qP-5\"></presence>"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.putString(msg2, Charset.forName(CHARSET).newEncoder()); in.putString(msg3, Charset.forName(CHARSET).newEncoder()); in.putString(msg4, Charset.forName(CHARSET).newEncoder()); in.putString(msg5, Charset.forName(CHARSET).newEncoder()); in.putString(msg6, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("Stream header is not being correctly parsed", parser.areThereMsgs()); String[] values = parser.getMsgs(); assertEquals("Wrong number of parsed stanzas", 6, values.length); assertEquals("Wrong stanza was parsed", msg1, values[0]); assertEquals("Wrong stanza was parsed", msg2, values[1]); assertEquals("Wrong stanza was parsed", msg3, values[2]); assertEquals("Wrong stanza was parsed", msg4, values[3]); assertEquals("Wrong stanza was parsed", msg5, values[4]); assertEquals("Wrong stanza was parsed", msg6, values[5]); } public void testCompleteStanzas() throws Exception { String msg1 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; String msg2 = "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"; String msg3 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; String msg4 = "<iq id=\"428qP-0\" to=\"localhost\" type=\"get\"><query xmlns=\"jabber:iq:register\"></query></iq>"; String msg5 = "<stream:stream to=\"localhost\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">"; String msg6 = "<presence id=\"428qP-5\"></presence>"; String msg7 = "</stream:stream>"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.putString(msg2, Charset.forName(CHARSET).newEncoder()); in.putString(msg3, Charset.forName(CHARSET).newEncoder()); in.putString(msg4, Charset.forName(CHARSET).newEncoder()); in.putString(msg5, Charset.forName(CHARSET).newEncoder()); in.putString(msg6, Charset.forName(CHARSET).newEncoder()); in.putString(msg7, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("Stream header is not being correctly parsed", parser.areThereMsgs()); String[] values = parser.getMsgs(); assertEquals("Wrong number of parsed stanzas", 7, values.length); assertEquals("Wrong stanza was parsed", msg1, values[0]); assertEquals("Wrong stanza was parsed", msg2, values[1]); assertEquals("Wrong stanza was parsed", msg3, values[2]); assertEquals("Wrong stanza was parsed", msg4, values[3]); assertEquals("Wrong stanza was parsed", msg5, values[4]); assertEquals("Wrong stanza was parsed", msg6, values[5]); assertEquals("Wrong stanza was parsed", msg7, values[6]); } public void testIQ() throws Exception { String iq = "<iq type=\"set\" to=\"lachesis\" from=\"0sups/Connection Worker - 1\" id=\"360-22348\"><session xmlns=\"http://jabber.org/protocol/connectionmanager\" id=\"0sups87b1694\"><close/></session></iq>"; in.putString(iq, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("Stream header is not being correctly parsed", parser.areThereMsgs()); String parsedIQ = parser.getMsgs()[0]; assertEquals("Wrong stanza was parsed", iq, parsedIQ); SAXReader reader = new SAXReader(); reader.setEncoding(CHARSET); Element doc = reader.read(new StringReader(parsedIQ)).getRootElement(); assertNotNull("Failed to parse IQ stanza", doc); } public void testParsing() throws Exception { String stanza = "<presence type=\"unavailable\" from=\"user11840@lachesis/tsung\" to=\"user11846@lachesis\"/>"; XmlPullParserFactory factory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null); factory.setNamespaceAware(true); XMPPPacketReader xmppReader = new XMPPPacketReader(); xmppReader.setXPPFactory(factory); Element doc = xmppReader.read(new StringReader(stanza)).getRootElement(); assertNotNull(doc); assertEquals(stanza, doc.asXML()); } public void testWeirdChars() throws Exception { //String stanza = "<message id=\"wXBU0-86\" to=\"derek@jivesoftware.com\" from=\"phone@jivesoftware.com/spark\" type=\"chat\"><body>© 2003 - 2007 by Monsters and Critics.com, WotR Ltd. All Rights Reserved. All photos are copyright their respective owners and are used under license or with permission. * Note M&C cannot be held responsible for the content on other Web Sites.</body><thread>5Yo2Kd</thread><x xmlns=\"jabber:x:event\"><offline/><composing/></x></message>"; String stanza = "<message id=\"wXBU0-86\" to=\"derek@jivesoftware.com\" from=\"phone@jivesoftware.com/spark\" type=\"chat\"><body>© 2003 - 2007 by Monsters and Critics.com, WotR Ltd. All Rights Reserved. All photos are copyright their respective owners and are used under license or with permission. * Note M\"&C cannot be held responsible for the content on other Web Sites.</body><thread>5Yo2Kd</thread><x xmlns=\"jabber:x:event\"><offline/><composing/></x></message>"; XmlPullParserFactory factory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null); factory.setNamespaceAware(true); XMPPPacketReader xmppReader = new XMPPPacketReader(); xmppReader.setXPPFactory(factory); Element doc = xmppReader.read(new StringReader(stanza)).getRootElement(); assertNotNull(doc); assertEquals(stanza, doc.asXML()); } public void testEmptyElement() throws Exception { String stanza = "<message/>"; XmlPullParserFactory factory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null); factory.setNamespaceAware(true); XMPPPacketReader xmppReader = new XMPPPacketReader(); xmppReader.setXPPFactory(factory); Element doc = xmppReader.read(new StringReader(stanza)).getRootElement(); assertNotNull(doc); assertEquals(stanza, doc.asXML()); } public void testNestedElements() throws Exception { String msg1 = "<message><message xmlns=\"e\">1</message></message>"; //String msg1 = "<message id=\"3W3We-84\" to=\"gato@localhost/IDEtalk\" type=\"chat\"><body>will update it...</body><thread>12jid1</thread><IDEtalk-data xmlns=\"http://idetalk.com/namespace/jabber\"><message xmlns=\"http://idetalk.com/namespace\" when=\"1171565295250\">will update it...</message></IDEtalk-data></message>"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("Stream header is not being correctly parsed", parser.areThereMsgs()); String[] values = parser.getMsgs(); assertEquals("Wrong number of parsed stanzas", 1, values.length); assertEquals("Wrong stanza was parsed", msg1, values[0]); } public void testIncompleteStanza() throws Exception { String msg1 = "<message><something xmlns=\"http://idetalk.com/namespace\">12"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertFalse("Found messages in incomplete stanza", parser.areThereMsgs()); } public void testStanzaWithSpecialChars() throws Exception { String msg1 = "<message><something xmlns=\"http://idetalk.com/namespace\">12/</something></message>"; String msg2 = "<message><something xmlns=\"http://idetalk.com/namespace\">12///</something></message>"; String msg3 = "<message><something xmlns=\"http://idetalk.com/namespace\">12/\\/</something></message>"; String msg4 = "<message><something xmlns=\"http://idetalk.com/namespace\">http://idetalk.com/namespace/</something></message>"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.putString(msg2, Charset.forName(CHARSET).newEncoder()); in.putString(msg3, Charset.forName(CHARSET).newEncoder()); in.putString(msg4, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("No messages were found in stanza", parser.areThereMsgs()); String[] values = parser.getMsgs(); assertEquals("Wrong number of parsed stanzas", 4, values.length); assertEquals("Wrong stanza was parsed", msg1, values[0]); assertEquals("Wrong stanza was parsed", msg2, values[1]); assertEquals("Wrong stanza was parsed", msg3, values[2]); assertEquals("Wrong stanza was parsed", msg4, values[3]); } public void testCompletedStanza() throws Exception { String msg1 = "<message><something xmlns=\"http://idetalk.com/namespace\">12"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertFalse("Found messages in incomplete stanza", parser.areThereMsgs()); String msg2 = "</something></message>"; ByteBuffer in2 = ByteBuffer.allocate(4096); in2.setAutoExpand(true); in2.putString(msg2, Charset.forName(CHARSET).newEncoder()); in2.flip(); // Fill parser with byte buffer content and parse it parser.read(in2); in2.release(); assertTrue("Stream header is not being correctly parsed", parser.areThereMsgs()); String[] values = parser.getMsgs(); assertEquals("Wrong number of parsed stanzas", 1, values.length); assertEquals("Wrong stanza was parsed", msg1 + msg2, values[0]); } public void testStanzaWithComments() throws Exception { String msg1 = "<iq from=\"lg@jivesoftware.com/spark\"><query xmlns=\"jabber:iq:privacy\"><!-- silly comment --></query></iq>"; in.putString(msg1, Charset.forName(CHARSET).newEncoder()); in.flip(); // Fill parser with byte buffer content and parse it parser.read(in); // Make verifications assertTrue("No messages were found in stanza", parser.areThereMsgs()); String[] values = parser.getMsgs(); assertEquals("Wrong number of parsed stanzas", 1, values.length); assertEquals("Wrong stanza was parsed", msg1, values[0]); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null); factory.setNamespaceAware(true); XMPPPacketReader xmppReader = new XMPPPacketReader(); xmppReader.setXPPFactory(factory); Element doc = xmppReader.read(new StringReader(values[0])).getRootElement(); assertNotNull(doc); assertEquals(msg1, doc.asXML()); } public void testWeirdoContent() throws Exception { final String[] testStanzas = { "<?xml version=\"1.0\"?>", "<stream:stream xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\" to=\"localhost\" >", "<emppartag test=\"1\"/>", "<cdatatest><![CDATA[just<ignore everything& >>here<<<<< /> />]]>]]></cdatatest>", "<esctest param=\"1\"> this \" is / a test /> test /> </esctest>", "<comtest>this <!-- comment --> is a comment</comtest>", "<emptag/>", "<iq type=\"get\" id=\"aab1a\" ><query xmlns=\"jabber:iq:roster\"/> <tag> text </tag></iq>", "<iq type=\"get\" id=\"aab1a\" ><query xmlns=\"jabber:iq:roster\"/> </iq>", "<message><body xmlns=\"http://idetalk.com/namespace\">12\"</body></message>" , "<message to=\"lg@jivesoftware.com\" id=\"XRk8p-X\"><body> /> /> </body></message>" , }; String testMsg = ""; for(String s : testStanzas) { testMsg += s; } ByteBuffer mybuffer = ByteBuffer.wrap(testMsg.getBytes()); parser.read(mybuffer); String[] msgs = parser.getMsgs(); for(int i = 0; i < testStanzas.length; i++) { assertTrue(i < msgs.length); assertEquals(testStanzas[i], msgs[i]); } } public void testInvalidSurrogates() throws Exception { byte[] one = ("<message><body xmlns=\"http://idetalk.com/namespace\">").getBytes(); byte[] two = {(byte) 0xed, (byte) 0xb3, (byte) 0xb1}; byte[] three = "</body></message>".getBytes(); byte[] message = new byte[one.length + two.length + three.length]; int j = 0; for (byte b : one) { message[j++] = b; } for (byte b : two) { message[j++] = b; } for (byte b : three) { message[j++] = b; } ByteBuffer mybuffer = ByteBuffer.wrap(message); try { parser.read(mybuffer); fail("Failed to detect a low surrogate char without a preceding high surrogate"); } catch (Exception e) { assertEquals("Incorrect exception was received", "Found low surrogate char without a preceding high surrogate", e.getMessage()); } } /** * Check that the parser does not accept characters below 0x20 (except for 9, A, and D) * * @throws Exception */ public void testInvalidXML() throws Exception { byte[] one = ("<message><body xmlns=\"http://idetalk.com/namespace\">").getBytes(); byte[] two = {(byte) 0x7 , (byte) 0x8}; byte[] three = "</body></message>".getBytes(); byte[] message = new byte[one.length + two.length + three.length]; int j = 0; for (byte b : one) { message[j++] = b; } for (byte b : two) { message[j++] = b; } for (byte b : three) { message[j++] = b; } ByteBuffer mybuffer = ByteBuffer.wrap(message); try { parser.read(mybuffer); fail("Failed to detect a low surrogate char without a preceding high surrogate"); } catch (Exception e) { assertEquals("Incorrect exception was received", "Found low surrogate char without a preceding high surrogate", e.getMessage()); } } public void testRead() { try { XMLLightweightParser parser = new XMLLightweightParser("UTF-8"); String xml1 = "<ab>\u1000</a"; String xml2 = "b>"; ByteBuffer buffer1 = ByteBuffer.wrap(xml1.getBytes("UTF-8")); ByteBuffer buffer2 = ByteBuffer.wrap(xml2.getBytes("UTF-8")); parser.read(buffer1); parser.read(buffer2); if (!parser.areThereMsgs()) Assert.fail("No messages found"); String msgs[] = parser.getMsgs(); if (msgs.length > 1) { Assert.fail("More than one message found"); } else { Assert.assertEquals(xml1 + xml2, msgs[0]); } } catch (Exception e) { Assert.fail(e.getMessage()); } } protected void setUp() throws Exception { super.setUp(); // Create parser parser = new XMLLightweightParser(CHARSET); // Crete byte buffer and append text in = ByteBuffer.allocate(4096); in.setAutoExpand(true); } protected void tearDown() throws Exception { super.tearDown(); // Release byte buffer in.release(); } }