Commit 01d67e45 authored by Dave Cridland's avatar Dave Cridland

OF-1335 Strip namespaces differently

parent daf92ff2
/* /*
* Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved. * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
* *
* This software is open source. * This software is open source.
* See the bottom of this file for the licence. * See the bottom of this file for the licence.
* *
*/ */
package org.dom4j.io; package org.dom4j.io;
import org.dom4j.*; import org.dom4j.*;
import org.jivesoftware.openfire.net.MXParser; import org.jivesoftware.openfire.net.MXParser;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlPullParserFactory;
import java.io.*; import java.io.*;
import java.net.URL; import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
/** /**
* <p><code>XMPPPacketReader</code> is a Reader of DOM4J documents that * <p><code>XMPPPacketReader</code> is a Reader of DOM4J documents that
* uses the fast * uses the fast
* <a href="http://www.extreme.indiana.edu/soap/xpp/">XML Pull Parser 3.x</a>. * <a href="http://www.extreme.indiana.edu/soap/xpp/">XML Pull Parser 3.x</a>.
* It is very fast for use in SOAP style environments.</p> * It is very fast for use in SOAP style environments.</p>
* *
* @author <a href="mailto:pelle@neubia.com">Pelle Braendgaard</a> * @author <a href="mailto:pelle@neubia.com">Pelle Braendgaard</a>
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a> * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/ */
public class XMPPPacketReader { public class XMPPPacketReader {
/** /**
* <code>DocumentFactory</code> used to create new document objects * <code>DocumentFactory</code> used to create new document objects
*/ */
private DocumentFactory factory; private DocumentFactory factory;
/** /**
* <code>XmlPullParser</code> used to parse XML * <code>XmlPullParser</code> used to parse XML
*/ */
private MXParser xppParser; private MXParser xppParser;
/** /**
* <code>XmlPullParser</code> used to parse XML * <code>XmlPullParser</code> used to parse XML
*/ */
private XmlPullParserFactory xppFactory; private XmlPullParserFactory xppFactory;
/** /**
* DispatchHandler to call when each <code>Element</code> is encountered * DispatchHandler to call when each <code>Element</code> is encountered
*/ */
private DispatchHandler dispatchHandler; private DispatchHandler dispatchHandler;
/** /**
* Last time a full Document was read or a heartbeat was received. Hearbeats * Last time a full Document was read or a heartbeat was received. Hearbeats
* are represented as whitespaces received while a Document is not being parsed. * are represented as whitespaces received while a Document is not being parsed.
*/ */
private long lastActive = System.currentTimeMillis(); private long lastActive = System.currentTimeMillis();
/** /**
* Stream of various endpoints (eg: s2s, c2s) use different default namespaces. To be able to use a stanza that's * Stream of various endpoints (eg: s2s, c2s) use different default namespaces. To be able to use a stanza that's
* parsed on one type of endpoint in the context of another endpoint, we explicitly ignore these namespaced. This * parsed on one type of endpoint in the context of another endpoint, we explicitly ignore these namespaced. This
* allows us to forward, for instance, a stanza received via C2S (which has the "jabber:client" default namespace) * allows us to forward, for instance, a stanza received via C2S (which has the "jabber:client" default namespace)
* on a S2S stream (which has the "jabber:server" default namespace). * on a S2S stream (which has the "jabber:server" default namespace).
* *
* @see <a href="https://xmpp.org/rfcs/rfc6120.html#streams-ns-xmpp">RFC 6120, 4.8.3. XMPP Content Namespaces</a> * @see <a href="https://xmpp.org/rfcs/rfc6120.html#streams-ns-xmpp">RFC 6120, 4.8.3. XMPP Content Namespaces</a>
*/ */
public static final Collection<String> IGNORED_NAMESPACE_ON_STANZA = Arrays.asList( "jabber:client", "jabber:server", "jabber:connectionmanager", "jabber:component:accept", "http://jabber.org/protocol/httpbind" ); public static final Collection<String> IGNORED_NAMESPACE_ON_STANZA = Arrays.asList( "jabber:client", "jabber:server", "jabber:connectionmanager", "jabber:component:accept", "http://jabber.org/protocol/httpbind" );
public XMPPPacketReader() { public XMPPPacketReader() {
} }
public XMPPPacketReader(DocumentFactory factory) { public XMPPPacketReader(DocumentFactory factory) {
this.factory = factory; this.factory = factory;
} }
/** /**
* <p>Reads a Document from the given <code>File</code></p> * <p>Reads a Document from the given <code>File</code></p>
* *
* @param file is the <code>File</code> to read from. * @param file is the <code>File</code> to read from.
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
* @throws java.net.MalformedURLException if a URL could not be made for the given File * @throws java.net.MalformedURLException if a URL could not be made for the given File
*/ */
public Document read(File file) throws DocumentException, IOException, XmlPullParserException { public Document read(File file) throws DocumentException, IOException, XmlPullParserException {
String systemID = file.getAbsolutePath(); String systemID = file.getAbsolutePath();
return read(new BufferedReader(new FileReader(file)), systemID); return read(new BufferedReader(new FileReader(file)), systemID);
} }
/** /**
* <p>Reads a Document from the given <code>URL</code></p> * <p>Reads a Document from the given <code>URL</code></p>
* *
* @param url <code>URL</code> to read from. * @param url <code>URL</code> to read from.
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
*/ */
public Document read(URL url) throws DocumentException, IOException, XmlPullParserException { public Document read(URL url) throws DocumentException, IOException, XmlPullParserException {
String systemID = url.toExternalForm(); String systemID = url.toExternalForm();
return read(createReader(url.openStream()), systemID); return read(createReader(url.openStream()), systemID);
} }
/** /**
* <p>Reads a Document from the given URL or filename.</p> * <p>Reads a Document from the given URL or filename.</p>
* <p> * <p>
* If the systemID contains a <code>':'</code> character then it is * If the systemID contains a <code>':'</code> character then it is
* assumed to be a URL otherwise its assumed to be a file name. * assumed to be a URL otherwise its assumed to be a file name.
* If you want finer grained control over this mechansim then please * If you want finer grained control over this mechansim then please
* explicitly pass in either a {@link URL} or a {@link File} instance * explicitly pass in either a {@link URL} or a {@link File} instance
* instead of a {@link String} to denote the source of the document. * instead of a {@link String} to denote the source of the document.
* </p> * </p>
* *
* @param systemID is a URL for a document or a file name. * @param systemID is a URL for a document or a file name.
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
* @throws java.net.MalformedURLException if a URL could not be made for the given File * @throws java.net.MalformedURLException if a URL could not be made for the given File
*/ */
public Document read(String systemID) throws DocumentException, IOException, XmlPullParserException { public Document read(String systemID) throws DocumentException, IOException, XmlPullParserException {
if (systemID.indexOf(':') >= 0) { if (systemID.indexOf(':') >= 0) {
// lets assume its a URL // lets assume its a URL
return read(new URL(systemID)); return read(new URL(systemID));
} }
else { else {
// lets assume that we are given a file name // lets assume that we are given a file name
return read(new File(systemID)); return read(new File(systemID));
} }
} }
/** /**
* <p>Reads a Document from the given stream</p> * <p>Reads a Document from the given stream</p>
* *
* @param in <code>InputStream</code> to read from. * @param in <code>InputStream</code> to read from.
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
*/ */
public Document read(InputStream in) throws DocumentException, IOException, XmlPullParserException { public Document read(InputStream in) throws DocumentException, IOException, XmlPullParserException {
return read(createReader(in)); return read(createReader(in));
} }
/** /**
* <p>Reads a Document from the given stream</p> * <p>Reads a Document from the given stream</p>
* *
* @param charSet the charSet that the input is encoded in * @param charSet the charSet that the input is encoded in
* @param in <code>InputStream</code> to read from. * @param in <code>InputStream</code> to read from.
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
*/ */
public Document read(String charSet, InputStream in) public Document read(String charSet, InputStream in)
throws DocumentException, IOException, XmlPullParserException throws DocumentException, IOException, XmlPullParserException
{ {
return read(createReader(in, charSet)); return read(createReader(in, charSet));
} }
/** /**
* <p>Reads a Document from the given <code>Reader</code></p> * <p>Reads a Document from the given <code>Reader</code></p>
* *
* @param reader is the reader for the input * @param reader is the reader for the input
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
*/ */
public Document read(Reader reader) throws DocumentException, IOException, XmlPullParserException { public Document read(Reader reader) throws DocumentException, IOException, XmlPullParserException {
getXPPParser().setInput(reader); getXPPParser().setInput(reader);
return parseDocument(); return parseDocument();
} }
/** /**
* <p>Reads a Document from the given array of characters</p> * <p>Reads a Document from the given array of characters</p>
* *
* @param text is the text to parse * @param text is the text to parse
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
*/ */
public Document read(char[] text) throws DocumentException, IOException, XmlPullParserException { public Document read(char[] text) throws DocumentException, IOException, XmlPullParserException {
getXPPParser().setInput(new CharArrayReader(text)); getXPPParser().setInput(new CharArrayReader(text));
return parseDocument(); return parseDocument();
} }
/** /**
* <p>Reads a Document from the given stream</p> * <p>Reads a Document from the given stream</p>
* *
* @param in <code>InputStream</code> to read from. * @param in <code>InputStream</code> to read from.
* @param systemID is the URI for the input * @param systemID is the URI for the input
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
*/ */
public Document read(InputStream in, String systemID) throws DocumentException, IOException, XmlPullParserException { public Document read(InputStream in, String systemID) throws DocumentException, IOException, XmlPullParserException {
return read(createReader(in), systemID); return read(createReader(in), systemID);
} }
/** /**
* <p>Reads a Document from the given <code>Reader</code></p> * <p>Reads a Document from the given <code>Reader</code></p>
* *
* @param reader is the reader for the input * @param reader is the reader for the input
* @param systemID is the URI for the input * @param systemID is the URI for the input
* @return the newly created Document instance * @return the newly created Document instance
* @throws DocumentException if an error occurs during parsing. * @throws DocumentException if an error occurs during parsing.
*/ */
public Document read(Reader reader, String systemID) throws DocumentException, IOException, XmlPullParserException { public Document read(Reader reader, String systemID) throws DocumentException, IOException, XmlPullParserException {
Document document = read(reader); Document document = read(reader);
document.setName(systemID); document.setName(systemID);
return document; return document;
} }
// Properties // Properties
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
public MXParser getXPPParser() throws XmlPullParserException { public MXParser getXPPParser() throws XmlPullParserException {
if (xppParser == null) { if (xppParser == null) {
xppParser = (MXParser) getXPPFactory().newPullParser(); xppParser = (MXParser) getXPPFactory().newPullParser();
} }
return xppParser; return xppParser;
} }
public XmlPullParserFactory getXPPFactory() throws XmlPullParserException { public XmlPullParserFactory getXPPFactory() throws XmlPullParserException {
if (xppFactory == null) { if (xppFactory == null) {
xppFactory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null); xppFactory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null);
} }
xppFactory.setNamespaceAware(true); xppFactory.setNamespaceAware(true);
return xppFactory; return xppFactory;
} }
public void setXPPFactory(XmlPullParserFactory xppFactory) { public void setXPPFactory(XmlPullParserFactory xppFactory) {
this.xppFactory = xppFactory; this.xppFactory = xppFactory;
} }
/** /**
* @return the <code>DocumentFactory</code> used to create document objects * @return the <code>DocumentFactory</code> used to create document objects
*/ */
public DocumentFactory getDocumentFactory() { public DocumentFactory getDocumentFactory() {
if (factory == null) { if (factory == null) {
factory = DocumentFactory.getInstance(); factory = DocumentFactory.getInstance();
} }
return factory; return factory;
} }
/** /**
* <p>This sets the <code>DocumentFactory</code> used to create new documents. * <p>This sets the <code>DocumentFactory</code> used to create new documents.
* This method allows the building of custom DOM4J tree objects to be implemented * This method allows the building of custom DOM4J tree objects to be implemented
* easily using a custom derivation of {@link DocumentFactory}</p> * easily using a custom derivation of {@link DocumentFactory}</p>
* *
* @param factory <code>DocumentFactory</code> used to create DOM4J objects * @param factory <code>DocumentFactory</code> used to create DOM4J objects
*/ */
public void setDocumentFactory(DocumentFactory factory) { public void setDocumentFactory(DocumentFactory factory) {
this.factory = factory; this.factory = factory;
} }
/** /**
* Adds the <code>ElementHandler</code> to be called when the * Adds the <code>ElementHandler</code> to be called when the
* specified path is encounted. * specified path is encounted.
* *
* @param path is the path to be handled * @param path is the path to be handled
* @param handler is the <code>ElementHandler</code> to be called * @param handler is the <code>ElementHandler</code> to be called
* by the event based processor. * by the event based processor.
*/ */
public void addHandler(String path, ElementHandler handler) { public void addHandler(String path, ElementHandler handler) {
getDispatchHandler().addHandler(path, handler); getDispatchHandler().addHandler(path, handler);
} }
/** /**
* Removes the <code>ElementHandler</code> from the event based * Removes the <code>ElementHandler</code> from the event based
* processor, for the specified path. * processor, for the specified path.
* *
* @param path is the path to remove the <code>ElementHandler</code> for. * @param path is the path to remove the <code>ElementHandler</code> for.
*/ */
public void removeHandler(String path) { public void removeHandler(String path) {
getDispatchHandler().removeHandler(path); getDispatchHandler().removeHandler(path);
} }
/** /**
* When multiple <code>ElementHandler</code> instances have been * When multiple <code>ElementHandler</code> instances have been
* registered, this will set a default <code>ElementHandler</code> * registered, this will set a default <code>ElementHandler</code>
* to be called for any path which does <b>NOT</b> have a handler * to be called for any path which does <b>NOT</b> have a handler
* registered. * registered.
* *
* @param handler is the <code>ElementHandler</code> to be called * @param handler is the <code>ElementHandler</code> to be called
* by the event based processor. * by the event based processor.
*/ */
public void setDefaultHandler(ElementHandler handler) { public void setDefaultHandler(ElementHandler handler) {
getDispatchHandler().setDefaultHandler(handler); getDispatchHandler().setDefaultHandler(handler);
} }
/** /**
* Returns the last time a full Document was read or a heartbeat was received. Hearbeats * Returns the last time a full Document was read or a heartbeat was received. Hearbeats
* are represented as whitespaces or \n received while a Document is not being parsed. * are represented as whitespaces or \n received while a Document is not being parsed.
* *
* @return the time in milliseconds when the last document or heartbeat was received. * @return the time in milliseconds when the last document or heartbeat was received.
*/ */
public long getLastActive() { public long getLastActive() {
long lastHeartbeat = 0; long lastHeartbeat = 0;
try { try {
lastHeartbeat = getXPPParser().getLastHeartbeat(); lastHeartbeat = getXPPParser().getLastHeartbeat();
} }
catch (XmlPullParserException e) {} catch (XmlPullParserException e) {}
return lastActive > lastHeartbeat ? lastActive : lastHeartbeat; return lastActive > lastHeartbeat ? lastActive : lastHeartbeat;
} }
/* /*
* DANIELE: Add parse document by string * DANIELE: Add parse document by string
*/ */
public Document parseDocument(String xml) throws DocumentException { public Document parseDocument(String xml) throws DocumentException {
/* /*
// Long way with reuse of DocumentFactory. // Long way with reuse of DocumentFactory.
DocumentFactory df = getDocumentFactory(); DocumentFactory df = getDocumentFactory();
SAXReader reader = new SAXReader( df ); SAXReader reader = new SAXReader( df );
Document document = reader.read( new StringReader( xml );*/ Document document = reader.read( new StringReader( xml );*/
// Simple way // Simple way
// TODO Optimize. Do not create a sax reader for each parsing // TODO Optimize. Do not create a sax reader for each parsing
Document document = DocumentHelper.parseText(xml); Document document = DocumentHelper.parseText(xml);
return document; return document;
} }
// Implementation methods // Implementation methods
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
public Document parseDocument() throws DocumentException, IOException, XmlPullParserException { public Document parseDocument() throws DocumentException, IOException, XmlPullParserException {
DocumentFactory df = getDocumentFactory(); DocumentFactory df = getDocumentFactory();
Document document = df.createDocument(); Document document = df.createDocument();
Element parent = null; Element parent = null;
XmlPullParser pp = getXPPParser(); XmlPullParser pp = getXPPParser();
int count = 0; int count = 0;
while (true) { while (true) {
int type = -1; int type = -1;
type = pp.nextToken(); type = pp.nextToken();
switch (type) { switch (type) {
case XmlPullParser.PROCESSING_INSTRUCTION: { case XmlPullParser.PROCESSING_INSTRUCTION: {
String text = pp.getText(); String text = pp.getText();
int loc = text.indexOf(" "); int loc = text.indexOf(" ");
if (loc >= 0) { if (loc >= 0) {
document.addProcessingInstruction(text.substring(0, loc), document.addProcessingInstruction(text.substring(0, loc),
text.substring(loc + 1)); text.substring(loc + 1));
} }
else { else {
document.addProcessingInstruction(text, ""); document.addProcessingInstruction(text, "");
} }
break; break;
} }
case XmlPullParser.COMMENT: { case XmlPullParser.COMMENT: {
if (parent != null) { if (parent != null) {
parent.addComment(pp.getText()); parent.addComment(pp.getText());
} }
else { else {
document.addComment(pp.getText()); document.addComment(pp.getText());
} }
break; break;
} }
case XmlPullParser.CDSECT: { case XmlPullParser.CDSECT: {
String text = pp.getText(); String text = pp.getText();
if (parent != null) { if (parent != null) {
parent.addCDATA(text); parent.addCDATA(text);
} }
else { else {
if (text.trim().length() > 0) { if (text.trim().length() > 0) {
throw new DocumentException("Cannot have text content outside of the root document"); throw new DocumentException("Cannot have text content outside of the root document");
} }
} }
break; break;
} }
case XmlPullParser.ENTITY_REF: { case XmlPullParser.ENTITY_REF: {
String text = pp.getText(); String text = pp.getText();
if (parent != null) { if (parent != null) {
parent.addText(text); parent.addText(text);
} }
else { else {
if (text.trim().length() > 0) { if (text.trim().length() > 0) {
throw new DocumentException("Cannot have an entityref outside of the root document"); throw new DocumentException("Cannot have an entityref outside of the root document");
} }
} }
break; break;
} }
case XmlPullParser.END_DOCUMENT: { case XmlPullParser.END_DOCUMENT: {
return document; return document;
} }
case XmlPullParser.START_TAG: { case XmlPullParser.START_TAG: {
QName qname = (pp.getPrefix() == null) ? df.createQName(pp.getName(), pp.getNamespace()) : df.createQName(pp.getName(), pp.getPrefix(), pp.getNamespace()); QName qname = (pp.getPrefix() == null) ? df.createQName(pp.getName(), pp.getNamespace()) : df.createQName(pp.getName(), pp.getPrefix(), pp.getNamespace());
Element newElement; Element newElement;
// Do not qualify stanza element with certain namespaces. This makes those stanzas re-usable between, // Strip namespace from all default-namespaced elements if
// for example, c2s and s2s. This code prevents such qualification only for elements that have no // all ancestors have the same namespace and it's a content
// default namespace declared // namespace.
final boolean defaultNamespaceDeclared = parent == null || !parent.getNamespaceForPrefix("").getURI().equals(""); boolean dropNamespace = false;
if ( !defaultNamespaceDeclared && IGNORED_NAMESPACE_ON_STANZA.contains( qname.getNamespaceURI() ) ) { System.out.println("* Processing start element {" + pp.getNamespace() + "}" + pp.getName());
newElement = df.createElement(pp.getName()); if (pp.getPrefix() == null && IGNORED_NAMESPACE_ON_STANZA.contains(qname.getNamespaceURI())) {
} System.out.println("Prefix null on element " + qname.getName() + " in ns " + qname.getNamespaceURI());
else { // Default namespaced element which is in a content namespace,
newElement = df.createElement(qname); // so we'll drop. Example, stanzas, <message><body/></message>
} dropNamespace = true;
int nsStart = pp.getNamespaceCount(pp.getDepth() - 1); for (Element el = parent; el != null; el = el.getParent()) {
int nsEnd = pp.getNamespaceCount(pp.getDepth()); final String defaultNS = el.getNamespaceForPrefix("").getURI();
for (int i = nsStart; i < nsEnd; i++) { System.out.println(" Parent defaultNS is " + defaultNS);
final String namespacePrefix = pp.getNamespacePrefix( i ); if (defaultNS.equals("")) {
final String namespaceUri = pp.getNamespaceUri( i ); // We've cleared this one already, just bail.
if ( namespacePrefix != null ) { System.out.println(" --> Stop; dropNS");
newElement.addNamespace( namespacePrefix, namespaceUri ); break;
} else if ( !( pp.getDepth() <= 2 && IGNORED_NAMESPACE_ON_STANZA.contains(namespaceUri) ) ) { }
// Do not include certain default namespace on the root-element ('stream') or stanza level. This makes stanzas re-usable between, for example, c2s and s2s. if (!defaultNS.equals(qname.getNamespaceURI())) {
newElement.addNamespace( "", namespaceUri ); // But if there's an ancestor element, we shouldn't drop
} // after all. Example: forwarded message.
} dropNamespace = false;
for (int i = 0; i < pp.getAttributeCount(); i++) { System.out.println(" --> Stop; NOT dropNS");
QName qa = (pp.getAttributePrefix(i) == null) ? df.createQName(pp.getAttributeName(i)) : df.createQName(pp.getAttributeName(i), pp.getAttributePrefix(i), pp.getAttributeNamespace(i)); break;
newElement.addAttribute(qa, pp.getAttributeValue(i)); }
} }
if (parent != null) { }
parent.add(newElement); if ( dropNamespace ) {
} System.out.println("New element, no namespace");
else { newElement = df.createElement(pp.getName());
document.add(newElement); }
} else {
parent = newElement; System.out.println("New element, with namespace");
count++; newElement = df.createElement(qname);
break; }
} int nsStart = pp.getNamespaceCount(pp.getDepth() - 1);
case XmlPullParser.END_TAG: { int nsEnd = pp.getNamespaceCount(pp.getDepth());
if (parent != null) { for (int i = nsStart; i < nsEnd; i++) {
parent = parent.getParent(); final String namespacePrefix = pp.getNamespacePrefix( i );
} final String namespaceUri = pp.getNamespaceUri( i );
count--; System.out.println("Considering {" + namespacePrefix + "} -> {" + namespaceUri + "}");
if (count < 1) { if ( namespacePrefix != null ) {
// Update the last time a Document was received newElement.addNamespace(namespacePrefix, namespaceUri);
lastActive = System.currentTimeMillis(); System.out.println(" Copying.");
return document; } else if ( parent == null && IGNORED_NAMESPACE_ON_STANZA.contains( namespaceUri ) ) {
} // Don't copy.
break; } else if ( !(dropNamespace && namespaceUri.equals( qname.getNamespaceURI() ) ) ) {
} // Do not include certain default namespace on the root-element ('stream') or stanza level. This makes stanzas re-usable between, for example, c2s and s2s.
case XmlPullParser.TEXT: { newElement.addNamespace( "", namespaceUri );
String text = pp.getText(); System.out.println(" Copying no prefix.");
if (parent != null) { }
parent.addText(text); }
} for (int i = 0; i < pp.getAttributeCount(); i++) {
else { QName qa = (pp.getAttributePrefix(i) == null) ? df.createQName(pp.getAttributeName(i)) : df.createQName(pp.getAttributeName(i), pp.getAttributePrefix(i), pp.getAttributeNamespace(i));
if (text.trim().length() > 0) { newElement.addAttribute(qa, pp.getAttributeValue(i));
throw new DocumentException("Cannot have text content outside of the root document"); }
} if (parent != null) {
} parent.add(newElement);
break; }
} else {
default: document.add(newElement);
{ }
parent = newElement;
} count++;
} break;
} }
} case XmlPullParser.END_TAG: {
if (parent != null) {
protected DispatchHandler getDispatchHandler() { parent = parent.getParent();
if (dispatchHandler == null) { }
dispatchHandler = new DispatchHandler(); count--;
} if (count < 1) {
return dispatchHandler; // Update the last time a Document was received
} lastActive = System.currentTimeMillis();
return document;
protected void setDispatchHandler(DispatchHandler dispatchHandler) { }
this.dispatchHandler = dispatchHandler; break;
} }
case XmlPullParser.TEXT: {
/** String text = pp.getText();
* Factory method to create a Reader from the given InputStream. if (parent != null) {
*/ parent.addText(text);
protected Reader createReader(InputStream in) throws IOException { }
return new BufferedReader(new InputStreamReader(in)); else {
} if (text.trim().length() > 0) {
throw new DocumentException("Cannot have text content outside of the root document");
private Reader createReader(InputStream in, String charSet) throws UnsupportedEncodingException { }
return new BufferedReader(new InputStreamReader(in, charSet)); }
} break;
} }
default:
/* {
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided }
* that the following conditions are met: }
* }
* 1. Redistributions of source code must retain copyright }
* statements and notices. Redistributions must also contain a
* copy of this document. protected DispatchHandler getDispatchHandler() {
* if (dispatchHandler == null) {
* 2. Redistributions in binary form must reproduce the dispatchHandler = new DispatchHandler();
* above copyright notice, this list of conditions and the }
* following disclaimer in the documentation and/or other return dispatchHandler;
* materials provided with the distribution. }
*
* 3. The name "DOM4J" must not be used to endorse or promote protected void setDispatchHandler(DispatchHandler dispatchHandler) {
* products derived from this Software without prior written this.dispatchHandler = dispatchHandler;
* permission of MetaStuff, Ltd. For written permission, }
* please contact dom4j-info@metastuff.com.
* /**
* 4. Products derived from this Software may not be called "DOM4J" * Factory method to create a Reader from the given InputStream.
* nor may "DOM4J" appear in their names without prior written */
* permission of MetaStuff, Ltd. DOM4J is a registered protected Reader createReader(InputStream in) throws IOException {
* trademark of MetaStuff, Ltd. return new BufferedReader(new InputStreamReader(in));
* }
* 5. Due credit should be given to the DOM4J Project -
* http://www.dom4j.org private Reader createReader(InputStream in, String charSet) throws UnsupportedEncodingException {
* return new BufferedReader(new InputStreamReader(in, charSet));
* THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS }
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT }
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL /*
* METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * Redistribution and use of this software and associated documentation
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * ("Software"), with or without modification, are permitted provided
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * that the following conditions are met:
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * 1. Redistributions of source code must retain copyright
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * statements and notices. Redistributions must also contain a
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * copy of this document.
* OF THE POSSIBILITY OF SUCH DAMAGE. *
* * 2. Redistributions in binary form must reproduce the
* Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved. * above copyright notice, this list of conditions and the
* * following disclaimer in the documentation and/or other
*/ * materials provided with the distribution.
*
* 3. The name "DOM4J" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of MetaStuff, Ltd. For written permission,
* please contact dom4j-info@metastuff.com.
*
* 4. Products derived from this Software may not be called "DOM4J"
* nor may "DOM4J" appear in their names without prior written
* permission of MetaStuff, Ltd. DOM4J is a registered
* trademark of MetaStuff, Ltd.
*
* 5. Due credit should be given to the DOM4J Project -
* http://www.dom4j.org
*
* THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
*
*/
...@@ -55,7 +55,9 @@ public class XMPPPacketReaderTest ...@@ -55,7 +55,9 @@ public class XMPPPacketReaderTest
final String input = "<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><body>Art thou not Romeo, and a Montague?</body></message></stream:stream>"; final String input = "<stream:stream to='example.com' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><message from='juliet@example.com' to='romeo@example.net' xml:lang='en'><body>Art thou not Romeo, and a Montague?</body></message></stream:stream>";
// Execute system under test. // Execute system under test.
System.out.println("** " + input);
final Document result = packetReader.read( new StringReader( input ) ); final Document result = packetReader.read( new StringReader( input ) );
System.out.println("** " + result.asXML());
// Verify result. // Verify result.
Assert.assertFalse( result.asXML().contains( "jabber:client" ) ); Assert.assertFalse( result.asXML().contains( "jabber:client" ) );
...@@ -76,7 +78,9 @@ public class XMPPPacketReaderTest ...@@ -76,7 +78,9 @@ public class XMPPPacketReaderTest
final String input = "<stream:stream to='example.com' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><message xmlns='jabber:client' from='juliet@example.com' to='romeo@example.net' xml:lang='en'><body>Art thou not Romeo, and a Montague?</body></message></stream:stream>"; final String input = "<stream:stream to='example.com' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><message xmlns='jabber:client' from='juliet@example.com' to='romeo@example.net' xml:lang='en'><body>Art thou not Romeo, and a Montague?</body></message></stream:stream>";
// Execute system under test. // Execute system under test.
System.out.println("** " + input);
final Document result = packetReader.read( new StringReader( input ) ); final Document result = packetReader.read( new StringReader( input ) );
System.out.println("** " + result.asXML());
// Verify result. // Verify result.
Assert.assertFalse( result.asXML().contains( "jabber:client" ) ); Assert.assertFalse( result.asXML().contains( "jabber:client" ) );
...@@ -105,7 +109,9 @@ public class XMPPPacketReaderTest ...@@ -105,7 +109,9 @@ public class XMPPPacketReaderTest
" </message>" + " </message>" +
"</stream:stream>"; "</stream:stream>";
System.out.println("** " + input);
final Document result = packetReader.read( new StringReader( input ) ); final Document result = packetReader.read( new StringReader( input ) );
System.out.println("** " + result.asXML());
// Verify result. // Verify result.
Assert.assertFalse( "'jabber:client' should not occur before 'something:else'", result.asXML().substring( 0, result.asXML().indexOf("something:else") ).contains( "jabber:client" ) ); Assert.assertFalse( "'jabber:client' should not occur before 'something:else'", result.asXML().substring( 0, result.asXML().indexOf("something:else") ).contains( "jabber:client" ) );
...@@ -135,7 +141,31 @@ public class XMPPPacketReaderTest ...@@ -135,7 +141,31 @@ public class XMPPPacketReaderTest
" </message>" + " </message>" +
"</stream:stream>"; "</stream:stream>";
System.out.println("** " + input);
final Document result = packetReader.read( new StringReader( input ) ); final Document result = packetReader.read( new StringReader( input ) );
System.out.println("** " + result.asXML());
// Verify result.
Assert.assertFalse( "'jabber:client' should not occur before 'something:else'", result.asXML().substring( 0, result.asXML().indexOf("something:else") ).contains( "jabber:client" ) );
Assert.assertTrue( "'jabber:client' should occur after 'something:else'", result.asXML().substring( result.asXML().indexOf("something:else") ).contains( "jabber:client" ) );
}
/**
* Check that a websocket connection woudl also work.
*/
@Test
public void testStripNamespacesForWebsocket() throws Exception
{
final String input_header = "<open xmlns='urn:ietf:params:xml:ns:xmpp-framing' to='example.com' version='1.0' />";
final Document doc_header = packetReader.read( new StringReader( input_header ) );
final String input = " <message xmlns='jabber:client'>" +
" <other xmlns='something:else'>" +
" <message xmlns='jabber:client'/>" +
" </other>" +
" </message>";
System.out.println("** " + input);
final Document result = packetReader.read( new StringReader( input ) );
System.out.println("** " + result.asXML());
// Verify result. // Verify result.
Assert.assertFalse( "'jabber:client' should not occur before 'something:else'", result.asXML().substring( 0, result.asXML().indexOf("something:else") ).contains( "jabber:client" ) ); Assert.assertFalse( "'jabber:client' should not occur before 'something:else'", result.asXML().substring( 0, result.asXML().indexOf("something:else") ).contains( "jabber:client" ) );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment