From e08632136f38ecae3bc68b6984ccd6562c20ed69 Mon Sep 17 00:00:00 2001 From: lingsheng Date: Fri, 19 Jun 2020 15:50:08 +0800 Subject: [PATCH] Fix CVE-2020-10683 --- ...-default-XMLReader-with-its-defaults.patch | 2205 +++++++++++++++++ ...r-features-are-set-when-SAXParser-is.patch | 97 + ...ownloading-external-resources-with-1.patch | 31 + ...ownloading-external-resources-with-2.patch | 30 + dom4j.spec | 9 +- 5 files changed, 2371 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2020-10683-SAXReader-uses-system-default-XMLReader-with-its-defaults.patch create mode 100644 backport-Default-SAXParser-features-are-set-when-SAXParser-is.patch create mode 100644 backport-Disable-downloading-external-resources-with-1.patch create mode 100644 backport-Disable-downloading-external-resources-with-2.patch diff --git a/backport-CVE-2020-10683-SAXReader-uses-system-default-XMLReader-with-its-defaults.patch b/backport-CVE-2020-10683-SAXReader-uses-system-default-XMLReader-with-its-defaults.patch new file mode 100644 index 0000000..623a3c3 --- /dev/null +++ b/backport-CVE-2020-10683-SAXReader-uses-system-default-XMLReader-with-its-defaults.patch @@ -0,0 +1,2205 @@ +From a8228522a99a02146106672a34c104adbda5c658 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Filip=20Jirs=C3=A1k?= +Date: Sat, 11 Apr 2020 19:06:44 +0200 +Subject: [PATCH] SAXReader uses system default XMLReader with its defaults. + New factory method SAXReader.createDefault() sets more secure defaults. + +--- + src/main/java/org/dom4j/DocumentHelper.java | 65 +- + src/main/java/org/dom4j/io/SAXHelper.java | 37 +- + src/main/java/org/dom4j/io/SAXReader.java | 1824 ++++++++++--------- + 3 files changed, 973 insertions(+), 953 deletions(-) + +diff --git a/src/main/java/org/dom4j/DocumentHelper.java b/src/main/java/org/dom4j/DocumentHelper.java +index 6ceed9a3..865a51a1 100644 +--- a/src/main/java/org/dom4j/DocumentHelper.java ++++ b/src/main/java/org/dom4j/DocumentHelper.java +@@ -107,12 +107,12 @@ public static QName createQName(String localName) { + * XPath XPath instance using the singleton {@link + * DocumentFactory}. + *

+- * ++ * + * @param xpathExpression + * is the XPath expression to create +- * ++ * + * @return a new XPath instance +- * ++ * + * @throws InvalidXPathException + * if the XPath expression is invalid + */ +@@ -127,14 +127,14 @@ public static XPath createXPath(String xpathExpression) + * XPath XPath instance using the singleton {@link + * DocumentFactory}. + *

+- * ++ * + * @param xpathExpression + * is the XPath expression to create + * @param context + * is the variable context to use when evaluating the XPath +- * ++ * + * @return a new XPath instance +- * ++ * + * @throws InvalidXPathException + * if the XPath expression is invalid + */ +@@ -150,10 +150,10 @@ public static XPath createXPath(String xpathExpression, + * filter expressions occur within XPath expressions such as + * self::node()[ filterExpression ] + *

+- * ++ * + * @param xpathFilterExpression + * is the XPath filter expression to create +- * ++ * + * @return a new NodeFilter instance + */ + public static NodeFilter createXPathFilter(String xpathFilterExpression) { +@@ -166,10 +166,10 @@ public static NodeFilter createXPathFilter(String xpathFilterExpression) { + * an XSLT style {@link Pattern}instance which can then be used in an XSLT + * processing model. + *

+- * ++ * + * @param xpathPattern + * is the XPath pattern expression to create +- * ++ * + * @return a new Pattern instance + */ + public static Pattern createPattern(String xpathPattern) { +@@ -182,12 +182,12 @@ public static Pattern createPattern(String xpathPattern) { + * {@link List}of {@link Node}instances appending all the results together + * into a single list. + *

+- * ++ * + * @param xpathFilterExpression + * is the XPath filter expression to evaluate + * @param nodes + * is the list of nodes on which to evalute the XPath +- * ++ * + * @return the results of all the XPath evaluations as a single list + */ + public static List selectNodes(String xpathFilterExpression, List nodes) { +@@ -202,12 +202,12 @@ public static Pattern createPattern(String xpathPattern) { + * {@link List}of {@link Node}instances appending all the results together + * into a single list. + *

+- * ++ * + * @param xpathFilterExpression + * is the XPath filter expression to evaluate + * @param node + * is the Node on which to evalute the XPath +- * ++ * + * @return the results of all the XPath evaluations as a single list + */ + public static List selectNodes(String xpathFilterExpression, Node node) { +@@ -221,7 +221,7 @@ public static Pattern createPattern(String xpathPattern) { + * sort sorts the given List of Nodes using an XPath + * expression as a {@link java.util.Comparator}. + *

+- * ++ * + * @param list + * is the list of Nodes to sort + * @param xpathExpression +@@ -238,7 +238,7 @@ public static void sort(List list, String xpathExpression) { + * expression as a {@link java.util.Comparator}and optionally removing + * duplicates. + *

+- * ++ * + * @param list + * is the list of Nodes to sort + * @param expression +@@ -259,24 +259,17 @@ public static void sort(List list, String expression, boolean distinct) { + *

+ * + * Loading external DTD and entities is disabled (if it is possible) for security reasons. +- * ++ * + * @param text + * the XML text to be parsed +- * ++ * + * @return a newly parsed Document +- * ++ * + * @throws DocumentException + * if the document could not be parsed + */ + public static Document parseText(String text) throws DocumentException { +- SAXReader reader = new SAXReader(); +- try { +- reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); +- reader.setFeature("http://xml.org/sax/features/external-general-entities", false); +- reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); +- } catch (SAXException e) { +- //Parse with external resources downloading allowed. +- } ++ SAXReader reader = SAXReader.createDefault(); + + String encoding = getEncoding(text); + +@@ -330,14 +323,14 @@ private static String getEncoding(String text) { + * get the first child <a> element, which would be created if it did + * not exist, then the next child <b> and so on until finally a + * <c> element is returned. +- * ++ * + * @param source + * is the Element or Document to start navigating from + * @param path + * is a simple path expression, seperated by '/' which denotes + * the path from the source to the resulting element such as + * a/b/c +- * ++ * + * @return the first Element on the given path which either already existed + * on the path or were created by this method. + */ +@@ -386,24 +379,24 @@ public static Element makeElement(Branch source, String path) { + * 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. +- * ++ * + * 2. Redistributions in binary form must reproduce the 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 +@@ -415,6 +408,6 @@ public static Element makeElement(Branch source, String path) { + * 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-2005 (C) MetaStuff, Ltd. All Rights Reserved. + */ +diff --git a/src/main/java/org/dom4j/io/SAXHelper.java b/src/main/java/org/dom4j/io/SAXHelper.java +index d204d084..e66905e9 100644 +--- a/src/main/java/org/dom4j/io/SAXHelper.java ++++ b/src/main/java/org/dom4j/io/SAXHelper.java +@@ -13,12 +13,14 @@ + import org.xml.sax.XMLReader; + import org.xml.sax.helpers.XMLReaderFactory; + ++import javax.xml.parsers.SAXParserFactory; ++ + /** + *

+ * SAXHelper contains some helper methods for working with SAX + * and XMLReader objects. + *

+- * ++ * + * @author James Strachan + * @version $Revision: 1.18 $ + */ +@@ -61,12 +63,21 @@ public static boolean setParserFeature(XMLReader reader, + /** + * Creats a default XMLReader via the org.xml.sax.driver system property or + * JAXP if the system property is not set. +- * ++ * ++ * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. ++ * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: ++ * ++ *
++     * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
++     * reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
++     * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
++     * 
++ * + * @param validating + * DOCUMENT ME! +- * ++ * + * @return DOCUMENT ME! +- * ++ * + * @throws SAXException + * DOCUMENT ME! + */ +@@ -125,12 +136,12 @@ public static XMLReader createXMLReader(boolean validating) + * This method attempts to use JAXP to locate the SAX2 XMLReader + * implementation. This method uses reflection to avoid being dependent + * directly on the JAXP classes. +- * ++ * + * @param validating + * DOCUMENT ME! + * @param namespaceAware + * DOCUMENT ME! +- * ++ * + * @return DOCUMENT ME! + */ + protected static XMLReader createXMLReaderViaJAXP(boolean validating, +@@ -176,24 +187,24 @@ protected static boolean isVerboseErrorReporting() { + * 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. +- * ++ * + * 2. Redistributions in binary form must reproduce the 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 +@@ -205,6 +216,6 @@ protected static boolean isVerboseErrorReporting() { + * 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-2005 (C) MetaStuff, Ltd. All Rights Reserved. + */ +diff --git a/src/main/java/org/dom4j/io/SAXReader.java b/src/main/java/org/dom4j/io/SAXReader.java +index 6bb3d926..73660abf 100644 +--- a/src/main/java/org/dom4j/io/SAXReader.java ++++ b/src/main/java/org/dom4j/io/SAXReader.java +@@ -30,32 +30,34 @@ + import org.xml.sax.helpers.DefaultHandler; + import org.xml.sax.helpers.XMLReaderFactory; + ++import javax.xml.parsers.SAXParserFactory; ++ + /** + * SAXReader creates a DOM4J tree from SAX parsing events. +- * ++ *

+ * The actual SAX parser that is used by this class is configurable so you can + * use your favourite SAX parser if you wish. DOM4J comes configured with its + * own SAX parser so you do not need to worry about configuring the SAX parser. +- * ++ *

+ * To explicitly configure the SAX parser that is used via Java code you can use + * a constructor or use the {@link #setXMLReader(XMLReader)}or {@link + * #setXMLReaderClassName(String)} methods. +- * ++ *

+ * If the parser is not specified explicitly then the standard SAX policy of + * using the org.xml.sax.driver system property is used to + * determine the implementation class of {@link XMLReader}. +- * ++ *

+ * If the org.xml.sax.driver system property is not defined then + * JAXP is used via reflection (so that DOM4J is not explicitly dependent on the + * JAXP classes) to load the JAXP configured SAXParser. If there is any error + * creating a JAXP SAXParser an informational message is output and then the + * default (Aelfred) SAX parser is used instead. +- * ++ *

+ * If you are trying to use JAXP to explicitly set your SAX parser and are + * experiencing problems, you can turn on verbose error reporting by defining + * the system property org.dom4j.verbose to be "true" which will + * output a more detailed description of why JAXP could not find a SAX parser +- * ++ *

+ * For more information on JAXP please go to Sun's Java & XML site + * +@@ -63,932 +65,946 @@ + * @version $Revision: 1.58 $ + */ + public class SAXReader { +- private static final String SAX_STRING_INTERNING = +- "http://xml.org/sax/features/string-interning"; +- private static final String SAX_DECL_HANDLER = +- "http://xml.org/sax/properties/declaration-handler"; +- private static final String SAX_LEXICAL_HANDLER = +- "http://xml.org/sax/properties/lexical-handler"; +- private static final String SAX_LEXICALHANDLER = +- "http://xml.org/sax/handlers/LexicalHandler"; +- +- /** DocumentFactory used to create new document objects */ +- private DocumentFactory factory; +- +- /** XMLReader used to parse the SAX events */ +- private XMLReader xmlReader; +- +- /** Whether validation should occur */ +- private boolean validating; +- +- /** DispatchHandler to call when each Element is encountered */ +- private DispatchHandler dispatchHandler; +- +- /** ErrorHandler class to use */ +- private ErrorHandler errorHandler; +- +- /** The entity resolver */ +- private EntityResolver entityResolver; +- +- /** Should element & attribute names and namespace URIs be interned? */ +- private boolean stringInternEnabled = true; +- +- /** Should internal DTD declarations be expanded into a List in the DTD */ +- private boolean includeInternalDTDDeclarations = false; +- +- /** Should external DTD declarations be expanded into a List in the DTD */ +- private boolean includeExternalDTDDeclarations = false; +- +- /** Whether adjacent text nodes should be merged */ +- private boolean mergeAdjacentText = false; +- +- /** Holds value of property stripWhitespaceText. */ +- private boolean stripWhitespaceText = false; +- +- /** Should we ignore comments */ +- private boolean ignoreComments = false; +- +- /** Encoding of InputSource - null means system default encoding */ +- private String encoding = null; +- +- // private boolean includeExternalGeneralEntities = false; +- // private boolean includeExternalParameterEntities = false; +- +- /** The SAX filter used to filter SAX events */ +- private XMLFilter xmlFilter; +- +- public SAXReader() { +- } +- +- public SAXReader(boolean validating) { +- this.validating = validating; +- } +- +- public SAXReader(DocumentFactory factory) { +- this.factory = factory; +- } +- +- public SAXReader(DocumentFactory factory, boolean validating) { +- this.factory = factory; +- this.validating = validating; +- } +- +- public SAXReader(XMLReader xmlReader) { +- this.xmlReader = xmlReader; +- } +- +- public SAXReader(XMLReader xmlReader, boolean validating) { +- this.xmlReader = xmlReader; +- this.validating = validating; +- } +- +- public SAXReader(String xmlReaderClassName) throws SAXException { +- if (xmlReaderClassName != null) { +- this.xmlReader = XMLReaderFactory +- .createXMLReader(xmlReaderClassName); ++ private static final String SAX_STRING_INTERNING = ++ "http://xml.org/sax/features/string-interning"; ++ private static final String SAX_DECL_HANDLER = ++ "http://xml.org/sax/properties/declaration-handler"; ++ private static final String SAX_LEXICAL_HANDLER = ++ "http://xml.org/sax/properties/lexical-handler"; ++ private static final String SAX_LEXICALHANDLER = ++ "http://xml.org/sax/handlers/LexicalHandler"; ++ ++ /** ++ * DocumentFactory used to create new document objects ++ */ ++ private DocumentFactory factory; ++ ++ /** ++ * XMLReader used to parse the SAX events ++ */ ++ private XMLReader xmlReader; ++ ++ /** ++ * Whether validation should occur ++ */ ++ private boolean validating; ++ ++ /** ++ * DispatchHandler to call when each Element is encountered ++ */ ++ private DispatchHandler dispatchHandler; ++ ++ /** ++ * ErrorHandler class to use ++ */ ++ private ErrorHandler errorHandler; ++ ++ /** ++ * The entity resolver ++ */ ++ private EntityResolver entityResolver; ++ ++ /** ++ * Should element & attribute names and namespace URIs be interned? ++ */ ++ private boolean stringInternEnabled = true; ++ ++ /** ++ * Should internal DTD declarations be expanded into a List in the DTD ++ */ ++ private boolean includeInternalDTDDeclarations = false; ++ ++ /** ++ * Should external DTD declarations be expanded into a List in the DTD ++ */ ++ private boolean includeExternalDTDDeclarations = false; ++ ++ /** ++ * Whether adjacent text nodes should be merged ++ */ ++ private boolean mergeAdjacentText = false; ++ ++ /** ++ * Holds value of property stripWhitespaceText. ++ */ ++ private boolean stripWhitespaceText = false; ++ ++ /** ++ * Should we ignore comments ++ */ ++ private boolean ignoreComments = false; ++ ++ /** ++ * Encoding of InputSource - null means system default encoding ++ */ ++ private String encoding = null; ++ ++ // private boolean includeExternalGeneralEntities = false; ++ // private boolean includeExternalParameterEntities = false; ++ ++ /** ++ * The SAX filter used to filter SAX events ++ * ++ * @since 2.1.2 ++ */ ++ private XMLFilter xmlFilter; ++ ++ public static SAXReader createDefault() { ++ SAXReader reader = new SAXReader(); ++ try { ++ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); ++ reader.setFeature("http://xml.org/sax/features/external-general-entities", false); ++ reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); ++ } catch (SAXException e) { ++ // nothing to do, incompatible reader ++ } ++ return reader; ++ } ++ ++ /** ++ * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. ++ * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: ++ * ++ *

++   * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
++   * reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
++   * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
++   * 
++ */ ++ public SAXReader() { ++ } ++ ++ /** ++ * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. ++ * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: ++ * ++ *
++   * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
++   * reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
++   * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
++   * 
++ * ++ * @param validating ++ */ ++ public SAXReader(boolean validating) { ++ this.validating = validating; ++ } ++ ++ /** ++ * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. ++ * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: ++ * ++ *
++   * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
++   * reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
++   * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
++   * 
++ * ++ * @param factory ++ */ ++ public SAXReader(DocumentFactory factory) { ++ this.factory = factory; ++ } ++ ++ /** ++ * This method internally calls {@link SAXParserFactory}{@code .newInstance().newSAXParser().getXMLReader()} or {@link XMLReaderFactory#createXMLReader()}. ++ * Be sure to configure returned reader if the default configuration does not suit you. Consider setting the following properties: ++ * ++ *
++   * reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
++   * reader.setFeature("http://xml.org/sax/features/external-general-entities", false);
++   * reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
++   * 
++ * ++ * @param factory ++ * @param validating ++ */ ++ public SAXReader(DocumentFactory factory, boolean validating) { ++ this.factory = factory; ++ this.validating = validating; ++ } ++ ++ public SAXReader(XMLReader xmlReader) { ++ this.xmlReader = xmlReader; ++ } ++ ++ public SAXReader(XMLReader xmlReader, boolean validating) { ++ this.xmlReader = xmlReader; ++ this.validating = validating; ++ } ++ ++ public SAXReader(String xmlReaderClassName) throws SAXException { ++ if (xmlReaderClassName != null) { ++ this.xmlReader = XMLReaderFactory ++ .createXMLReader(xmlReaderClassName); ++ } ++ } ++ ++ public SAXReader(String xmlReaderClassName, boolean validating) ++ throws SAXException { ++ if (xmlReaderClassName != null) { ++ this.xmlReader = XMLReaderFactory ++ .createXMLReader(xmlReaderClassName); ++ } ++ ++ this.validating = validating; ++ } ++ ++ /** ++ * Allows a SAX property to be set on the underlying SAX parser. This can be ++ * useful to set parser-specific properties such as the location of schema ++ * or DTD resources. Though use this method with caution as it has the ++ * possibility of breaking the standard behaviour. An alternative to calling ++ * this method is to correctly configure an XMLReader object instance and ++ * call the {@link #setXMLReader(XMLReader)}method ++ * ++ * @param name is the SAX property name ++ * @param value is the value of the SAX property ++ * @throws SAXException if the XMLReader could not be created or the property could ++ * not be changed. ++ */ ++ public void setProperty(String name, Object value) throws SAXException { ++ getXMLReader().setProperty(name, value); ++ } ++ ++ /** ++ * Sets a SAX feature on the underlying SAX parser. This can be useful to ++ * set parser-specific features. Though use this method with caution as it ++ * has the possibility of breaking the standard behaviour. An alternative to ++ * calling this method is to correctly configure an XMLReader object ++ * instance and call the {@link #setXMLReader(XMLReader)}method ++ * ++ * @param name is the SAX feature name ++ * @param value is the value of the SAX feature ++ * @throws SAXException if the XMLReader could not be created or the feature could ++ * not be changed. ++ */ ++ public void setFeature(String name, boolean value) throws SAXException { ++ getXMLReader().setFeature(name, value); ++ } ++ ++ /** ++ *

++ * Reads a Document from the given File ++ *

++ * ++ * @param file is the File to read from. ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(File file) throws DocumentException { ++ try { ++ /* ++ * We cannot convert the file to an URL because if the filename ++ * contains '#' characters, there will be problems with the URL in ++ * the InputSource (because a URL like ++ * http://myhost.com/index#anchor is treated the same as ++ * http://myhost.com/index) Thanks to Christian Oetterli ++ */ ++ InputSource source = new InputSource(new FileInputStream(file)); ++ if (this.encoding != null) { ++ source.setEncoding(this.encoding); ++ } ++ String path = file.getAbsolutePath(); ++ ++ if (path != null) { ++ // Code taken from Ant FileUtils ++ StringBuffer sb = new StringBuffer("file://"); ++ ++ // add an extra slash for filesystems with drive-specifiers ++ if (!path.startsWith(File.separator)) { ++ sb.append("/"); + } +- } + +- public SAXReader(String xmlReaderClassName, boolean validating) +- throws SAXException { +- if (xmlReaderClassName != null) { +- this.xmlReader = XMLReaderFactory +- .createXMLReader(xmlReaderClassName); ++ path = path.replace('\\', '/'); ++ sb.append(path); ++ ++ source.setSystemId(sb.toString()); ++ } ++ ++ return read(source); ++ } catch (FileNotFoundException e) { ++ throw new DocumentException(e.getMessage(), e); ++ } ++ } ++ ++ /** ++ *

++ * Reads a Document from the given URL using SAX ++ *

++ * ++ * @param url URL to read from. ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(URL url) throws DocumentException { ++ String systemID = url.toExternalForm(); ++ ++ InputSource source = new InputSource(systemID); ++ if (this.encoding != null) { ++ source.setEncoding(this.encoding); ++ } ++ ++ return read(source); ++ } ++ ++ /** ++ *

++ * Reads a Document from the given URL or filename using SAX. ++ *

++ * ++ *

++ * If the systemId contains a ':' character then it is ++ * assumed to be a URL otherwise its assumed to be a file name. If you want ++ * finer grained control over this mechansim then please explicitly pass in ++ * either a {@link URL}or a {@link File}instance instead of a {@link ++ * String} to denote the source of the document. ++ *

++ * ++ * @param systemId is a URL for a document or a file name. ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(String systemId) throws DocumentException { ++ InputSource source = new InputSource(systemId); ++ if (this.encoding != null) { ++ source.setEncoding(this.encoding); ++ } ++ ++ return read(source); ++ } ++ ++ /** ++ *

++ * Reads a Document from the given stream using SAX ++ *

++ * ++ * @param in InputStream to read from. ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(InputStream in) throws DocumentException { ++ InputSource source = new InputSource(in); ++ if (this.encoding != null) { ++ source.setEncoding(this.encoding); ++ } ++ ++ return read(source); ++ } ++ ++ /** ++ * Reads a Document from the given Reader using SAX ++ * ++ * @param reader is the reader for the input ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(Reader reader) throws DocumentException { ++ InputSource source = new InputSource(reader); ++ if (this.encoding != null) { ++ source.setEncoding(this.encoding); ++ } ++ ++ return read(source); ++ } ++ ++ /** ++ *

++ * Reads a Document from the given stream using SAX ++ *

++ * ++ * @param in InputStream to read from. ++ * @param systemId is the URI for the input ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(InputStream in, String systemId) ++ throws DocumentException { ++ InputSource source = new InputSource(in); ++ source.setSystemId(systemId); ++ if (this.encoding != null) { ++ source.setEncoding(this.encoding); ++ } ++ ++ return read(source); ++ } ++ ++ /** ++ *

++ * Reads a Document from the given Reader using SAX ++ *

++ * ++ * @param reader is the reader for the input ++ * @param systemId is the URI for the input ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(Reader reader, String systemId) ++ throws DocumentException { ++ InputSource source = new InputSource(reader); ++ source.setSystemId(systemId); ++ if (this.encoding != null) { ++ source.setEncoding(this.encoding); ++ } ++ ++ return read(source); ++ } ++ ++ /** ++ *

++ * Reads a Document from the given InputSource using SAX ++ *

++ * ++ * @param in InputSource to read from. ++ * @return the newly created Document instance ++ * @throws DocumentException if an error occurs during parsing. ++ */ ++ public Document read(InputSource in) throws DocumentException { ++ try { ++ XMLReader reader = getXMLReader(); ++ ++ reader = installXMLFilter(reader); ++ ++ EntityResolver thatEntityResolver = this.entityResolver; ++ ++ if (thatEntityResolver == null) { ++ thatEntityResolver = createDefaultEntityResolver(in ++ .getSystemId()); ++ this.entityResolver = thatEntityResolver; ++ } ++ ++ reader.setEntityResolver(thatEntityResolver); ++ ++ SAXContentHandler contentHandler = createContentHandler(reader); ++ contentHandler.setEntityResolver(thatEntityResolver); ++ contentHandler.setInputSource(in); ++ ++ boolean internal = isIncludeInternalDTDDeclarations(); ++ boolean external = isIncludeExternalDTDDeclarations(); ++ ++ contentHandler.setIncludeInternalDTDDeclarations(internal); ++ contentHandler.setIncludeExternalDTDDeclarations(external); ++ contentHandler.setMergeAdjacentText(isMergeAdjacentText()); ++ contentHandler.setStripWhitespaceText(isStripWhitespaceText()); ++ contentHandler.setIgnoreComments(isIgnoreComments()); ++ reader.setContentHandler(contentHandler); ++ ++ configureReader(reader, contentHandler); ++ ++ reader.parse(in); ++ ++ return contentHandler.getDocument(); ++ } catch (Exception e) { ++ if (e instanceof SAXParseException) { ++ // e.printStackTrace(); ++ SAXParseException parseException = (SAXParseException) e; ++ String systemId = parseException.getSystemId(); ++ ++ if (systemId == null) { ++ systemId = ""; + } + +- this.validating = validating; +- } +- +- /** +- * Allows a SAX property to be set on the underlying SAX parser. This can be +- * useful to set parser-specific properties such as the location of schema +- * or DTD resources. Though use this method with caution as it has the +- * possibility of breaking the standard behaviour. An alternative to calling +- * this method is to correctly configure an XMLReader object instance and +- * call the {@link #setXMLReader(XMLReader)}method +- * +- * @param name +- * is the SAX property name +- * @param value +- * is the value of the SAX property +- * +- * @throws SAXException +- * if the XMLReader could not be created or the property could +- * not be changed. +- */ +- public void setProperty(String name, Object value) throws SAXException { +- getXMLReader().setProperty(name, value); +- } +- +- /** +- * Sets a SAX feature on the underlying SAX parser. This can be useful to +- * set parser-specific features. Though use this method with caution as it +- * has the possibility of breaking the standard behaviour. An alternative to +- * calling this method is to correctly configure an XMLReader object +- * instance and call the {@link #setXMLReader(XMLReader)}method +- * +- * @param name +- * is the SAX feature name +- * @param value +- * is the value of the SAX feature +- * +- * @throws SAXException +- * if the XMLReader could not be created or the feature could +- * not be changed. +- */ +- public void setFeature(String name, boolean value) throws SAXException { +- getXMLReader().setFeature(name, value); +- } +- +- /** +- *

+- * Reads a Document from the given File +- *

+- * +- * @param file +- * is the File to read from. +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(File file) throws DocumentException { +- try { +- /* +- * We cannot convert the file to an URL because if the filename +- * contains '#' characters, there will be problems with the URL in +- * the InputSource (because a URL like +- * http://myhost.com/index#anchor is treated the same as +- * http://myhost.com/index) Thanks to Christian Oetterli +- */ +- InputSource source = new InputSource(new FileInputStream(file)); +- if (this.encoding != null) { +- source.setEncoding(this.encoding); +- } +- String path = file.getAbsolutePath(); +- +- if (path != null) { +- // Code taken from Ant FileUtils +- StringBuffer sb = new StringBuffer("file://"); +- +- // add an extra slash for filesystems with drive-specifiers +- if (!path.startsWith(File.separator)) { +- sb.append("/"); +- } +- +- path = path.replace('\\', '/'); +- sb.append(path); +- +- source.setSystemId(sb.toString()); +- } +- +- return read(source); +- } catch (FileNotFoundException e) { +- throw new DocumentException(e.getMessage(), e); ++ String message = "Error on line " ++ + parseException.getLineNumber() + " of document " ++ + systemId + " : " + parseException.getMessage(); ++ ++ throw new DocumentException(message, e); ++ } else { ++ throw new DocumentException(e.getMessage(), e); ++ } ++ } ++ } ++ ++ // Properties ++ // ------------------------------------------------------------------------- ++ ++ /** ++ * DOCUMENT ME! ++ * ++ * @return the validation mode, true if validating will be done otherwise ++ * false. ++ */ ++ public boolean isValidating() { ++ return validating; ++ } ++ ++ /** ++ * Sets the validation mode. ++ * ++ * @param validation indicates whether or not validation should occur. ++ */ ++ public void setValidation(boolean validation) { ++ this.validating = validation; ++ } ++ ++ /** ++ * DOCUMENT ME! ++ * ++ * @return whether internal DTD declarations should be expanded into the ++ * DocumentType object or not. ++ */ ++ public boolean isIncludeInternalDTDDeclarations() { ++ return includeInternalDTDDeclarations; ++ } ++ ++ /** ++ * Sets whether internal DTD declarations should be expanded into the ++ * DocumentType object or not. ++ * ++ * @param include whether or not DTD declarations should be expanded and ++ * included into the DocumentType object. ++ */ ++ public void setIncludeInternalDTDDeclarations(boolean include) { ++ this.includeInternalDTDDeclarations = include; ++ } ++ ++ /** ++ * DOCUMENT ME! ++ * ++ * @return whether external DTD declarations should be expanded into the ++ * DocumentType object or not. ++ */ ++ public boolean isIncludeExternalDTDDeclarations() { ++ return includeExternalDTDDeclarations; ++ } ++ ++ /** ++ * Sets whether DTD external declarations should be expanded into the ++ * DocumentType object or not. ++ * ++ * @param include whether or not DTD declarations should be expanded and ++ * included into the DocumentType object. ++ */ ++ public void setIncludeExternalDTDDeclarations(boolean include) { ++ this.includeExternalDTDDeclarations = include; ++ } ++ ++ /** ++ * Sets whether String interning is enabled or disabled for element & ++ * attribute names and namespace URIs. This proprety is enabled by default. ++ * ++ * @return DOCUMENT ME! ++ */ ++ public boolean isStringInternEnabled() { ++ return stringInternEnabled; ++ } ++ ++ /** ++ * Sets whether String interning is enabled or disabled for element & ++ * attribute names and namespace URIs ++ * ++ * @param stringInternEnabled DOCUMENT ME! ++ */ ++ public void setStringInternEnabled(boolean stringInternEnabled) { ++ this.stringInternEnabled = stringInternEnabled; ++ } ++ ++ /** ++ * Returns whether adjacent text nodes should be merged together. ++ * ++ * @return Value of property mergeAdjacentText. ++ */ ++ public boolean isMergeAdjacentText() { ++ return mergeAdjacentText; ++ } ++ ++ /** ++ * Sets whether or not adjacent text nodes should be merged together when ++ * parsing. ++ * ++ * @param mergeAdjacentText New value of property mergeAdjacentText. ++ */ ++ public void setMergeAdjacentText(boolean mergeAdjacentText) { ++ this.mergeAdjacentText = mergeAdjacentText; ++ } ++ ++ /** ++ * Sets whether whitespace between element start and end tags should be ++ * ignored ++ * ++ * @return Value of property stripWhitespaceText. ++ */ ++ public boolean isStripWhitespaceText() { ++ return stripWhitespaceText; ++ } ++ ++ /** ++ * Sets whether whitespace between element start and end tags should be ++ * ignored. ++ * ++ * @param stripWhitespaceText New value of property stripWhitespaceText. ++ */ ++ public void setStripWhitespaceText(boolean stripWhitespaceText) { ++ this.stripWhitespaceText = stripWhitespaceText; ++ } ++ ++ /** ++ * Returns whether we should ignore comments or not. ++ * ++ * @return boolean ++ */ ++ public boolean isIgnoreComments() { ++ return ignoreComments; ++ } ++ ++ /** ++ * Sets whether we should ignore comments or not. ++ * ++ * @param ignoreComments whether we should ignore comments or not. ++ */ ++ public void setIgnoreComments(boolean ignoreComments) { ++ this.ignoreComments = ignoreComments; ++ } ++ ++ /** ++ * DOCUMENT ME! ++ * ++ * @return the DocumentFactory used to create document ++ * objects ++ */ ++ public DocumentFactory getDocumentFactory() { ++ if (factory == null) { ++ factory = DocumentFactory.getInstance(); ++ } ++ ++ return factory; ++ } ++ ++ /** ++ *

++ * This sets the DocumentFactory used to create new ++ * documents. This method allows the building of custom DOM4J tree objects ++ * to be implemented easily using a custom derivation of ++ * {@link DocumentFactory} ++ *

++ * ++ * @param documentFactory DocumentFactory used to create DOM4J objects ++ */ ++ public void setDocumentFactory(DocumentFactory documentFactory) { ++ this.factory = documentFactory; ++ } ++ ++ /** ++ * DOCUMENT ME! ++ * ++ * @return the ErrorHandler used by SAX ++ */ ++ public ErrorHandler getErrorHandler() { ++ return errorHandler; ++ } ++ ++ /** ++ * Sets the ErrorHandler used by the SAX ++ * XMLReader. ++ * ++ * @param errorHandler is the ErrorHandler used by SAX ++ */ ++ public void setErrorHandler(ErrorHandler errorHandler) { ++ this.errorHandler = errorHandler; ++ } ++ ++ /** ++ * Returns the current entity resolver used to resolve entities ++ * ++ * @return DOCUMENT ME! ++ */ ++ public EntityResolver getEntityResolver() { ++ return entityResolver; ++ } ++ ++ /** ++ * Sets the entity resolver used to resolve entities. ++ * ++ * @param entityResolver DOCUMENT ME! ++ */ ++ public void setEntityResolver(EntityResolver entityResolver) { ++ this.entityResolver = entityResolver; ++ } ++ ++ /** ++ * DOCUMENT ME! ++ * ++ * @return the XMLReader used to parse SAX events ++ * @throws SAXException DOCUMENT ME! ++ */ ++ public XMLReader getXMLReader() throws SAXException { ++ if (xmlReader == null) { ++ xmlReader = createXMLReader(); ++ } ++ ++ return xmlReader; ++ } ++ ++ /** ++ * Sets the XMLReader used to parse SAX events ++ * ++ * @param reader is the XMLReader to parse SAX events ++ */ ++ public void setXMLReader(XMLReader reader) { ++ this.xmlReader = reader; ++ } ++ ++ /** ++ * Returns encoding used for InputSource (null means system default ++ * encoding) ++ * ++ * @return encoding used for InputSource ++ */ ++ public String getEncoding() { ++ return encoding; ++ } ++ ++ /** ++ * Sets encoding used for InputSource (null means system default encoding) ++ * ++ * @param encoding is encoding used for InputSource ++ */ ++ public void setEncoding(String encoding) { ++ this.encoding = encoding; ++ } ++ ++ /** ++ * Sets the class name of the XMLReader to be used to parse ++ * SAX events. ++ * ++ * @param xmlReaderClassName is the class name of the XMLReader to parse SAX ++ * events ++ * @throws SAXException DOCUMENT ME! ++ */ ++ public void setXMLReaderClassName(String xmlReaderClassName) ++ throws SAXException { ++ setXMLReader(XMLReaderFactory.createXMLReader(xmlReaderClassName)); ++ } ++ ++ /** ++ * Adds the ElementHandler to be called when the specified ++ * path is encounted. ++ * ++ * @param path is the path to be handled ++ * @param handler is the ElementHandler to be called by the event ++ * based processor. ++ */ ++ public void addHandler(String path, ElementHandler handler) { ++ getDispatchHandler().addHandler(path, handler); ++ } ++ ++ /** ++ * Removes the ElementHandler from the event based processor, ++ * for the specified path. ++ * ++ * @param path is the path to remove the ElementHandler for. ++ */ ++ public void removeHandler(String path) { ++ getDispatchHandler().removeHandler(path); ++ } ++ ++ /** ++ * When multiple ElementHandler instances have been ++ * registered, this will set a default ElementHandler to be ++ * called for any path which does NOT have a handler registered. ++ * ++ * @param handler is the ElementHandler to be called by the event ++ * based processor. ++ */ ++ public void setDefaultHandler(ElementHandler handler) { ++ getDispatchHandler().setDefaultHandler(handler); ++ } ++ ++ /** ++ * This method clears out all the existing handlers and default handler ++ * setting things back as if no handler existed. Useful when reusing an ++ * object instance. ++ */ ++ public void resetHandlers() { ++ getDispatchHandler().resetHandlers(); ++ } ++ ++ /** ++ * Returns the SAX filter being used to filter SAX events. ++ * ++ * @return the SAX filter being used or null if no SAX filter is installed ++ */ ++ public XMLFilter getXMLFilter() { ++ return xmlFilter; ++ } ++ ++ /** ++ * Sets the SAX filter to be used when filtering SAX events ++ * ++ * @param filter is the SAX filter to use or null to disable filtering ++ */ ++ public void setXMLFilter(XMLFilter filter) { ++ this.xmlFilter = filter; ++ } ++ ++ // Implementation methods ++ // ------------------------------------------------------------------------- ++ ++ /** ++ * Installs any XMLFilter objects required to allow the SAX event stream to ++ * be filtered and preprocessed before it gets to dom4j. ++ * ++ * @param reader DOCUMENT ME! ++ * @return the new XMLFilter if applicable or the original XMLReader if no ++ * filter is being used. ++ */ ++ protected XMLReader installXMLFilter(XMLReader reader) { ++ XMLFilter filter = getXMLFilter(); ++ ++ if (filter != null) { ++ // find the root XMLFilter ++ XMLFilter root = filter; ++ ++ while (true) { ++ XMLReader parent = root.getParent(); ++ ++ if (parent instanceof XMLFilter) { ++ root = (XMLFilter) parent; ++ } else { ++ break; + } ++ } ++ ++ root.setParent(reader); ++ ++ return filter; + } + +- /** +- *

+- * Reads a Document from the given URL using SAX +- *

+- * +- * @param url +- * URL to read from. +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(URL url) throws DocumentException { +- String systemID = url.toExternalForm(); +- +- InputSource source = new InputSource(systemID); +- if (this.encoding != null) { +- source.setEncoding(this.encoding); +- } ++ return reader; ++ } + +- return read(source); +- } +- +- /** +- *

+- * Reads a Document from the given URL or filename using SAX. +- *

+- * +- *

+- * If the systemId contains a ':' character then it is +- * assumed to be a URL otherwise its assumed to be a file name. If you want +- * finer grained control over this mechansim then please explicitly pass in +- * either a {@link URL}or a {@link File}instance instead of a {@link +- * String} to denote the source of the document. +- *

+- * +- * @param systemId +- * is a URL for a document or a file name. +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(String systemId) throws DocumentException { +- InputSource source = new InputSource(systemId); +- if (this.encoding != null) { +- source.setEncoding(this.encoding); +- } +- +- return read(source); +- } +- +- /** +- *

+- * Reads a Document from the given stream using SAX +- *

+- * +- * @param in +- * InputStream to read from. +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(InputStream in) throws DocumentException { +- InputSource source = new InputSource(in); +- if (this.encoding != null) { +- source.setEncoding(this.encoding); +- } +- +- return read(source); +- } +- +- /** +- * Reads a Document from the given Reader using SAX +- * +- * @param reader +- * is the reader for the input +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(Reader reader) throws DocumentException { +- InputSource source = new InputSource(reader); +- if (this.encoding != null) { +- source.setEncoding(this.encoding); +- } +- +- return read(source); +- } +- +- /** +- *

+- * Reads a Document from the given stream using SAX +- *

+- * +- * @param in +- * InputStream to read from. +- * @param systemId +- * is the URI for the input +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(InputStream in, String systemId) +- throws DocumentException { +- InputSource source = new InputSource(in); +- source.setSystemId(systemId); +- if (this.encoding != null) { +- source.setEncoding(this.encoding); +- } +- +- return read(source); +- } +- +- /** +- *

+- * Reads a Document from the given Reader using SAX +- *

+- * +- * @param reader +- * is the reader for the input +- * @param systemId +- * is the URI for the input +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(Reader reader, String systemId) +- throws DocumentException { +- InputSource source = new InputSource(reader); +- source.setSystemId(systemId); +- if (this.encoding != null) { +- source.setEncoding(this.encoding); +- } +- +- return read(source); +- } +- +- /** +- *

+- * Reads a Document from the given InputSource using SAX +- *

+- * +- * @param in +- * InputSource to read from. +- * +- * @return the newly created Document instance +- * +- * @throws DocumentException +- * if an error occurs during parsing. +- */ +- public Document read(InputSource in) throws DocumentException { +- try { +- XMLReader reader = getXMLReader(); +- +- reader = installXMLFilter(reader); +- +- EntityResolver thatEntityResolver = this.entityResolver; +- +- if (thatEntityResolver == null) { +- thatEntityResolver = createDefaultEntityResolver(in +- .getSystemId()); +- this.entityResolver = thatEntityResolver; +- } +- +- reader.setEntityResolver(thatEntityResolver); +- +- SAXContentHandler contentHandler = createContentHandler(reader); +- contentHandler.setEntityResolver(thatEntityResolver); +- contentHandler.setInputSource(in); +- +- boolean internal = isIncludeInternalDTDDeclarations(); +- boolean external = isIncludeExternalDTDDeclarations(); +- +- contentHandler.setIncludeInternalDTDDeclarations(internal); +- contentHandler.setIncludeExternalDTDDeclarations(external); +- contentHandler.setMergeAdjacentText(isMergeAdjacentText()); +- contentHandler.setStripWhitespaceText(isStripWhitespaceText()); +- contentHandler.setIgnoreComments(isIgnoreComments()); +- reader.setContentHandler(contentHandler); +- +- configureReader(reader, contentHandler); +- +- reader.parse(in); +- +- return contentHandler.getDocument(); +- } catch (Exception e) { +- if (e instanceof SAXParseException) { +- // e.printStackTrace(); +- SAXParseException parseException = (SAXParseException) e; +- String systemId = parseException.getSystemId(); +- +- if (systemId == null) { +- systemId = ""; +- } +- +- String message = "Error on line " +- + parseException.getLineNumber() + " of document " +- + systemId + " : " + parseException.getMessage(); +- +- throw new DocumentException(message, e); +- } else { +- throw new DocumentException(e.getMessage(), e); +- } ++ protected DispatchHandler getDispatchHandler() { ++ if (dispatchHandler == null) { ++ dispatchHandler = new DispatchHandler(); ++ } ++ ++ return dispatchHandler; ++ } ++ ++ protected void setDispatchHandler(DispatchHandler dispatchHandler) { ++ this.dispatchHandler = dispatchHandler; ++ } ++ ++ /** ++ * Factory Method to allow alternate methods of creating and configuring ++ * XMLReader objects ++ * ++ * @return DOCUMENT ME! ++ * @throws SAXException DOCUMENT ME! ++ */ ++ protected XMLReader createXMLReader() throws SAXException { ++ return SAXHelper.createXMLReader(isValidating()); ++ } ++ ++ /** ++ * Configures the XMLReader before use ++ * ++ * @param reader DOCUMENT ME! ++ * @param handler DOCUMENT ME! ++ * @throws DocumentException DOCUMENT ME! ++ */ ++ protected void configureReader(XMLReader reader, DefaultHandler handler) ++ throws DocumentException { ++ // configure lexical handling ++ SAXHelper.setParserProperty(reader, SAX_LEXICALHANDLER, handler); ++ ++ // try alternate property just in case ++ SAXHelper.setParserProperty(reader, SAX_LEXICAL_HANDLER, handler); ++ ++ // register the DeclHandler ++ if (includeInternalDTDDeclarations || includeExternalDTDDeclarations) { ++ SAXHelper.setParserProperty(reader, SAX_DECL_HANDLER, handler); ++ } ++ ++ // string interning ++ SAXHelper.setParserFeature(reader, SAX_STRING_INTERNING, ++ isStringInternEnabled()); ++ ++ try { ++ // configure validation support ++ reader.setFeature("http://xml.org/sax/features/validation", ++ isValidating()); ++ ++ if (errorHandler != null) { ++ reader.setErrorHandler(errorHandler); ++ } else { ++ reader.setErrorHandler(handler); ++ } ++ } catch (Exception e) { ++ if (isValidating()) { ++ throw new DocumentException("Validation not supported for" ++ + " XMLReader: " + reader, e); ++ } ++ } ++ } ++ ++ /** ++ * Factory Method to allow user derived SAXContentHandler objects to be used ++ * ++ * @param reader DOCUMENT ME! ++ * @return DOCUMENT ME! ++ */ ++ protected SAXContentHandler createContentHandler(XMLReader reader) { ++ return new SAXContentHandler(getDocumentFactory(), dispatchHandler); ++ } ++ ++ protected EntityResolver createDefaultEntityResolver(String systemId) { ++ String prefix = null; ++ ++ if ((systemId != null) && (systemId.length() > 0)) { ++ int idx = systemId.lastIndexOf('/'); ++ ++ if (idx > 0) { ++ prefix = systemId.substring(0, idx + 1); ++ } ++ } ++ ++ return new SAXEntityResolver(prefix); ++ } ++ ++ protected static class SAXEntityResolver implements EntityResolver, ++ Serializable { ++ protected String uriPrefix; ++ ++ public SAXEntityResolver(String uriPrefix) { ++ this.uriPrefix = uriPrefix; ++ } ++ ++ public InputSource resolveEntity(String publicId, String systemId) { ++ // try create a relative URI reader... ++ if ((systemId != null) && (systemId.length() > 0)) { ++ if ((uriPrefix != null) && (systemId.indexOf(':') <= 0)) { ++ systemId = uriPrefix + systemId; + } +- } +- +- // Properties +- // ------------------------------------------------------------------------- +- +- /** +- * DOCUMENT ME! +- * +- * @return the validation mode, true if validating will be done otherwise +- * false. +- */ +- public boolean isValidating() { +- return validating; +- } +- +- /** +- * Sets the validation mode. +- * +- * @param validation +- * indicates whether or not validation should occur. +- */ +- public void setValidation(boolean validation) { +- this.validating = validation; +- } ++ } + +- /** +- * DOCUMENT ME! +- * +- * @return whether internal DTD declarations should be expanded into the +- * DocumentType object or not. +- */ +- public boolean isIncludeInternalDTDDeclarations() { +- return includeInternalDTDDeclarations; +- } +- +- /** +- * Sets whether internal DTD declarations should be expanded into the +- * DocumentType object or not. +- * +- * @param include +- * whether or not DTD declarations should be expanded and +- * included into the DocumentType object. +- */ +- public void setIncludeInternalDTDDeclarations(boolean include) { +- this.includeInternalDTDDeclarations = include; +- } +- +- /** +- * DOCUMENT ME! +- * +- * @return whether external DTD declarations should be expanded into the +- * DocumentType object or not. +- */ +- public boolean isIncludeExternalDTDDeclarations() { +- return includeExternalDTDDeclarations; +- } +- +- /** +- * Sets whether DTD external declarations should be expanded into the +- * DocumentType object or not. +- * +- * @param include +- * whether or not DTD declarations should be expanded and +- * included into the DocumentType object. +- */ +- public void setIncludeExternalDTDDeclarations(boolean include) { +- this.includeExternalDTDDeclarations = include; +- } +- +- /** +- * Sets whether String interning is enabled or disabled for element & +- * attribute names and namespace URIs. This proprety is enabled by default. +- * +- * @return DOCUMENT ME! +- */ +- public boolean isStringInternEnabled() { +- return stringInternEnabled; +- } +- +- /** +- * Sets whether String interning is enabled or disabled for element & +- * attribute names and namespace URIs +- * +- * @param stringInternEnabled +- * DOCUMENT ME! +- */ +- public void setStringInternEnabled(boolean stringInternEnabled) { +- this.stringInternEnabled = stringInternEnabled; +- } +- +- /** +- * Returns whether adjacent text nodes should be merged together. +- * +- * @return Value of property mergeAdjacentText. +- */ +- public boolean isMergeAdjacentText() { +- return mergeAdjacentText; +- } +- +- /** +- * Sets whether or not adjacent text nodes should be merged together when +- * parsing. +- * +- * @param mergeAdjacentText +- * New value of property mergeAdjacentText. +- */ +- public void setMergeAdjacentText(boolean mergeAdjacentText) { +- this.mergeAdjacentText = mergeAdjacentText; +- } +- +- /** +- * Sets whether whitespace between element start and end tags should be +- * ignored +- * +- * @return Value of property stripWhitespaceText. +- */ +- public boolean isStripWhitespaceText() { +- return stripWhitespaceText; +- } +- +- /** +- * Sets whether whitespace between element start and end tags should be +- * ignored. +- * +- * @param stripWhitespaceText +- * New value of property stripWhitespaceText. +- */ +- public void setStripWhitespaceText(boolean stripWhitespaceText) { +- this.stripWhitespaceText = stripWhitespaceText; +- } +- +- /** +- * Returns whether we should ignore comments or not. +- * +- * @return boolean +- */ +- public boolean isIgnoreComments() { +- return ignoreComments; +- } +- +- /** +- * Sets whether we should ignore comments or not. +- * +- * @param ignoreComments +- * whether we should ignore comments or not. +- */ +- public void setIgnoreComments(boolean ignoreComments) { +- this.ignoreComments = ignoreComments; +- } +- +- /** +- * DOCUMENT ME! +- * +- * @return the DocumentFactory used to create document +- * objects +- */ +- public DocumentFactory getDocumentFactory() { +- if (factory == null) { +- factory = DocumentFactory.getInstance(); +- } +- +- return factory; +- } +- +- /** +- *

+- * This sets the DocumentFactory used to create new +- * documents. This method allows the building of custom DOM4J tree objects +- * to be implemented easily using a custom derivation of +- * {@link DocumentFactory} +- *

+- * +- * @param documentFactory +- * DocumentFactory used to create DOM4J objects +- */ +- public void setDocumentFactory(DocumentFactory documentFactory) { +- this.factory = documentFactory; +- } +- +- /** +- * DOCUMENT ME! +- * +- * @return the ErrorHandler used by SAX +- */ +- public ErrorHandler getErrorHandler() { +- return errorHandler; +- } +- +- /** +- * Sets the ErrorHandler used by the SAX +- * XMLReader. +- * +- * @param errorHandler +- * is the ErrorHandler used by SAX +- */ +- public void setErrorHandler(ErrorHandler errorHandler) { +- this.errorHandler = errorHandler; +- } +- +- /** +- * Returns the current entity resolver used to resolve entities +- * +- * @return DOCUMENT ME! +- */ +- public EntityResolver getEntityResolver() { +- return entityResolver; +- } +- +- /** +- * Sets the entity resolver used to resolve entities. +- * +- * @param entityResolver +- * DOCUMENT ME! +- */ +- public void setEntityResolver(EntityResolver entityResolver) { +- this.entityResolver = entityResolver; +- } +- +- /** +- * DOCUMENT ME! +- * +- * @return the XMLReader used to parse SAX events +- * +- * @throws SAXException +- * DOCUMENT ME! +- */ +- public XMLReader getXMLReader() throws SAXException { +- if (xmlReader == null) { +- xmlReader = createXMLReader(); +- } +- +- return xmlReader; +- } +- +- /** +- * Sets the XMLReader used to parse SAX events +- * +- * @param reader +- * is the XMLReader to parse SAX events +- */ +- public void setXMLReader(XMLReader reader) { +- this.xmlReader = reader; +- } +- +- /** +- * Returns encoding used for InputSource (null means system default +- * encoding) +- * +- * @return encoding used for InputSource +- * +- */ +- public String getEncoding() { +- return encoding; +- } +- +- /** +- * Sets encoding used for InputSource (null means system default encoding) +- * +- * @param encoding +- * is encoding used for InputSource +- */ +- public void setEncoding(String encoding) { +- this.encoding = encoding; +- } +- +- /** +- * Sets the class name of the XMLReader to be used to parse +- * SAX events. +- * +- * @param xmlReaderClassName +- * is the class name of the XMLReader to parse SAX +- * events +- * +- * @throws SAXException +- * DOCUMENT ME! +- */ +- public void setXMLReaderClassName(String xmlReaderClassName) +- throws SAXException { +- setXMLReader(XMLReaderFactory.createXMLReader(xmlReaderClassName)); +- } +- +- /** +- * Adds the ElementHandler to be called when the specified +- * path is encounted. +- * +- * @param path +- * is the path to be handled +- * @param handler +- * is the ElementHandler to be called by the event +- * based processor. +- */ +- public void addHandler(String path, ElementHandler handler) { +- getDispatchHandler().addHandler(path, handler); +- } +- +- /** +- * Removes the ElementHandler from the event based processor, +- * for the specified path. +- * +- * @param path +- * is the path to remove the ElementHandler for. +- */ +- public void removeHandler(String path) { +- getDispatchHandler().removeHandler(path); +- } +- +- /** +- * When multiple ElementHandler instances have been +- * registered, this will set a default ElementHandler to be +- * called for any path which does NOT have a handler registered. +- * +- * @param handler +- * is the ElementHandler to be called by the event +- * based processor. +- */ +- public void setDefaultHandler(ElementHandler handler) { +- getDispatchHandler().setDefaultHandler(handler); +- } +- +- /** +- * This method clears out all the existing handlers and default handler +- * setting things back as if no handler existed. Useful when reusing an +- * object instance. +- */ +- public void resetHandlers() { +- getDispatchHandler().resetHandlers(); +- } +- +- /** +- * Returns the SAX filter being used to filter SAX events. +- * +- * @return the SAX filter being used or null if no SAX filter is installed +- */ +- public XMLFilter getXMLFilter() { +- return xmlFilter; +- } +- +- /** +- * Sets the SAX filter to be used when filtering SAX events +- * +- * @param filter +- * is the SAX filter to use or null to disable filtering +- */ +- public void setXMLFilter(XMLFilter filter) { +- this.xmlFilter = filter; +- } +- +- // Implementation methods +- // ------------------------------------------------------------------------- +- +- /** +- * Installs any XMLFilter objects required to allow the SAX event stream to +- * be filtered and preprocessed before it gets to dom4j. +- * +- * @param reader +- * DOCUMENT ME! +- * +- * @return the new XMLFilter if applicable or the original XMLReader if no +- * filter is being used. +- */ +- protected XMLReader installXMLFilter(XMLReader reader) { +- XMLFilter filter = getXMLFilter(); +- +- if (filter != null) { +- // find the root XMLFilter +- XMLFilter root = filter; +- +- while (true) { +- XMLReader parent = root.getParent(); +- +- if (parent instanceof XMLFilter) { +- root = (XMLFilter) parent; +- } else { +- break; +- } +- } +- +- root.setParent(reader); +- +- return filter; +- } +- +- return reader; +- } +- +- protected DispatchHandler getDispatchHandler() { +- if (dispatchHandler == null) { +- dispatchHandler = new DispatchHandler(); +- } +- +- return dispatchHandler; +- } +- +- protected void setDispatchHandler(DispatchHandler dispatchHandler) { +- this.dispatchHandler = dispatchHandler; +- } +- +- /** +- * Factory Method to allow alternate methods of creating and configuring +- * XMLReader objects +- * +- * @return DOCUMENT ME! +- * +- * @throws SAXException +- * DOCUMENT ME! +- */ +- protected XMLReader createXMLReader() throws SAXException { +- return SAXHelper.createXMLReader(isValidating()); +- } +- +- /** +- * Configures the XMLReader before use +- * +- * @param reader +- * DOCUMENT ME! +- * @param handler +- * DOCUMENT ME! +- * +- * @throws DocumentException +- * DOCUMENT ME! +- */ +- protected void configureReader(XMLReader reader, DefaultHandler handler) +- throws DocumentException { +- // configure lexical handling +- SAXHelper.setParserProperty(reader, SAX_LEXICALHANDLER, handler); +- +- // try alternate property just in case +- SAXHelper.setParserProperty(reader, SAX_LEXICAL_HANDLER, handler); +- +- // register the DeclHandler +- if (includeInternalDTDDeclarations || includeExternalDTDDeclarations) { +- SAXHelper.setParserProperty(reader, SAX_DECL_HANDLER, handler); +- } +- +- // string interning +- SAXHelper.setParserFeature(reader, SAX_STRING_INTERNING, +- isStringInternEnabled()); +- +- try { +- // configure validation support +- reader.setFeature("http://xml.org/sax/features/validation", +- isValidating()); +- +- if (errorHandler != null) { +- reader.setErrorHandler(errorHandler); +- } else { +- reader.setErrorHandler(handler); +- } +- } catch (Exception e) { +- if (isValidating()) { +- throw new DocumentException("Validation not supported for" +- + " XMLReader: " + reader, e); +- } +- } +- } +- +- /** +- * Factory Method to allow user derived SAXContentHandler objects to be used +- * +- * @param reader +- * DOCUMENT ME! +- * +- * @return DOCUMENT ME! +- */ +- protected SAXContentHandler createContentHandler(XMLReader reader) { +- return new SAXContentHandler(getDocumentFactory(), dispatchHandler); +- } +- +- protected EntityResolver createDefaultEntityResolver(String systemId) { +- String prefix = null; +- +- if ((systemId != null) && (systemId.length() > 0)) { +- int idx = systemId.lastIndexOf('/'); +- +- if (idx > 0) { +- prefix = systemId.substring(0, idx + 1); +- } +- } +- +- return new SAXEntityResolver(prefix); +- } +- +- protected static class SAXEntityResolver implements EntityResolver, +- Serializable { +- protected String uriPrefix; +- +- public SAXEntityResolver(String uriPrefix) { +- this.uriPrefix = uriPrefix; +- } +- +- public InputSource resolveEntity(String publicId, String systemId) { +- // try create a relative URI reader... +- if ((systemId != null) && (systemId.length() > 0)) { +- if ((uriPrefix != null) && (systemId.indexOf(':') <= 0)) { +- systemId = uriPrefix + systemId; +- } +- } +- +- return new InputSource(systemId); +- } ++ return new InputSource(systemId); + } ++ } + } + + /* + * 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. +- * ++ * + * 2. Redistributions in binary form must reproduce the 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 +@@ -1000,6 +1016,6 @@ public InputSource resolveEntity(String publicId, String systemId) { + * 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-2005 (C) MetaStuff, Ltd. All Rights Reserved. + */ diff --git a/backport-Default-SAXParser-features-are-set-when-SAXParser-is.patch b/backport-Default-SAXParser-features-are-set-when-SAXParser-is.patch new file mode 100644 index 0000000..4bc44aa --- /dev/null +++ b/backport-Default-SAXParser-features-are-set-when-SAXParser-is.patch @@ -0,0 +1,97 @@ +From a16aaa7a192f5e5258dd941cb6a4344c1ca80839 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Filip=20Jirs=C3=A1k?= +Date: Sun, 1 Jul 2018 13:20:26 +0200 +Subject: [PATCH] #44 Default SAXParser features are set when SAXParser is + created, so they can be overriden. + +(cherry picked from commit 161078a8a520dcd1db6d451190f2434d56547664) +--- + src/main/java/org/dom4j/io/SAXHelper.java | 15 +++++++++++++++ + src/main/java/org/dom4j/io/SAXReader.java | 23 +---------------------- + src/test/java/org/dom4j/io/DTDTest.java | 2 ++ + 3 files changed, 18 insertions(+), 22 deletions(-) + +diff --git a/src/main/java/org/dom4j/io/SAXHelper.java b/src/main/java/org/dom4j/io/SAXHelper.java +index 0810a90c..f120337f 100644 +--- a/src/main/java/org/dom4j/io/SAXHelper.java ++++ b/src/main/java/org/dom4j/io/SAXHelper.java +@@ -103,6 +103,21 @@ public static XMLReader createXMLReader(boolean validating) + throw new SAXException("Couldn't create SAX reader"); + } + ++ // configure namespace support ++ SAXHelper.setParserFeature(reader, "http://xml.org/sax/features/namespaces", true); ++ SAXHelper.setParserFeature(reader, "http://xml.org/sax/features/namespace-prefixes", false); ++ ++ // external entites ++// SAXHelper.setParserFeature(reader, "http://xml.org/sax/properties/external-general-entities", false); ++// SAXHelper.setParserFeature(reader, "http://xml.org/sax/properties/external-parameter-entities", false); ++ ++ // external DTD ++ SAXHelper.setParserFeature(reader,"http://apache.org/xml/features/nonvalidating/load-external-dtd", false); ++ ++ ++ // use Locator2 if possible ++ SAXHelper.setParserFeature(reader,"http://xml.org/sax/features/use-locator2", true); ++ + return reader; + } + +diff --git a/src/main/java/org/dom4j/io/SAXReader.java b/src/main/java/org/dom4j/io/SAXReader.java +index 23559e49..6bb3d926 100644 +--- a/src/main/java/org/dom4j/io/SAXReader.java ++++ b/src/main/java/org/dom4j/io/SAXReader.java +@@ -65,11 +65,7 @@ + public class SAXReader { + private static final String SAX_STRING_INTERNING = + "http://xml.org/sax/features/string-interning"; +- private static final String SAX_NAMESPACE_PREFIXES = +- "http://xml.org/sax/features/namespace-prefixes"; +- private static final String SAX_NAMESPACES = +- "http://xml.org/sax/features/namespaces"; +- private static final String SAX_DECL_HANDLER = ++ private static final String SAX_DECL_HANDLER = + "http://xml.org/sax/properties/declaration-handler"; + private static final String SAX_LEXICAL_HANDLER = + "http://xml.org/sax/properties/lexical-handler"; +@@ -902,27 +898,10 @@ protected void configureReader(XMLReader reader, DefaultHandler handler) + SAXHelper.setParserProperty(reader, SAX_DECL_HANDLER, handler); + } + +- // configure namespace support +- SAXHelper.setParserFeature(reader, SAX_NAMESPACES, true); +- +- SAXHelper.setParserFeature(reader, SAX_NAMESPACE_PREFIXES, false); +- + // string interning + SAXHelper.setParserFeature(reader, SAX_STRING_INTERNING, + isStringInternEnabled()); + +- // external entites +- /* +- * SAXHelper.setParserFeature( reader, +- * "http://xml.org/sax/properties/external-general-entities", +- * includeExternalGeneralEntities ); SAXHelper.setParserFeature( reader, +- * "http://xml.org/sax/properties/external-parameter-entities", +- * includeExternalParameterEntities ); +- */ +- // use Locator2 if possible +- SAXHelper.setParserFeature(reader, +- "http://xml.org/sax/features/use-locator2", true); +- + try { + // configure validation support + reader.setFeature("http://xml.org/sax/features/validation", +diff --git a/src/test/java/org/dom4j/io/DTDTest.java b/src/test/java/org/dom4j/io/DTDTest.java +index ff77e4be..1c432328 100644 +--- a/src/test/java/org/dom4j/io/DTDTest.java ++++ b/src/test/java/org/dom4j/io/DTDTest.java +@@ -445,6 +445,8 @@ protected Document readDocument(String resourceName, + reader.setEntityResolver(new MyEntityResolver(DTD_FILE, + DTD_PUBLICID, DTD_SYSTEM_ID)); + ++ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", true); ++ + return getDocument(resourceName, reader); + } + diff --git a/backport-Disable-downloading-external-resources-with-1.patch b/backport-Disable-downloading-external-resources-with-1.patch new file mode 100644 index 0000000..284448c --- /dev/null +++ b/backport-Disable-downloading-external-resources-with-1.patch @@ -0,0 +1,31 @@ +From c8d112e458799721d0c78959bc591b90e2f8d199 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Filip=20Jirs=C3=A1k?= +Date: Sun, 1 Jul 2018 12:45:33 +0200 +Subject: [PATCH] #28 Disable downloading external resources with + DocumentHelper.parseText() helper. + +(cherry picked from commit 8f6a7f6001d679176c1079ac65871d4e493360db) +--- + src/main/java/org/dom4j/DocumentHelper.java | 3 +++ + +diff --git a/src/main/java/org/dom4j/DocumentHelper.java b/src/main/java/org/dom4j/DocumentHelper.java +index 26569e2d..a3a69dca 100644 +--- a/src/main/java/org/dom4j/DocumentHelper.java ++++ b/src/main/java/org/dom4j/DocumentHelper.java +@@ -18,6 +18,7 @@ + import org.jaxen.VariableContext; + + import org.xml.sax.InputSource; ++import org.xml.sax.SAXException; + + /** + * DocumentHelper is a collection of helper methods for using +@@ -256,6 +257,8 @@ public static void sort(List list, String expression, boolean distinct) { + * parseText parses the given text as an XML document and + * returns the newly created Document. + *

++ * ++ * Loading external DTD and entities is disabled (if it is possible) for security reasons. + * + * @param text + * the XML text to be parsed diff --git a/backport-Disable-downloading-external-resources-with-2.patch b/backport-Disable-downloading-external-resources-with-2.patch new file mode 100644 index 0000000..bfab3c2 --- /dev/null +++ b/backport-Disable-downloading-external-resources-with-2.patch @@ -0,0 +1,30 @@ +From 1707bf3d898a8ada3b213acb0e3b38f16eaae73d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Filip=20Jirs=C3=A1k?= +Date: Sat, 11 Apr 2020 19:27:36 +0200 +Subject: [PATCH] #28 Disable downloading external resources with + DocumentHelper.parseText() helper. + +(cherry picked from commit 8f6a7f6001d679176c1079ac65871d4e493360db) +--- + src/main/java/org/dom4j/DocumentHelper.java | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/main/java/org/dom4j/DocumentHelper.java b/src/main/java/org/dom4j/DocumentHelper.java +index a3a69dca..6ceed9a3 100644 +--- a/src/main/java/org/dom4j/DocumentHelper.java ++++ b/src/main/java/org/dom4j/DocumentHelper.java +@@ -270,6 +270,14 @@ public static void sort(List list, String expression, boolean distinct) { + */ + public static Document parseText(String text) throws DocumentException { + SAXReader reader = new SAXReader(); ++ try { ++ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); ++ reader.setFeature("http://xml.org/sax/features/external-general-entities", false); ++ reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); ++ } catch (SAXException e) { ++ //Parse with external resources downloading allowed. ++ } ++ + String encoding = getEncoding(text); + + InputSource source = new InputSource(new StringReader(text)); diff --git a/dom4j.spec b/dom4j.spec index 06f287e..cc07ae6 100644 --- a/dom4j.spec +++ b/dom4j.spec @@ -1,6 +1,6 @@ Name: dom4j Version: 2.0.0 -Release: 7 +Release: 8 Summary: Flexible XML framework for Java License: BSD URL: https://dom4j.github.io/ @@ -8,6 +8,10 @@ Source0: https://github.com/%{name}/%{name}/archive/v%{version}.tar.gz Source1: https://repo1.maven.org/maven2/org/%{name}/%{name}/%{version}/%{name}-%{version}.pom Patch6000: CVE-2018-1000632-pre.patch Patch6001: CVE-2018-1000632.patch +Patch6002: backport-Disable-downloading-external-resources-with-1.patch +Patch6003: backport-Disable-downloading-external-resources-with-2.patch +Patch6004: backport-Default-SAXParser-features-are-set-when-SAXParser-is.patch +Patch6005: backport-CVE-2020-10683-SAXReader-uses-system-default-XMLReader-with-its-defaults.patch BuildArch: noarch BuildRequires: maven-local, mvn(jaxen:jaxen), mvn(net.java.dev.msv:xsdlib), mvn(xpp3:xpp3), mvn(javax.xml.bind:jaxb-api) @@ -48,5 +52,8 @@ rm -rf src/test/java/org/dom4j/util/PerThreadSingletonTest.java %{_javadocdir}/%{name}/* %changelog +* Fri Jun 19 2020 lingsheng - 2.0.0-8 +- Fix CVE-2020-10683 + * Fri Dec 13 2019 openEuler Buildteam - 2.0.0-7 - Package init