Blame SOURCES/CVE-2015-0254.patch

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

Filters a SAX stream based on a single supplied SPath

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

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

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

Support for tag handlers for <transform>, the XML transformation

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