From 9a05c75ad28ebad4abbe624fa432664c59763747 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 6 Jul 2023 16:32:49 -0500 Subject: [PATCH] Issue #10066 - Allow customization of `SAXParserFactory` and `SAXParser` in `XmlParser` (#10067) * Allow customization of SAXParserFactory / SAXParser in XmlParser * Introduce method `.getSAXParser()` --------- Signed-off-by: Joakim Erdfelt Co-authored-by: Greg Wilkins --- .../java/org/eclipse/jetty/xml/XmlParser.java | 14 ++++++-- .../org/eclipse/jetty/xml/XmlParserTest.java | 35 +++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java index 33c142481ec..ea8a3a4485a 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java @@ -66,7 +66,7 @@ public class XmlParser */ public XmlParser() { - SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParserFactory factory = newSAXParserFactory(); boolean validatingDefault = factory.getClass().toString().contains("org.apache.xerces."); String validatingProp = System.getProperty("org.eclipse.jetty.xml.XmlParser.Validating", validatingDefault ? "true" : "false"); boolean validating = Boolean.valueOf(validatingProp).booleanValue(); @@ -83,11 +83,16 @@ public class XmlParser return _lock.lock(); } + protected SAXParserFactory newSAXParserFactory() + { + return SAXParserFactory.newInstance(); + } + public void setValidating(boolean validating) { try { - SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParserFactory factory = newSAXParserFactory(); factory.setValidating(validating); _parser = factory.newSAXParser(); @@ -129,6 +134,11 @@ public class XmlParser return _parser.isValidating(); } + public SAXParser getSAXParser() + { + return _parser; + } + public void redirectEntity(String name, URL entity) { if (entity != null) diff --git a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java index 764bd522441..00ae93a1e31 100644 --- a/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java +++ b/jetty-xml/src/test/java/org/eclipse/jetty/xml/XmlParserTest.java @@ -14,10 +14,17 @@ package org.eclipse.jetty.xml; import java.net.URL; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import org.junit.jupiter.api.Test; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; public class XmlParserTest { @@ -38,4 +45,32 @@ public class XmlParserTest assertTrue(testDocStr.startsWith("")); } + + /** + * Customize SAXParserFactory behavior. + */ + @Test + public void testNewSAXParserFactory() throws SAXException + { + XmlParser xmlParser = new XmlParser() + { + @Override + protected SAXParserFactory newSAXParserFactory() + { + SAXParserFactory saxParserFactory = super.newSAXParserFactory(); + // Configure at factory level + saxParserFactory.setXIncludeAware(false); + return saxParserFactory; + } + }; + + SAXParser saxParser = xmlParser.getSAXParser(); + assertNotNull(saxParser); + + XMLReader xmlReader = saxParser.getXMLReader(); + // Only run testcase if Xerces is being used. + assumeTrue(xmlReader.getClass().getName().contains("org.apache.xerces.")); + // look to see it was set at XMLReader level + assertFalse(xmlReader.getFeature("http://apache.org/xml/features/xinclude")); + } }