diff --git a/standard/src/javax/servlet/jsp/jstl/tlv/PageParser.java b/standard/src/javax/servlet/jsp/jstl/tlv/PageParser.java new file mode 100644 index 0000000..29d5f17 --- /dev/null +++ b/standard/src/javax/servlet/jsp/jstl/tlv/PageParser.java @@ -0,0 +1,45 @@ +package javax.servlet.jsp.jstl.tlv; + +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.jsp.tagext.PageData; +import javax.xml.XMLConstants; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.DefaultHandler; + +class PageParser { + private final SAXParserFactory parserFactory; + + PageParser(boolean namespaceAware) throws SAXNotRecognizedException, SAXNotSupportedException, ParserConfigurationException { + parserFactory = SAXParserFactory.newInstance(); + + parserFactory.setNamespaceAware(namespaceAware); + parserFactory.setValidating(false); + try { + parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (SAXNotSupportedException e) { + // FSP is not supported, GCJ? + } + } + + void parse(PageData pageData, DefaultHandler handler) throws ParserConfigurationException, SAXException, IOException { + SAXParser parser = parserFactory.newSAXParser(); + InputStream is = pageData.getInputStream(); + try { + parser.parse(is, handler); + } finally { + try { + is.close(); + } catch (IOException e) { + // Suppress. + } + } + } +} diff --git a/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java b/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java index 4ba23d1..8e42449 100644 --- a/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java +++ b/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java @@ -25,8 +25,6 @@ import javax.servlet.jsp.tagext.PageData; import javax.servlet.jsp.tagext.TagLibraryValidator; import javax.servlet.jsp.tagext.ValidationMessage; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -104,10 +102,8 @@ public class PermittedTaglibsTLV extends TagLibraryValidator { DefaultHandler h = new PermittedTaglibsHandler(); // parse the page - SAXParserFactory f = SAXParserFactory.newInstance(); - f.setValidating(true); - SAXParser p = f.newSAXParser(); - p.parse(page.getInputStream(), h); + PageParser p = new PageParser(false); + p.parse(page, h); if (failed) return vmFromString( diff --git a/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java b/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java index d82b5c1..0bc4c11 100644 --- a/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java +++ b/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java @@ -17,15 +17,12 @@ package javax.servlet.jsp.jstl.tlv; import java.io.IOException; -import java.io.InputStream; import java.util.Map; import javax.servlet.jsp.tagext.PageData; import javax.servlet.jsp.tagext.TagLibraryValidator; import javax.servlet.jsp.tagext.ValidationMessage; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -58,17 +55,12 @@ public class ScriptFreeTLV extends TagLibraryValidator { private boolean allowScriptlets = false; private boolean allowExpressions = false; private boolean allowRTExpressions = false; - private SAXParserFactory factory; + private PageParser parser; /** * Constructs a new validator instance. - * Initializes the parser factory to create non-validating, namespace-aware - * SAX parsers. */ public ScriptFreeTLV () { - factory = SAXParserFactory.newInstance(); - factory.setValidating(false); - factory.setNamespaceAware(true); } /** @@ -102,15 +94,12 @@ public class ScriptFreeTLV extends TagLibraryValidator { */ public ValidationMessage[] validate (String prefix, String uri, PageData page) { - InputStream in = null; - SAXParser parser; MyContentHandler handler = new MyContentHandler(); try { - synchronized (factory) { - parser = factory.newSAXParser(); - } - in = page.getInputStream(); - parser.parse(in, handler); + // Initializes the parser factory to create non-validating, namespace-aware + // SAX parsers. + parser = new PageParser(true); + parser.parse(page, handler); } catch (ParserConfigurationException e) { return vmFromString(e.toString()); @@ -121,9 +110,7 @@ public class ScriptFreeTLV extends TagLibraryValidator { catch (IOException e) { return vmFromString(e.toString()); } - finally { - if (in != null) try { in.close(); } catch (IOException e) {} - } + return handler.reportResults(); } diff --git a/standard/src/org/apache/taglibs/standard/extra/spath/SPathFilter.java b/standard/src/org/apache/taglibs/standard/extra/spath/SPathFilter.java index bead698..c654ca9 100644 --- a/standard/src/org/apache/taglibs/standard/extra/spath/SPathFilter.java +++ b/standard/src/org/apache/taglibs/standard/extra/spath/SPathFilter.java @@ -20,6 +20,9 @@ import java.io.IOException; import java.util.List; import java.util.Stack; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.taglibs.standard.util.XmlUtil; import org.apache.xalan.serialize.Serializer; import org.apache.xalan.serialize.SerializerFactory; import org.apache.xalan.templates.OutputProperties; @@ -29,7 +32,6 @@ import org.xml.sax.SAXException; import org.xml.sax.XMLFilter; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLFilterImpl; -import org.xml.sax.helpers.XMLReaderFactory; /** *

Filters a SAX stream based on a single supplied SPath @@ -70,7 +72,12 @@ System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser"); // construct the appropriate SAX chain // (reader -> us -> serializer) - XMLReader r = XMLReaderFactory.createXMLReader(); + XMLReader r; + try { + r = XmlUtil.newSAXParser().getXMLReader(); + } catch (ParserConfigurationException e) { + throw new SAXException(e); + } XMLFilter f1 = new SPathFilter(p); XMLFilter f2 = new XMLFilterImpl(); f1.setParent(r); diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java index 3bc8a54..7118919 100644 --- a/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java +++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java @@ -28,24 +28,21 @@ import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; -import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.sax.TransformerHandler; import org.apache.taglibs.standard.resources.Resources; import org.apache.taglibs.standard.tag.common.core.ImportSupport; import org.apache.taglibs.standard.tag.common.core.Util; +import org.apache.taglibs.standard.util.XmlUtil; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLFilter; import org.xml.sax.XMLReader; -import org.xml.sax.helpers.XMLReaderFactory; /** *

Support for tag handlers for <parse>, the XML parsing tag.

@@ -70,9 +67,7 @@ public abstract class ParseSupport extends BodyTagSupport { private int scopeDom; // processed 'scopeDom' attr // state in support of XML parsing... - private DocumentBuilderFactory dbf; private DocumentBuilder db; - private TransformerFactory tf; private TransformerHandler th; @@ -89,9 +84,7 @@ public abstract class ParseSupport extends BodyTagSupport { xml = null; systemId = null; filter = null; - dbf = null; db = null; - tf = null; th = null; scope = PageContext.PAGE_SCOPE; scopeDom = PageContext.PAGE_SCOPE; @@ -106,22 +99,13 @@ public abstract class ParseSupport extends BodyTagSupport { try { // set up our DocumentBuilder - if (dbf == null) { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); + if (db == null) { + db = XmlUtil.newDocumentBuilder(); } - db = dbf.newDocumentBuilder(); // if we've gotten a filter, set up a transformer to support it if (filter != null) { - if (tf == null) - tf = TransformerFactory.newInstance(); - if (!tf.getFeature(SAXTransformerFactory.FEATURE)) - throw new JspTagException( - Resources.getMessage("PARSE_NO_SAXTRANSFORMER")); - SAXTransformerFactory stf = (SAXTransformerFactory) tf; - th = stf.newTransformerHandler(); + th = XmlUtil.newTransformerHandler(); } // produce a Document by parsing whatever the attributes tell us to use @@ -172,15 +156,14 @@ public abstract class ParseSupport extends BodyTagSupport { /** Parses the given InputSource after, applying the given XMLFilter. */ private Document parseInputSourceWithFilter(InputSource s, XMLFilter f) - throws SAXException, IOException { + throws SAXException, IOException, ParserConfigurationException { if (f != null) { // prepare an output Document Document o = db.newDocument(); // use TrAX to adapt SAX events to a Document object th.setResult(new DOMResult(o)); - XMLReader xr = XMLReaderFactory.createXMLReader(); - xr.setEntityResolver(new JstlEntityResolver(pageContext)); + XMLReader xr = XmlUtil.newXMLReader(new JstlEntityResolver(pageContext)); // (note that we overwrite the filter's parent. this seems // to be expected usage. we could cache and reset the old // parent, but you can't setParent(null), so this wouldn't @@ -195,20 +178,20 @@ public abstract class ParseSupport extends BodyTagSupport { /** Parses the given Reader after applying the given XMLFilter. */ private Document parseReaderWithFilter(Reader r, XMLFilter f) - throws SAXException, IOException { + throws SAXException, IOException, ParserConfigurationException { return parseInputSourceWithFilter(new InputSource(r), f); } /** Parses the given String after applying the given XMLFilter. */ private Document parseStringWithFilter(String s, XMLFilter f) - throws SAXException, IOException { + throws SAXException, IOException, ParserConfigurationException { StringReader r = new StringReader(s); return parseReaderWithFilter(r, f); } /** Parses the given Reader after applying the given XMLFilter. */ private Document parseURLWithFilter(String url, XMLFilter f) - throws SAXException, IOException { + throws SAXException, IOException, ParserConfigurationException { return parseInputSourceWithFilter(new InputSource(url), f); } @@ -264,8 +247,10 @@ public abstract class ParseSupport extends BodyTagSupport { systemId = systemId.substring(5); // we're only concerned with relative URLs - if (ImportSupport.isAbsoluteUrl(systemId)) - return null; + if (ImportSupport.isAbsoluteUrl(systemId)) { + XmlUtil.checkProtocol(XmlUtil.ALLOWED_PROTOCOLS, systemId); + return null; + } // for relative URLs, load and wrap the resource. // don't bother checking for 'null' since we specifically want diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java index 65d56f5..4751887 100644 --- a/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java +++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java @@ -29,14 +29,12 @@ import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyTagSupport; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.URIResolver; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; @@ -47,12 +45,12 @@ import javax.xml.transform.stream.StreamSource; import org.apache.taglibs.standard.resources.Resources; import org.apache.taglibs.standard.tag.common.core.ImportSupport; import org.apache.taglibs.standard.tag.common.core.Util; +import org.apache.taglibs.standard.util.XmlUtil; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; -import org.xml.sax.helpers.XMLReaderFactory; /** *

Support for tag handlers for <transform>, the XML transformation @@ -77,9 +75,7 @@ public abstract class TransformSupport extends BodyTagSupport { private String var; // 'var' attribute private int scope; // processed 'scope' attr private Transformer t; // actual Transformer - private TransformerFactory tf; // reusable factory private DocumentBuilder db; // reusable factory - private DocumentBuilderFactory dbf; // reusable factory //********************************************************************* @@ -95,7 +91,6 @@ public abstract class TransformSupport extends BodyTagSupport { xmlSystemId = xsltSystemId = null; var = null; result = null; - tf = null; scope = PageContext.PAGE_SCOPE; } @@ -114,18 +109,8 @@ public abstract class TransformSupport extends BodyTagSupport { //************************************ // Initialize - // set up our DocumentBuilderFactory if necessary - if (dbf == null) { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - } if (db == null) - db = dbf.newDocumentBuilder(); - - // set up the TransformerFactory if necessary - if (tf == null) - tf = TransformerFactory.newInstance(); + db = XmlUtil.newDocumentBuilder(); //************************************ // Produce transformer @@ -141,8 +126,8 @@ public abstract class TransformSupport extends BodyTagSupport { throw new JspTagException( Resources.getMessage("TRANSFORM_NO_TRANSFORMER")); } - tf.setURIResolver(new JstlUriResolver(pageContext)); - t = tf.newTransformer(s); + t = XmlUtil.newTransformer(s); + t.setURIResolver(new JstlUriResolver(pageContext)); return EVAL_BODY_BUFFERED; @@ -257,9 +242,7 @@ public abstract class TransformSupport extends BodyTagSupport { } else if (o instanceof Reader) { // explicitly go through SAX to maintain control // over how relative external entities resolve - XMLReader xr = XMLReaderFactory.createXMLReader(); - xr.setEntityResolver( - new ParseSupport.JstlEntityResolver(pageContext)); + XMLReader xr = XmlUtil.newXMLReader(new ParseSupport.JstlEntityResolver(pageContext)); InputSource s = new InputSource((Reader) o); s.setSystemId(wrapSystemId(systemId)); Source result = new SAXSource(xr, s); @@ -340,8 +323,10 @@ public abstract class TransformSupport extends BodyTagSupport { // we're only concerned with relative URLs if (ImportSupport.isAbsoluteUrl(href) - || (base != null && ImportSupport.isAbsoluteUrl(base))) + || (base != null && ImportSupport.isAbsoluteUrl(base))) { + XmlUtil.checkProtocol(XmlUtil.ALLOWED_PROTOCOLS, base); return null; + } // base is relative; remove everything after trailing '/' if (base == null || base.lastIndexOf("/") == -1) diff --git a/standard/src/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java b/standard/src/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java index 9b66d73..20a8c0b 100644 --- a/standard/src/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java +++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/XPathUtil.java @@ -28,10 +28,10 @@ import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.TransformerException; import org.apache.taglibs.standard.resources.Resources; +import org.apache.taglibs.standard.util.XmlUtil; import org.apache.xml.utils.QName; import org.apache.xpath.VariableStack; import org.apache.xpath.XPathContext; @@ -394,18 +394,14 @@ public class XPathUtil { } } - static DocumentBuilderFactory dbf = null; static DocumentBuilder db = null; static Document d = null; static Document getDummyDocument( ) { try { - if ( dbf == null ) { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); + if ( db == null ) { + db = XmlUtil.newDocumentBuilder(); } - db = dbf.newDocumentBuilder(); DOMImplementation dim = db.getDOMImplementation(); d = dim.createDocument("http://java.sun.com/jstl", "dummyroot", null); @@ -419,12 +415,9 @@ public class XPathUtil { static Document getDummyDocumentWithoutRoot( ) { try { - if ( dbf == null ) { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware( true ); - dbf.setValidating( false ); + if ( db == null ) { + db = XmlUtil.newDocumentBuilder(); } - db = dbf.newDocumentBuilder(); d = db.newDocument(); return d; diff --git a/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java b/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java index e2d6092..6f81f89 100644 --- a/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java +++ b/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java @@ -17,6 +17,7 @@ package org.apache.taglibs.standard.tlv; import java.io.IOException; +import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -31,14 +32,15 @@ import javax.servlet.jsp.tagext.TagData; import javax.servlet.jsp.tagext.TagLibraryValidator; import javax.servlet.jsp.tagext.ValidationMessage; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import org.apache.taglibs.standard.lang.support.ExpressionEvaluator; import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager; import org.apache.taglibs.standard.resources.Resources; +import org.apache.taglibs.standard.util.XmlUtil; import org.xml.sax.Attributes; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; /** @@ -149,11 +151,18 @@ public abstract class JstlBaseTLV extends TagLibraryValidator { DefaultHandler h = getHandler(); // parse the page - SAXParserFactory f = SAXParserFactory.newInstance(); - f.setValidating(false); - f.setNamespaceAware(true); - SAXParser p = f.newSAXParser(); - p.parse(page.getInputStream(), h); + XMLReader xmlReader = XmlUtil.newXMLReader(null); + xmlReader.setContentHandler(h); + InputStream inputStream = page.getInputStream(); + try { + xmlReader.parse(new InputSource(inputStream)); + } finally { + try { + inputStream.close(); + } catch (IOException e) { + // Suppressed. + } + } if (messageVector.size() == 0) return null; diff --git a/standard/src/org/apache/taglibs/standard/util/XmlUtil.java b/standard/src/org/apache/taglibs/standard/util/XmlUtil.java new file mode 100644 index 0000000..13ec790 --- /dev/null +++ b/standard/src/org/apache/taglibs/standard/util/XmlUtil.java @@ -0,0 +1,168 @@ +package org.apache.taglibs.standard.util; + +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXTransformerFactory; +import javax.xml.transform.sax.TransformerHandler; + +import org.apache.taglibs.standard.tag.common.xml.ParseSupport.JstlEntityResolver; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +/** + * Utilities for working with JAXP and SAX. + */ +public class XmlUtil { + + /** + * Create a new DocumentBuilder configured for namespaces but not validating. + * + * @return a new, configured DocumentBuilder + * @throws ParserConfigurationException + */ + public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + + dbf.setNamespaceAware(true); + dbf.setValidating(false); + try { + dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + // FSP is not supported, GCJ? + } + return dbf.newDocumentBuilder(); + } + + private static SAXTransformerFactory newTransformerFactory() throws TransformerConfigurationException { + TransformerFactory tf = TransformerFactory.newInstance(); + if (!(tf instanceof SAXTransformerFactory)) { + throw new TransformerConfigurationException("TransformerFactory does not support SAX"); + } + try { + tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (TransformerConfigurationException e) { + // FSP is not supported, GCJ? + } + return (SAXTransformerFactory) tf; + } + + /** + * Create a new TransformerHandler. + * @return a new TransformerHandler + */ + public static TransformerHandler newTransformerHandler() throws TransformerConfigurationException { + return newTransformerFactory().newTransformerHandler(); + } + + /** + * Create a new Transformer from an XSLT. + * @param source the source of the XSLT. + * @return a new Transformer + * @throws TransformerConfigurationException if there was a problem creating the Transformer from the XSLT + */ + public static Transformer newTransformer(Source source) throws TransformerConfigurationException { + Transformer transformer = newTransformerFactory().newTransformer(source); + // Although newTansformer() is not allowed to return null, Xalan does. + // Trap that here by throwing the expected TransformerConfigurationException. + if (transformer == null) { + throw new TransformerConfigurationException("newTransformer returned null. XSLT may be invalid."); + } + return transformer; + } + + /** + * Create an XMLReader that resolves entities using JSTL semantics. + * @param entityResolver for resolving using JSTL semantics + * @return a new XMLReader + * @throws ParserConfigurationException if there was a configuration problem creating the reader + * @throws SAXException if there was a problem creating the reader + */ + public static XMLReader newXMLReader(JstlEntityResolver entityResolver) + throws ParserConfigurationException, SAXException { + + XMLReader xmlReader = newSAXParser().getXMLReader(); + xmlReader.setEntityResolver(entityResolver); + return xmlReader; + } + + /** + * Create a new SAXParser. + * @return a new SAXParser + * @throws ParserConfigurationException if there was a configuration problem creating the reader + * @throws SAXException if there was a problem creating the reader + */ + public static SAXParser newSAXParser() throws ParserConfigurationException, SAXException { + SAXParserFactory spf = SAXParserFactory.newInstance(); + + spf.setNamespaceAware(true); + try { + spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (SAXNotSupportedException e) { + // FSP is not supported, GCJ? + } + return spf.newSAXParser(); + } + + private static final String SP_ALLOWED_PROTOCOLS = "org.apache.taglibs.standard.xml.accessExternalEntity"; + public static final String ALLOWED_PROTOCOLS = initAllowedProtocols(); + + private static String initAllowedProtocols() { + if (System.getSecurityManager() == null) { + return System.getProperty(SP_ALLOWED_PROTOCOLS, "all"); + } else { + final String defaultProtocols = ""; + try { + return (String) AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty(SP_ALLOWED_PROTOCOLS, defaultProtocols); + } + }); + } catch (AccessControlException e) { + // Fall back to the default i.e. none. + return defaultProtocols; + } + } + } + + public static void checkProtocol(String allowedProtocols, String uri) { + if ("all".equalsIgnoreCase(allowedProtocols)) { + return; + } + String protocol = getScheme(uri); + String[] allowed = allowedProtocols.split(","); + for (int i = 0; i < allowed.length; i++) { + if (allowed[i].trim().equalsIgnoreCase(protocol)) { + return; + } + } + throw new AccessControlException("Access to external URI not allowed: " + uri); + } + + private static String getScheme(CharSequence url) { + StringBuilder scheme = new StringBuilder(); + for (int i = 0; i < url.length(); i++) { + char ch = url.charAt(i); + if (ch == ':') { + String result = scheme.toString(); + if (!"jar".equals(result)) { + return result; + } + } + scheme.append(ch); + } + throw new IllegalArgumentException("No scheme found: " + url); + } +}