[taglibs-standard] 07/12: Removed CVE-2015-0254.patch (fixed upstream)

Emmanuel Bourg ebourg-guest at moszumanska.debian.org
Tue Jul 26 09:31:21 UTC 2016


This is an automated email from the git hooks/post-receive script.

ebourg-guest pushed a commit to branch master
in repository taglibs-standard.

commit 3aebde786ab0604f6b9bb0ee31891b1e25aa7c99
Author: Emmanuel Bourg <ebourg at apache.org>
Date:   Wed Jul 20 17:29:38 2016 +0200

    Removed CVE-2015-0254.patch (fixed upstream)
---
 debian/changelog                   |    4 +-
 debian/patches/CVE-2015-0254.patch | 2239 ------------------------------------
 debian/patches/series              |    1 -
 3 files changed, 3 insertions(+), 2241 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index e657db6..43b51c0 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,8 @@
-taglibs-standard (1.1.2-5) UNRELEASED; urgency=medium
+taglibs-standard (1.2.5-1) UNRELEASED; urgency=medium
 
   * Team upload.
+  * New upstream release
+    - Removed CVE-2015-0254.patch (fixed upstream)
   * Renamed the package to taglibs-standard
   * Standards-Version updated to 3.9.8
   * Updated debian/watch to track the releases >= 1.2
diff --git a/debian/patches/CVE-2015-0254.patch b/debian/patches/CVE-2015-0254.patch
deleted file mode 100644
index fe46e41..0000000
--- a/debian/patches/CVE-2015-0254.patch
+++ /dev/null
@@ -1,2239 +0,0 @@
-Description: Fix CVE-2015-0254 XXE and RCE via XSL extension in JSTL XML tags
- When an application uses <x:parse> or <x:transform> tags to process
- untrusted XML documents, a request may utilize external entity
- references to access resources on the host system or utilize XSLT
- extensions that may allow remote execution. For more information, just go
- to: http://www.securityfocus.com/archive/1/534772.
-Author: The Apache Software Foundation
-Bug-Debian: https://bugs.debian.org/779621
-Origin: upstream, http://svn.apache.org/r1642442, http://svn.apache.org/r1642613
-Forwarded: not-needed
-Last-Update: 2015-03-14
-
---- /dev/null
-+++ b/standard/src/javax/servlet/jsp/jstl/tlv/ParserUtil.java
-@@ -0,0 +1,86 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements.  See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License.  You may obtain a copy of the License at
-+ *
-+ *      http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package javax.servlet.jsp.jstl.tlv;
-+
-+import java.io.IOException;
-+import java.io.InputStream;
-+import java.security.AccessController;
-+import java.security.PrivilegedAction;
-+
-+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;
-+
-+/**
-+ * Support class for working with the SAX Parser.
-+ */
-+class ParserUtil {
-+
-+    private static final SAXParserFactory PARSER_FACTORY;
-+    static {
-+        PARSER_FACTORY = AccessController.doPrivileged(new PrivilegedAction<SAXParserFactory>() {
-+            public SAXParserFactory run() {
-+                ClassLoader original = Thread.currentThread().getContextClassLoader();
-+                ClassLoader ours = ParserUtil.class.getClassLoader();
-+                try {
-+                    if (original != ours) {
-+                        Thread.currentThread().setContextClassLoader(ours);
-+                    }
-+                    return SAXParserFactory.newInstance();
-+                } finally {
-+                    if (original != ours) {
-+                        Thread.currentThread().setContextClassLoader(original);
-+                    }
-+                }
-+            }
-+        });
-+        try {
-+            PARSER_FACTORY.setValidating(true);
-+            PARSER_FACTORY.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-+        } catch (ParserConfigurationException e) {
-+            throw new ExceptionInInitializerError(e);
-+        } catch (SAXNotRecognizedException e) {
-+            throw new ExceptionInInitializerError(e);
-+        } catch (SAXNotSupportedException e) {
-+            throw new ExceptionInInitializerError(e);
-+        }
-+    }
-+
-+    private ParserUtil() {
-+    }
-+
-+    static void parse(PageData pageData, DefaultHandler handler) throws ParserConfigurationException, SAXException, IOException {
-+        SAXParser parser = PARSER_FACTORY.newSAXParser();
-+        InputStream is = pageData.getInputStream();
-+        try {
-+            parser.parse(is, handler);
-+        } finally {
-+            try {
-+                is.close();
-+            } catch (IOException e) {
-+                // Suppress.
-+            }
-+        }
-+    }
-+}
---- a/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java
-+++ b/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java
-@@ -17,6 +17,7 @@
- package javax.servlet.jsp.jstl.tlv;
- 
- import java.io.IOException;
-+import java.io.InputStream;
- import java.util.HashSet;
- import java.util.Set;
- import java.util.StringTokenizer;
-@@ -92,8 +93,7 @@
-     //*********************************************************************
-     // Validation entry point
- 
--    public synchronized ValidationMessage[] validate(
--	    String prefix, String uri, PageData page) {
-+    public synchronized ValidationMessage[] validate(String prefix, String uri, PageData page) {
- 	try {
- 
- 	    // initialize
-@@ -104,10 +104,7 @@
- 	    DefaultHandler h = new PermittedTaglibsHandler();
- 
- 	    // parse the page
--	    SAXParserFactory f = SAXParserFactory.newInstance();
--	    f.setValidating(true);
--	    SAXParser p = f.newSAXParser();
--	    p.parse(page.getInputStream(), h);
-+	    ParserUtil.parse(page, h);
- 
- 	    if (failed)
- 		return vmFromString(
---- a/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java
-+++ b/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java
-@@ -24,7 +24,6 @@
- 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;
-@@ -100,32 +99,19 @@
-    * @return null, if the page is valid; otherwise, a ValidationMessage[]
-    * containing one or more messages indicating why the page is not valid.
-    */
--  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);
-+    public ValidationMessage[] validate(String prefix, String uri, PageData page) {
-+        try {
-+            MyContentHandler handler = new MyContentHandler();
-+            ParserUtil.parse(page, handler);
-+            return handler.reportResults();
-+        } catch (ParserConfigurationException e) {
-+            return vmFromString(e.toString());
-+        } catch (SAXException e) {
-+            return vmFromString(e.toString());
-+        } catch (IOException e) {
-+            return vmFromString(e.toString());
-+        }
-     }
--    catch (ParserConfigurationException e) {
--      return vmFromString(e.toString());
--    }
--    catch (SAXException e) {
--      return vmFromString(e.toString());
--    }
--    catch (IOException e) {
--      return vmFromString(e.toString());
--    }
--    finally {
--      if (in != null) try { in.close(); } catch (IOException e) {}
--    }
--    return handler.reportResults();
--  }
- 
-   /** 
-    * Handler for SAX events. 
---- a/standard/src/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/ImportSupport.java
-@@ -45,6 +45,7 @@
- import javax.servlet.jsp.tagext.TryCatchFinally;
- 
- import org.apache.taglibs.standard.resources.Resources;
-+import org.apache.taglibs.standard.util.UrlUtil;
- 
- /**
-  * <p>Support for tag handlers for <import>, the general-purpose
-@@ -60,22 +61,6 @@
-     //*********************************************************************
-     // Public constants
-     
--    /** <p>Valid characters in a scheme.</p>
--     *  <p>RFC 1738 says the following:</p>
--     *  <blockquote>
--     *   Scheme names consist of a sequence of characters. The lower
--     *   case letters "a"--"z", digits, and the characters plus ("+"),
--     *   period ("."), and hyphen ("-") are allowed. For resiliency,
--     *   programs interpreting URLs should treat upper case letters as
--     *   equivalent to lower case in scheme names (e.g., allow "HTTP" as
--     *   well as "http").
--     *  </blockquote>
--     * <p>We treat as absolute any URL that begins with such a scheme name,
--     * followed by a colon.</p>
--     */
--    public static final String VALID_SCHEME_CHARS =
--	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
--
-     /** Default character encoding for response. */
-     public static final String DEFAULT_ENCODING = "ISO-8859-1";
- 
-@@ -133,7 +118,7 @@
- 	    throw new NullAttributeException("import", "url");
- 
- 	// Record whether our URL is absolute or relative
--	isAbsoluteUrl = isAbsoluteUrl();
-+	isAbsoluteUrl = UrlUtil.isAbsoluteUrl(url);
- 
- 	try {
- 	    // If we need to expose a Reader, we've got to do it right away
-@@ -500,43 +485,10 @@
- 	return urlWithParams;
-     }
- 
--    /**
--     * Returns <tt>true</tt> if our current URL is absolute,
--     * <tt>false</tt> otherwise.
--     */
--    private boolean isAbsoluteUrl() throws JspTagException {
--        return isAbsoluteUrl(url);
--    }
--
--
-     //*********************************************************************
-     // Public utility methods
- 
-     /**
--     * Returns <tt>true</tt> if our current URL is absolute,
--     * <tt>false</tt> otherwise.
--     */
--    public static boolean isAbsoluteUrl(String url) {
--	// a null URL is not absolute, by our definition
--	if (url == null)
--	    return false;
--
--	// do a fast, simple check first
--	int colonPos;
--	if ((colonPos = url.indexOf(":")) == -1)
--	    return false;
--
--	// if we DO have a colon, make sure that every character
--	// leading up to it is a valid scheme character
--	for (int i = 0; i < colonPos; i++)
--	    if (VALID_SCHEME_CHARS.indexOf(url.charAt(i)) == -1)
--		return false;
--
--	// if so, we've got an absolute url
--	return true;
--    }
--
--    /**
-      * Strips a servlet session ID from <tt>url</tt>.  The session ID
-      * is encoded as a URL "path parameter" beginning with "jsessionid=".
-      * We thus remove anything we find between ";jsessionid=" (inclusive)
---- a/standard/src/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java
-@@ -22,6 +22,8 @@
- import javax.servlet.jsp.PageContext;
- import javax.servlet.jsp.tagext.BodyTagSupport;
- 
-+import org.apache.taglibs.standard.util.UrlUtil;
-+
- /**
-  * <p>Support for tag handlers for <redirect>, JSTL 1.0's tag
-  * for redirecting to a new URL (with optional query parameters).</p>
-@@ -90,29 +92,30 @@
- 	return EVAL_BODY_BUFFERED;
-     }
- 
--
-     // gets the right value, encodes it, and prints or stores it
-+
-     public int doEndTag() throws JspException {
--	String result;				// the eventual result
-+        String result;                // the eventual result
- 
--	// add (already encoded) parameters
-+        // add (already encoded) parameters
-         String baseUrl = UrlSupport.resolveUrl(url, context, pageContext);
-         result = params.aggregateParams(baseUrl);
- 
-         // if the URL is relative, rewrite it with 'redirect' encoding rules
-         HttpServletResponse response =
--            ((HttpServletResponse) pageContext.getResponse());
--        if (!ImportSupport.isAbsoluteUrl(result))
-+                ((HttpServletResponse) pageContext.getResponse());
-+        if (!UrlUtil.isAbsoluteUrl(result)) {
-             result = response.encodeRedirectURL(result);
-+        }
- 
--	// redirect!
--	try {
--	    response.sendRedirect(result);
--	} catch (java.io.IOException ex) {
--	    throw new JspTagException(ex.toString(), ex);
--	}
-+        // redirect!
-+        try {
-+            response.sendRedirect(result);
-+        } catch (java.io.IOException ex) {
-+            throw new JspTagException(ex.toString(), ex);
-+        }
- 
--	return SKIP_PAGE;
-+        return SKIP_PAGE;
-     }
- 
-     // Releases any resources we may have (or inherit)
---- a/standard/src/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/core/UrlSupport.java
-@@ -24,6 +24,7 @@
- import javax.servlet.jsp.tagext.BodyTagSupport;
- 
- import org.apache.taglibs.standard.resources.Resources;
-+import org.apache.taglibs.standard.util.UrlUtil;
- 
- /**
-  * <p>Support for tag handlers for <url>, the URL creation
-@@ -104,7 +105,7 @@
- 	result = params.aggregateParams(baseUrl);
- 
- 	// if the URL is relative, rewrite it
--	if (!ImportSupport.isAbsoluteUrl(result)) {
-+	if (!UrlUtil.isAbsoluteUrl(result)) {
- 	    HttpServletResponse response =
-                 ((HttpServletResponse) pageContext.getResponse());
-             result = response.encodeURL(result);
-@@ -134,29 +135,32 @@
- 
-     public static String resolveUrl(
-             String url, String context, PageContext pageContext)
--	    throws JspException {
--	// don't touch absolute URLs
--	if (ImportSupport.isAbsoluteUrl(url))
--	    return url;
--
--	// normalize relative URLs against a context root
--	HttpServletRequest request =
--	    (HttpServletRequest) pageContext.getRequest();
--	if (context == null) {
--	    if (url.startsWith("/"))
--		return (request.getContextPath() + url);
--	    else
--		return url;
--	} else {
-+            throws JspException {
-+        // don't touch absolute URLs
-+        if (UrlUtil.isAbsoluteUrl(url)) {
-+            return url;
-+        }
-+
-+        // normalize relative URLs against a context root
-+        HttpServletRequest request =
-+                (HttpServletRequest) pageContext.getRequest();
-+        if (context == null) {
-+            if (url.startsWith("/")) {
-+                return (request.getContextPath() + url);
-+            } else {
-+                return url;
-+            }
-+        } else {
-             if (!context.startsWith("/") || !url.startsWith("/")) {
-                 throw new JspTagException(
--                    Resources.getMessage("IMPORT_BAD_RELATIVE"));
-+                        Resources.getMessage("IMPORT_BAD_RELATIVE"));
-             }
--            if (context.equals("/")) {
-+            if (context.endsWith("/") && url.startsWith("/")) {
-                 // Don't produce string starting with '//', many
-                 // browsers interpret this as host name, not as
--                // path on same host.
--                return url;
-+                // path on same host. Bug 22860
-+                // Also avoid // inside the url. Bug 34109
-+                return (context.substring(0, context.length() - 1) + url);
-             } else {
-                 return (context + url);
-             }
---- /dev/null
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStack.java
-@@ -0,0 +1,132 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements.  See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License.  You may obtain a copy of the License at
-+ * 
-+ *      http://www.apache.org/licenses/LICENSE-2.0
-+ * 
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.taglibs.standard.tag.common.xml;
-+
-+import java.util.HashMap;
-+import java.util.Map;
-+
-+import javax.servlet.http.Cookie;
-+import javax.servlet.http.HttpServletRequest;
-+import javax.servlet.jsp.PageContext;
-+import javax.xml.transform.TransformerException;
-+
-+import org.apache.taglibs.standard.resources.Resources;
-+import org.apache.xml.utils.QName;
-+import org.apache.xpath.VariableStack;
-+import org.apache.xpath.XPathContext;
-+import org.apache.xpath.objects.XObject;
-+import org.apache.xpath.objects.XObjectFactory;
-+
-+/**
-+ */
-+public class JSTLVariableStack extends VariableStack {
-+
-+    private static enum Scope {
-+        PARAM,
-+        HEADER,
-+        COOKIE,
-+        INITPARAM,
-+        PAGE,
-+        REQUEST,
-+        SESSION,
-+        APPLICATION
-+    }
-+
-+    // Prefixes for JSTL implicit variables
-+    private static final String PARAM_PREFIX = "param";
-+    private static final String HEADER_PREFIX = "header";
-+    private static final String COOKIE_PREFIX = "cookie";
-+    private static final String INITPARAM_PREFIX = "initParam";
-+    private static final String PAGE_PREFIX = "pageScope";
-+    private static final String REQUEST_PREFIX = "requestScope";
-+    private static final String SESSION_PREFIX = "sessionScope";
-+    private static final String APP_PREFIX = "applicationScope";
-+
-+    // map prefixes to scopes
-+    private static final Map<String, Scope> SCOPES;
-+    static {
-+        SCOPES = new HashMap<String, Scope>(8);
-+        SCOPES.put(PARAM_PREFIX, Scope.PARAM);
-+        SCOPES.put(HEADER_PREFIX, Scope.HEADER);
-+        SCOPES.put(COOKIE_PREFIX, Scope.COOKIE);
-+        SCOPES.put(INITPARAM_PREFIX, Scope.INITPARAM);
-+        SCOPES.put(PAGE_PREFIX, Scope.PAGE);
-+        SCOPES.put(REQUEST_PREFIX, Scope.REQUEST);
-+        SCOPES.put(SESSION_PREFIX, Scope.SESSION);
-+        SCOPES.put(APP_PREFIX, Scope.APPLICATION);
-+    }
-+
-+    private final PageContext pageContext;
-+
-+    public JSTLVariableStack(PageContext pageContext) {
-+        super(2);
-+        this.pageContext = pageContext;
-+    }
-+
-+    @Override
-+    public XObject getVariableOrParam(XPathContext xctxt, QName qname) throws TransformerException {
-+        String prefix = qname.getNamespaceURI();
-+        String name = qname.getLocalPart();
-+        Object value = getValue(prefix, name);
-+        if (value == null) {
-+            StringBuilder var = new StringBuilder();
-+            var.append('$');
-+            if (prefix != null) {
-+                var.append(prefix);
-+                var.append(':');
-+            }
-+            var.append(name);
-+            throw new TransformerException(Resources.getMessage("XPATH_UNABLE_TO_RESOLVE_VARIABLE", var.toString()));
-+        }
-+        return XObjectFactory.create(value, xctxt);
-+    }
-+
-+    private Object getValue(String prefix, String name) {
-+        if (prefix == null) {
-+            return pageContext.findAttribute(name);
-+        }
-+        Scope scope = SCOPES.get(prefix);
-+        switch (scope) {
-+            case PARAM:
-+                return pageContext.getRequest().getParameter(name);
-+            case HEADER:
-+                return ((HttpServletRequest) pageContext.getRequest()).getHeader(name);
-+            case COOKIE:
-+                Cookie[] cookies = ((HttpServletRequest) pageContext.getRequest()).getCookies();
-+                if (cookies != null) {
-+                    for (Cookie cookie : cookies) {
-+                        if (cookie.getName().equals(name)) {
-+                            return cookie.getValue();
-+                        }
-+                    }
-+                }
-+                return null;
-+            case INITPARAM:
-+                return pageContext.getServletContext().getInitParameter(name);
-+            case PAGE:
-+                return pageContext.getAttribute(name, PageContext.PAGE_SCOPE);
-+            case REQUEST:
-+                return pageContext.getAttribute(name, PageContext.REQUEST_SCOPE);
-+            case SESSION:
-+                return pageContext.getAttribute(name, PageContext.SESSION_SCOPE);
-+            case APPLICATION:
-+                return pageContext.getAttribute(name, PageContext.APPLICATION_SCOPE);
-+            default:
-+                throw new AssertionError();
-+        }
-+    }
-+}
---- a/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java
-@@ -16,36 +16,26 @@
- 
- package org.apache.taglibs.standard.tag.common.xml;
- 
--import java.io.FileNotFoundException;
- import java.io.IOException;
--import java.io.InputStream;
- import java.io.Reader;
- import java.io.StringReader;
- 
--import javax.servlet.http.HttpServletRequest;
- import javax.servlet.jsp.JspException;
- 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.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;
- 
- /**
-  * <p>Support for tag handlers for <parse>, the XML parsing tag.</p>
-@@ -68,12 +58,7 @@
-     private String varDom;			   // 'varDom' attribute
-     private int scope;				   // processed 'scope' attr
-     private int scopeDom;			   // processed 'scopeDom' attr
--
--    // state in support of XML parsing...
--    private DocumentBuilderFactory dbf;
--    private DocumentBuilder db;
--    private TransformerFactory tf;
--    private TransformerHandler th;
-+    private XmlUtil.JstlEntityResolver entityResolver;
- 
- 
-     //*********************************************************************
-@@ -89,76 +74,50 @@
- 	xml = null;
- 	systemId = null;
- 	filter = null;
--	dbf = null;
--	db = null;
--	tf = null;
--	th = null;
- 	scope = PageContext.PAGE_SCOPE;
- 	scopeDom = PageContext.PAGE_SCOPE;
-     }
- 
--
-     //*********************************************************************
-     // Tag logic
- 
-     // parse 'source' or body, storing result in 'var'
-     public int doEndTag() throws JspException {
--      try {
--	
--	// set up our DocumentBuilder
--        if (dbf == null) {
--            dbf = DocumentBuilderFactory.newInstance();
--            dbf.setNamespaceAware(true);
--            dbf.setValidating(false);
-+        // produce a Document by parsing whatever the attributes tell us to use
-+        Object xmlText = this.xml;
-+        if (xmlText == null) {
-+            // if the attribute was specified, use the body as 'xml'
-+            if (bodyContent != null && bodyContent.getString() != null) {
-+                xmlText = bodyContent.getString().trim();
-+            } else {
-+                xmlText = "";
-+            }
-+        }
-+        if (xmlText instanceof String) {
-+            xmlText = new StringReader((String) xmlText);
-+        }
-+        if (!(xmlText instanceof Reader)) {
-+            throw new JspTagException(Resources.getMessage("PARSE_INVALID_SOURCE"));
-+        }
-+        InputSource source = XmlUtil.newInputSource(((Reader) xmlText), systemId);
-+
-+        Document d;
-+        if (filter != null) {
-+            d = parseInputSourceWithFilter(source, filter);
-+        } else {
-+            d = parseInputSource(source);
-+        }
-+
-+        // we've got a Document object; store it out as appropriate
-+        // (let any exclusivity or other constraints be enforced by TEI/TLV)
-+        if (var != null) {
-+            pageContext.setAttribute(var, d, scope);
-+        }
-+        if (varDom != null) {
-+            pageContext.setAttribute(varDom, d, scopeDom);
-         }
--        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();
--	}
--
--	// produce a Document by parsing whatever the attributes tell us to use
--	Document d;
--	Object xmlText = this.xml;
--	if (xmlText == null) {
--	    // if the attribute was specified, use the body as 'xml'
--	    if (bodyContent != null && bodyContent.getString() != null)
--		xmlText = bodyContent.getString().trim();
--	    else
--		xmlText = "";
--	}
--	if (xmlText instanceof String)
--	    d = parseStringWithFilter((String) xmlText, filter);
--	else if (xmlText instanceof Reader)
--	    d = parseReaderWithFilter((Reader) xmlText, filter);
--	else
--	    throw new JspTagException(
--	        Resources.getMessage("PARSE_INVALID_SOURCE"));
--
--	// we've got a Document object; store it out as appropriate
--	// (let any exclusivity or other constraints be enforced by TEI/TLV)
--	if (var != null)
--	    pageContext.setAttribute(var, d, scope);
--	if (varDom != null)
--	    pageContext.setAttribute(varDom, d, scopeDom);
--
--	return EVAL_PAGE;
--      } catch (SAXException ex) {
--	throw new JspException(ex);
--      } catch (IOException ex) {
--	throw new JspException(ex);
--      } catch (ParserConfigurationException ex) {
--	throw new JspException(ex);
--      } catch (TransformerConfigurationException ex) {
--	throw new JspException(ex);
--      }
-+        return EVAL_PAGE;
-     }
- 
-     // Releases any resources we may have (or inherit)
-@@ -171,126 +130,48 @@
-     // Private utility methods
- 
-     /** Parses the given InputSource after, applying the given XMLFilter. */
--    private Document parseInputSourceWithFilter(InputSource s, XMLFilter f)
--            throws SAXException, IOException {
--	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));
-+    private Document parseInputSourceWithFilter(InputSource s, XMLFilter f) throws JspException {
-+        try {
-+            XMLReader xr = XmlUtil.newXMLReader(entityResolver);
-             //   (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
-             //    be perfect.)
-             f.setParent(xr);
--            f.setContentHandler(th);
--            f.parse(s);
--            return o;
--	} else
--	    return parseInputSource(s);	
--    }
- 
--    /** Parses the given Reader after applying the given XMLFilter. */
--    private Document parseReaderWithFilter(Reader r, XMLFilter f)
--            throws SAXException, IOException {
--	return parseInputSourceWithFilter(new InputSource(r), f);
--    }
-+            TransformerHandler th = XmlUtil.newTransformerHandler();
-+            Document o = XmlUtil.newEmptyDocument();
-+            th.setResult(new DOMResult(o));
- 
--    /** Parses the given String after applying the given XMLFilter. */
--    private Document parseStringWithFilter(String s, XMLFilter f)
--            throws SAXException, IOException {
--        StringReader r = new StringReader(s);
--        return parseReaderWithFilter(r, f);
--    }
-+            f.setContentHandler(th);
- 
--    /** Parses the given Reader after applying the given XMLFilter. */
--    private Document parseURLWithFilter(String url, XMLFilter f)
--            throws SAXException, IOException {
--	return parseInputSourceWithFilter(new InputSource(url), f);
-+            f.parse(s);
-+            return o;
-+        } catch (IOException e) {
-+            throw new JspException(e);
-+        } catch (SAXException e) {
-+            throw new JspException(e);
-+        } catch (TransformerConfigurationException e) {
-+            throw new JspException(e);
-+        }
-     }
- 
-     /** Parses the given InputSource into a Document. */
--    private Document parseInputSource(InputSource s)
--	    throws SAXException, IOException {
--	db.setEntityResolver(new JstlEntityResolver(pageContext));
--
--        // normalize URIs so they can be processed consistently by resolver
--        if (systemId == null)
--            s.setSystemId("jstl:");
--	else if (ImportSupport.isAbsoluteUrl(systemId))
--            s.setSystemId(systemId);
--        else
--            s.setSystemId("jstl:" + systemId);
--	return db.parse(s);
--    }
--
--    /** Parses the given Reader into a Document. */
--    private Document parseReader(Reader r) throws SAXException, IOException {
--        return parseInputSource(new InputSource(r));
--    }
--
--    /** Parses the given String into a Document. */
--    private Document parseString(String s) throws SAXException, IOException {
--        StringReader r = new StringReader(s);
--        return parseReader(r);
--    }
--
--    /** Parses the URL (passed as a String) into a Document. */
--    private Document parseURL(String url) throws SAXException, IOException {
--	return parseInputSource(new InputSource(url));
--    }
--
--    //*********************************************************************
--    // JSTL-specific EntityResolver class
--
--    /** Lets us resolve relative external entities. */
--    public static class JstlEntityResolver implements EntityResolver {
--	private final PageContext ctx;
--        public JstlEntityResolver(PageContext ctx) {
--            this.ctx = ctx;
-+    private Document parseInputSource(InputSource s) throws JspException {
-+        try {
-+            DocumentBuilder db = XmlUtil.newDocumentBuilder();
-+            db.setEntityResolver(entityResolver);
-+            return db.parse(s);
-+        } catch (SAXException e) {
-+            throw new JspException(e);
-+        } catch (IOException e) {
-+            throw new JspException(e);
-         }
--        public InputSource resolveEntity(String publicId, String systemId)
--	        throws FileNotFoundException {
-+    }
- 
--	    // pass if we don't have a systemId
--	    if (systemId == null)
--		return null;
--
--	    // strip leading "jstl:" off URL if applicable
--	    if (systemId.startsWith("jstl:"))
--		systemId = systemId.substring(5);
--
--	    // we're only concerned with relative URLs
--	    if (ImportSupport.isAbsoluteUrl(systemId))
--		return null;
--
--	    // for relative URLs, load and wrap the resource.
--	    // don't bother checking for 'null' since we specifically want
--	    // the parser to fail if the resource doesn't exist
--	    InputStream s;
--	    if (systemId.startsWith("/")) {
--	        s = ctx.getServletContext().getResourceAsStream(systemId);
--	        if (s == null)
--		    throw new FileNotFoundException(
--			Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
--			 systemId));
--	    } else {
--		String pagePath =
--		    ((HttpServletRequest) ctx.getRequest()).getServletPath();
--		String basePath =
--		    pagePath.substring(0, pagePath.lastIndexOf("/"));
--		s = ctx.getServletContext().getResourceAsStream(
--		      basePath + "/" + systemId);
--	        if (s == null)
--		    throw new FileNotFoundException(
--			Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
--			 systemId));
--	    }
--	    return new InputSource(s);
--        }
-+    public void setPageContext(PageContext pageContext) {
-+        super.setPageContext(pageContext);
-+        entityResolver = pageContext == null ? null: new XmlUtil.JstlEntityResolver(pageContext);
-     }
- 
-     //*********************************************************************
---- a/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java
-@@ -16,43 +16,29 @@
- 
- package org.apache.taglibs.standard.tag.common.xml;
- 
--import java.io.IOException;
--import java.io.InputStream;
- import java.io.Reader;
- import java.io.StringReader;
--import java.io.Writer;
- import java.util.List;
- 
--import javax.servlet.http.HttpServletRequest;
- import javax.servlet.jsp.JspException;
- 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;
--import javax.xml.transform.sax.SAXSource;
- import javax.xml.transform.stream.StreamResult;
--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.UnclosableWriter;
- 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;
- 
- /**
-  * <p>Support for tag handlers for <transform>, the XML transformation
-@@ -66,6 +52,7 @@
-     // Protected state
- 
-     protected Object xml;                       // attribute
-+    protected boolean xmlSpecified;             // true if xml attribute was specified
-     protected String xmlSystemId;		// attribute
-     protected Object xslt;			// attribute
-     protected String xsltSystemId;		// attribute
-@@ -77,25 +64,22 @@
-     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
--
-+    private XmlUtil.JstlEntityResolver entityResolver;
-+    private XmlUtil.JstlUriResolver uriResolver;
- 
-     //*********************************************************************
-     // Constructor and initialization
- 
-     public TransformSupport() {
--	super();
- 	init();
-     }
- 
-     private void init() {
- 	xml = xslt = null;
-+	xmlSpecified = false;
- 	xmlSystemId = xsltSystemId = null;
- 	var = null;
- 	result = null;
--	tf = null;
-         scope = PageContext.PAGE_SCOPE;
-     }
- 
-@@ -104,107 +88,70 @@
-     // Tag logic
- 
-     public int doStartTag() throws JspException {
--      /*
--       * We can set up our Transformer here, so we do so, and we let
--       * it receive parameters directly from subtags (instead of
--       * caching them.
--       */
--      try {
--
--	//************************************
--	// 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();
--
--	//************************************
--	// Produce transformer
--
--	Source s;
--	if (xslt != null) {
--	    if (!(xslt instanceof String) && !(xslt instanceof Reader)
--                    && !(xslt instanceof javax.xml.transform.Source))
--		throw new JspTagException(
--		    Resources.getMessage("TRANSFORM_XSLT_UNRECOGNIZED"));
--	    s = getSource(xslt, xsltSystemId);
--	} else {
--	    throw new JspTagException(
--	        Resources.getMessage("TRANSFORM_NO_TRANSFORMER"));
--        }
--	tf.setURIResolver(new JstlUriResolver(pageContext));
--        t = tf.newTransformer(s);
--
--	return EVAL_BODY_BUFFERED;
--
--      } catch (SAXException ex) {
--	throw new JspException(ex);
--      } catch (ParserConfigurationException ex) {
--	throw new JspException(ex);
--      } catch (IOException ex) {
--	throw new JspException(ex);
--      } catch (TransformerConfigurationException ex) {
--	throw new JspException(ex);
--      }
-+        // set up transformer in the start tag so that nested <param> tags can set parameters directly
-+        if (xslt == null) {
-+            throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_NULL"));
-+        }
-+
-+        Source source;
-+        try {
-+            if (xslt instanceof Source) {
-+                source = (Source) xslt;
-+            } else if (xslt instanceof String) {
-+                String s = (String) xslt;
-+                s = s.trim();
-+                if (s.length() == 0) {
-+                    throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_EMPTY"));
-+                }
-+                source = XmlUtil.newSAXSource(new StringReader(s), xsltSystemId, entityResolver);
-+            } else if (xslt instanceof Reader) {
-+                source = XmlUtil.newSAXSource((Reader) xslt, xsltSystemId, entityResolver);
-+            } else {
-+                throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_UNSUPPORTED_TYPE", xslt.getClass()));
-+            }
-+        } catch (SAXException e) {
-+            throw new JspException(e);
-+        }
-+
-+        try {
-+            t = XmlUtil.newTransformer(source);
-+            t.setURIResolver(uriResolver);
-+        } catch (TransformerConfigurationException e) {
-+            throw new JspTagException(e);
-+        } catch (RuntimeException e) {
-+            throw e;
-+        }
-+        return EVAL_BODY_BUFFERED;
-     }
- 
--    // parse 'xml' or body, transform via our Transformer,
--    // and store as 'var' or through 'result'
-     public int doEndTag() throws JspException {
--      try {
- 
--	//************************************
--	// Determine source XML
-+        try {
-+            Source source = xmlSpecified ? getSourceFromXmlAttribute() : getSourceFromBodyContent();
- 
--	// if we haven't gotten a source, use the body (which may be empty)
--	Object xml = this.xml;
--	if (xml == null)				// still equal
--	    if (bodyContent != null && bodyContent.getString() != null)
--	        xml = bodyContent.getString().trim();
--	    else
--		xml = "";
--
--	// let the Source be with you
--	Source source = getSource(xml, xmlSystemId);
--
--	//************************************
--	// Conduct the transformation
--
--	// we can assume at most one of 'var' or 'result' is specified
--	if (result != null)
--	    // we can write directly to the Result
--	    t.transform(source, result);
--	else if (var != null) {
--	    // we need a Document
--	    Document d = db.newDocument();
--	    Result doc = new DOMResult(d);
--	    t.transform(source, doc);
--	    pageContext.setAttribute(var, d, scope);
--	} else {
--	    Result page =
--		new StreamResult(new SafeWriter(pageContext.getOut()));
--	    t.transform(source, page);
--	}
--
--	return EVAL_PAGE;
--      } catch (SAXException ex) {
--	throw new JspException(ex);
--      } catch (ParserConfigurationException ex) {
--	throw new JspException(ex);
--      } catch (IOException ex) {
--	throw new JspException(ex);
--      } catch (TransformerException ex) {
--	throw new JspException(ex);
--      }
-+            // Conduct the transformation
-+            if (var != null) {
-+                // Save the result to var.
-+                Document d = XmlUtil.newEmptyDocument();
-+                Result doc = new DOMResult(d);
-+                t.transform(source, doc);
-+                pageContext.setAttribute(var, d, scope);
-+            } else {
-+                // Write to out if result is not specified.
-+                Result out = result;
-+                if (out == null) {
-+                    out = new StreamResult(new UnclosableWriter(pageContext.getOut()));
-+                }
-+                t.transform(source, out);
-+            }
-+            return EVAL_PAGE;
-+        } catch (TransformerException ex) {
-+            throw new JspException(ex);
-+        } catch (SAXException e) {
-+            throw new JspException(e);
-+        } finally {
-+            t = null;
-+        }
-     }
- 
-     // Releases any resources we may have (or inherit)
-@@ -212,6 +159,11 @@
- 	init();
-     }
- 
-+    public void setPageContext(PageContext pageContext) {
-+        super.setPageContext(pageContext);
-+        uriResolver = pageContext == null ? null : new XmlUtil.JstlUriResolver(pageContext);
-+        entityResolver = pageContext == null ? null : new XmlUtil.JstlEntityResolver(pageContext);
-+    }
- 
-     //*********************************************************************
-     // Public methods for subtags
-@@ -226,64 +178,67 @@
-     // Utility methods
- 
-     /**
--     * Wraps systemId with a "jstl:" prefix to prevent the parser from
--     * thinking that the URI is truly relative and resolving it against
--     * the current directory in the filesystem.
-+     * Return the Source for a document specified in the "doc" or "xml" attribute.
-+     *
-+     * @return the document Source
-+     * @throws JspTagException if there is a problem with the attribute
-      */
--    private static String wrapSystemId(String systemId) {
--      if (systemId == null)
--          return "jstl:";
--      else if (ImportSupport.isAbsoluteUrl(systemId))
--          return systemId;
--      else
--          return ("jstl:" + systemId);
-+    Source getSourceFromXmlAttribute() throws JspTagException, SAXException {
-+        Object xml = this.xml;
-+        if (xml == null) {
-+            throw new JspTagException(Resources.getMessage("TRANSFORM_XML_IS_NULL"));
-+        }
-+
-+        // other JSTL XML tags may produce a list
-+        if (xml instanceof List) {
-+            List<?> list = (List<?>) xml;
-+            if (list.size() != 1) {
-+                throw new JspTagException(Resources.getMessage("TRANSFORM_XML_LIST_SIZE"));
-+            }
-+            xml = list.get(0);
-+        }
-+
-+        if (xml instanceof Source) {
-+            return (Source) xml;
-+        }
-+        if (xml instanceof String) {
-+            String s = (String) xml;
-+            s = s.trim();
-+            if (s.length() == 0) {
-+                throw new JspTagException(Resources.getMessage("TRANSFORM_XML_IS_EMPTY"));
-+            }
-+            return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, entityResolver);
-+        }
-+        if (xml instanceof Reader) {
-+            return XmlUtil.newSAXSource((Reader) xml, xmlSystemId, entityResolver);
-+        }
-+        if (xml instanceof Node) {
-+            return new DOMSource((Node) xml, xmlSystemId);
-+        }
-+        throw new JspTagException(Resources.getMessage("TRANSFORM_XML_UNSUPPORTED_TYPE", xml.getClass()));
-     }
- 
-     /**
--     * Retrieves a Source from the given Object, whether it be a String,
--     * Reader, Node, or other supported types (even a Source already).
--     * If 'url' is true, then we must be passed a String and will interpret
--     * it as a URL.  A null input always results in a null output.
-+     * Return the Source for a document specified as body content.
-+     *
-+     * @return the document Source
-+     * @throws JspTagException if there is a problem with the body content
-      */
--    private Source getSource(Object o, String systemId)
--	    throws SAXException, ParserConfigurationException, IOException {
--	if (o == null)
--	    return null;
--        else if (o instanceof Source) {
--	    return (Source) o;
--        } else if (o instanceof String) {
--	    // if we've got a string, chain to Reader below
--	    return getSource(new StringReader((String) o), systemId);
--        } 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));
--            InputSource s = new InputSource((Reader) o);
--            s.setSystemId(wrapSystemId(systemId));
--            Source result = new SAXSource(xr, s);
--            result.setSystemId(wrapSystemId(systemId));
--	    return result;
--        } else if (o instanceof Node) {
--	    return new DOMSource((Node) o);
--        } else if (o instanceof List) {
--	    // support 1-item List because our XPath processor outputs them	
--	    List l = (List) o;
--	    if (l.size() == 1) {
--	        return getSource(l.get(0), systemId);		// unwrap List
--	    } else {
--	        throw new IllegalArgumentException(
--                  Resources.getMessage("TRANSFORM_SOURCE_INVALID_LIST"));
--	    }
--        } else {
--	    throw new IllegalArgumentException(
--	       Resources.getMessage("TRANSFORM_SOURCE_UNRECOGNIZED")
--	         + o.getClass());
--	}
-+    Source getSourceFromBodyContent() throws JspTagException, SAXException {
-+        if (bodyContent == null) {
-+            throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_NULL"));
-+        }
-+        String s = bodyContent.getString();
-+        if (s == null) {
-+            throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_CONTENT_IS_NULL"));
-+        }
-+        s = s.trim();
-+        if (s.length() == 0) {
-+            throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_EMPTY"));
-+        }
-+        return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, entityResolver);
-     }
- 
--
-     //*********************************************************************
-     // Tag attributes
- 
-@@ -294,88 +249,4 @@
-     public void setScope(String scope) {
-         this.scope = Util.getScope(scope);
-     }
--
--
--    //*********************************************************************
--    // Private utility classes
--
--    /**
--     * A Writer based on a wrapped Writer but ignoring requests to
--     * close() and flush() it.  (Someone must have wrapped the
--     * toilet in my office similarly...)
--     */
--    private static class SafeWriter extends Writer {
--	private Writer w;
--	public SafeWriter(Writer w) { this.w = w; }
--	public void close() { }
--	public void flush() { }
--	public void write(char[] cbuf, int off, int len) throws IOException {
--	    w.write(cbuf, off, len);
--	}
--    }	
--
--    //*********************************************************************
--    // JSTL-specific URIResolver class
--
--    /** Lets us resolve relative external entities. */
--    private static class JstlUriResolver implements URIResolver {
--        private final PageContext ctx;
--        public JstlUriResolver(PageContext ctx) {
--            this.ctx = ctx;
--        }
--        public Source resolve(String href, String base)
--	        throws TransformerException {
--
--            // pass if we don't have a systemId
--            if (href == null)
--                return null;
--
--	    // remove "jstl" marker from 'base'
--            // NOTE: how 'base' is determined varies among different Xalan
--            // xsltc implementations
--            int index;
--            if (base != null && (index = base.indexOf("jstl:")) != -1) {
--                base = base.substring(index + 5);
--            }  
--
--            // we're only concerned with relative URLs
--            if (ImportSupport.isAbsoluteUrl(href)
--		    || (base != null && ImportSupport.isAbsoluteUrl(base)))
--                return null;
--
--	    // base is relative; remove everything after trailing '/'
--	    if (base == null || base.lastIndexOf("/") == -1)
--		base = "";
--	    else
--		base = base.substring(0, base.lastIndexOf("/") + 1);
--
--	    // concatenate to produce the real URL we're interested in
--	    String target = base + href;	    
--
--            // for relative URLs, load and wrap the resource.
--            // don't bother checking for 'null' since we specifically want
--            // the parser to fail if the resource doesn't exist
--            InputStream s;
--            if (target.startsWith("/")) {
--                s = ctx.getServletContext().getResourceAsStream(target);
--                if (s == null)
--                    throw new TransformerException(
--                        Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
--                         href));
--            } else {
--                String pagePath =
--                    ((HttpServletRequest) ctx.getRequest()).getServletPath();
--                String basePath =
--                    pagePath.substring(0, pagePath.lastIndexOf("/"));
--                s = ctx.getServletContext().getResourceAsStream(
--                      basePath + "/" + target);
--		if (s == null)
--		    throw new TransformerException(
--                        Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY",
--                         href));
--            }
--            return new StreamSource(s);
--        }
--    }
--
- }
---- /dev/null
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java
-@@ -0,0 +1,90 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements.  See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License.  You may obtain a copy of the License at
-+ * 
-+ *      http://www.apache.org/licenses/LICENSE-2.0
-+ * 
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.taglibs.standard.tag.common.xml;
-+
-+import javax.servlet.jsp.PageContext;
-+import javax.servlet.jsp.tagext.Tag;
-+import javax.servlet.jsp.tagext.TagSupport;
-+import javax.xml.transform.TransformerException;
-+
-+import org.apache.xpath.VariableStack;
-+import org.apache.xpath.XPathContext;
-+import org.apache.xpath.objects.XBoolean;
-+import org.apache.xpath.objects.XNodeSet;
-+import org.apache.xpath.objects.XNumber;
-+import org.apache.xpath.objects.XObject;
-+import org.apache.xpath.objects.XString;
-+import org.w3c.dom.NodeList;
-+
-+/**
-+ */
-+public class XalanUtil {
-+    /**
-+     * Return the XPathContext to be used for evaluating expressions.
-+     *
-+     * If the child is nested withing a forEach tag its iteration context is used.
-+     * Otherwise, a new context is created based on an empty Document.
-+     *
-+     * @param child the tag whose context should be returned
-+     * @param pageContext the current page context
-+     * @return the XPath evaluation context
-+     */
-+    public static XPathContext getContext(Tag child, PageContext pageContext) {
-+        // if within a forEach tag, use its context
-+        ForEachTag forEachTag = (ForEachTag) TagSupport.findAncestorWithClass(child, ForEachTag.class);
-+        if (forEachTag != null) {
-+            throw new UnsupportedOperationException("getContext: not implemented method in org.apache.taglibs.standard.tag.common.xml.ForEachTag class!");
-+            //return forEachTag.getContext();
-+        }
-+
-+        // otherwise, create a new context referring to an empty document
-+        XPathContext context = new XPathContext(false);
-+        VariableStack variableStack = new JSTLVariableStack(pageContext);
-+        context.setVarStack(variableStack);
-+        int dtm = context.getDTMHandleFromNode(XmlUtil.newEmptyDocument());
-+        context.pushCurrentNodeAndExpression(dtm, dtm);
-+        return context;
-+    }
-+
-+    /**
-+     * Return the Java value corresponding to an XPath result.
-+     *
-+     * @param xo the XPath type
-+     * @return the corresponding Java value per the JSTL mapping rules
-+     * @throws TransformerException if there was a problem converting the type
-+     */
-+    static Object coerceToJava(XObject xo) throws TransformerException {
-+        if (xo instanceof XBoolean) {
-+            return xo.bool();
-+        } else if (xo instanceof XNumber) {
-+            return xo.num();
-+        } else if (xo instanceof XString) {
-+            return xo.str();
-+        } else if (xo instanceof XNodeSet) {
-+            NodeList nodes = xo.nodelist();
-+            // if there is only one node in the nodeset return it rather than the list
-+            if (nodes.getLength() == 1) {
-+                return nodes.item(0);
-+            } else {
-+                return nodes;
-+            }
-+        } else {
-+            // unexpected result type
-+            throw new AssertionError();
-+        }
-+    }
-+}
---- /dev/null
-+++ b/standard/src/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java
-@@ -0,0 +1,279 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements.  See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License.  You may obtain a copy of the License at
-+ *
-+ *      http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.taglibs.standard.tag.common.xml;
-+
-+import java.io.FileNotFoundException;
-+import java.io.InputStream;
-+import java.io.Reader;
-+
-+import javax.servlet.http.HttpServletRequest;
-+import javax.servlet.jsp.PageContext;
-+import javax.xml.XMLConstants;
-+import javax.xml.parsers.DocumentBuilder;
-+import javax.xml.parsers.DocumentBuilderFactory;
-+import javax.xml.parsers.ParserConfigurationException;
-+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.sax.SAXSource;
-+import javax.xml.transform.sax.SAXTransformerFactory;
-+import javax.xml.transform.sax.TransformerHandler;
-+import javax.xml.transform.stream.StreamSource;
-+
-+import org.apache.taglibs.standard.resources.Resources;
-+import org.apache.taglibs.standard.util.UrlUtil;
-+import org.w3c.dom.Document;
-+import org.xml.sax.EntityResolver;
-+import org.xml.sax.InputSource;
-+import org.xml.sax.SAXException;
-+import org.xml.sax.XMLReader;
-+import org.xml.sax.helpers.XMLReaderFactory;
-+
-+/**
-+ * Utilities for working with JAXP and SAX.
-+ */
-+public class XmlUtil {
-+    private static final DocumentBuilderFactory dbf;
-+    private static final SAXTransformerFactory stf;
-+
-+    static {
-+        // from Java5 on DocumentBuilderFactory is thread safe and hence can be cached
-+        dbf = DocumentBuilderFactory.newInstance();
-+        dbf.setNamespaceAware(true);
-+        dbf.setValidating(false);
-+        try {
-+            dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-+        } catch (ParserConfigurationException e) {
-+            throw new AssertionError("Parser does not support secure processing");
-+        }
-+
-+        TransformerFactory tf = TransformerFactory.newInstance();
-+        if (!(tf instanceof SAXTransformerFactory)) {
-+            throw new AssertionError("TransformerFactory does not support SAX");
-+        }
-+        try {
-+            tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-+        } catch (TransformerConfigurationException e) {
-+            throw new AssertionError("TransformerFactory does not support secure processing");
-+        }
-+        stf = (SAXTransformerFactory) tf;
-+    }
-+
-+
-+    /**
-+     * Create a new empty document.
-+     *
-+     * This method always allocates a new document as its root node might be
-+     * exposed to other tags and potentially be mutated.
-+     *
-+     * @return a new empty document
-+     */
-+    static Document newEmptyDocument() {
-+        return newDocumentBuilder().newDocument();
-+    }
-+
-+    /**
-+     * Create a new DocumentBuilder configured for namespaces but not validating.
-+     *
-+     * @return a new, configured DocumentBuilder
-+     */
-+    static DocumentBuilder newDocumentBuilder() {
-+        try {
-+            return dbf.newDocumentBuilder();
-+        } catch (ParserConfigurationException e) {
-+            throw new AssertionError();
-+        }
-+    }
-+
-+    /**
-+     * Create a new TransformerHandler.
-+     * @return a new TransformerHandler
-+     */
-+    static TransformerHandler newTransformerHandler() throws TransformerConfigurationException {
-+        return stf.newTransformerHandler();
-+    }
-+
-+    static Transformer newTransformer(Source source) throws TransformerConfigurationException {
-+        Transformer transformer = stf.newTransformer(source);
-+        if (transformer == null) {
-+            throw new TransformerConfigurationException("newTransformer returned null");
-+        }
-+        return transformer;
-+    }
-+
-+    /**
-+     * Create an InputSource from a Reader.
-+     *
-+     * The systemId will be wrapped for use with JSTL's EntityResolver and UriResolver.
-+     *
-+     * @param reader the source of the XML
-+     * @param systemId the system id
-+     * @return a configured InputSource
-+     */
-+    static InputSource newInputSource(Reader reader, String systemId) {
-+        InputSource source = new InputSource(reader);
-+        source.setSystemId(wrapSystemId(systemId));
-+        return source;
-+    }
-+
-+    /**
-+     * Create an XMLReader that resolves entities using JSTL semantics.
-+     * @param entityResolver for resolving using JSTL semamtics
-+     * @return a new XMLReader
-+     * @throws SAXException if there was a problem creating the reader
-+     */
-+    static XMLReader newXMLReader(JstlEntityResolver entityResolver) throws SAXException {
-+        XMLReader xmlReader = XMLReaderFactory.createXMLReader();
-+        xmlReader.setEntityResolver(entityResolver);
-+        return xmlReader;
-+    }
-+
-+    /**
-+     * Create a SAXSource from a Reader. Any entities will be resolved using JSTL semantics.
-+     *
-+     * @param reader the source of the XML
-+     * @param systemId the system id
-+     * @param entityResolver for resolving using JSTL semamtics
-+     * @return a new SAXSource
-+     * @throws SAXException if there was a problem creating the source
-+     */
-+    static SAXSource newSAXSource(Reader reader, String systemId, JstlEntityResolver entityResolver)  throws SAXException {
-+        SAXSource source = new SAXSource(newXMLReader(entityResolver), new InputSource(reader));
-+        source.setSystemId(wrapSystemId(systemId));
-+        return source;
-+    }
-+
-+    /**
-+     * Wraps systemId with a "jstl:" prefix to prevent the parser from
-+     * thinking that the URI is truly relative and resolving it against
-+     * the current directory in the filesystem.
-+     */
-+    private static String wrapSystemId(String systemId) {
-+        if (systemId == null) {
-+            return "jstl:";
-+        } else if (UrlUtil.isAbsoluteUrl(systemId)) {
-+            return systemId;
-+        } else {
-+            return ("jstl:" + systemId);
-+        }
-+    }
-+
-+    /**
-+     * JSTL-specific implementation of EntityResolver.
-+     */
-+    static class JstlEntityResolver implements EntityResolver {
-+        private final PageContext ctx;
-+
-+        public JstlEntityResolver(PageContext ctx) {
-+            this.ctx = ctx;
-+        }
-+
-+        public InputSource resolveEntity(String publicId, String systemId) throws FileNotFoundException {
-+
-+            // pass if we don't have a systemId
-+            if (systemId == null) {
-+                return null;
-+            }
-+
-+            // strip leading "jstl:" off URL if applicable
-+            if (systemId.startsWith("jstl:")) {
-+                systemId = systemId.substring(5);
-+            }
-+
-+            // we're only concerned with relative URLs
-+            if (UrlUtil.isAbsoluteUrl(systemId)) {
-+                return null;
-+            }
-+
-+            // for relative URLs, load and wrap the resource.
-+            // don't bother checking for 'null' since we specifically want
-+            // the parser to fail if the resource doesn't exist
-+            String path = systemId;
-+            if (!path.startsWith("/")) {
-+                String pagePath = ((HttpServletRequest) ctx.getRequest()).getServletPath();
-+                String basePath = pagePath.substring(0, pagePath.lastIndexOf("/"));
-+                path =  basePath + "/" + systemId;
-+            }
-+
-+            InputStream s = ctx.getServletContext().getResourceAsStream(path);
-+            if (s == null) {
-+                throw new FileNotFoundException(Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY", systemId));
-+            }
-+            return new InputSource(s);
-+        }
-+    }
-+
-+    /**
-+     * JSTL-specific implementation of URIResolver.
-+     */
-+    static class JstlUriResolver implements URIResolver {
-+        private final PageContext ctx;
-+
-+        public JstlUriResolver(PageContext ctx) {
-+            this.ctx = ctx;
-+        }
-+
-+        public Source resolve(String href, String base) throws TransformerException {
-+
-+            // pass if we don't have a systemId
-+            if (href == null) {
-+                return null;
-+            }
-+
-+            // remove "jstl" marker from 'base'
-+            // NOTE: how 'base' is determined varies among different Xalan
-+            // xsltc implementations
-+            int index;
-+            if (base != null && (index = base.indexOf("jstl:")) != -1) {
-+                base = base.substring(index + 5);
-+            }
-+
-+            // we're only concerned with relative URLs
-+            if (UrlUtil.isAbsoluteUrl(href)
-+                    || (base != null && UrlUtil.isAbsoluteUrl(base))) {
-+                return null;
-+            }
-+
-+            // base is relative; remove everything after trailing '/'
-+            if (base == null || base.lastIndexOf("/") == -1) {
-+                base = "";
-+            } else {
-+                base = base.substring(0, base.lastIndexOf("/") + 1);
-+            }
-+
-+            // concatenate to produce the real URL we're interested in
-+            String target = base + href;
-+
-+            // for relative URLs, load and wrap the resource.
-+            // don't bother checking for 'null' since we specifically want
-+            // the parser to fail if the resource doesn't exist
-+            if (!target.startsWith("/")) {
-+                String pagePath = ((HttpServletRequest) ctx.getRequest()).getServletPath();
-+                String basePath = pagePath.substring(0, pagePath.lastIndexOf("/"));
-+                target = basePath + "/" + target;
-+            }
-+            InputStream s = ctx.getServletContext().getResourceAsStream(target);
-+            if (s == null) {
-+                throw new TransformerException(Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY", href));
-+            }
-+            return new StreamSource(s);
-+        }
-+    }
-+}
---- 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;
-@@ -30,15 +31,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 +150,19 @@
- 	    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;
-@@ -162,8 +171,6 @@
- 
- 	} catch (SAXException ex) {
- 	    return vmFromString(ex.toString());
--	} catch (ParserConfigurationException ex) {
--	    return vmFromString(ex.toString());
- 	} catch (IOException ex) {
- 	    return vmFromString(ex.toString());
- 	}
---- /dev/null
-+++ b/standard/src/org/apache/taglibs/standard/util/UnclosableWriter.java
-@@ -0,0 +1,44 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements.  See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License.  You may obtain a copy of the License at
-+ *
-+ *      http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.taglibs.standard.util;
-+
-+import java.io.IOException;
-+import java.io.Writer;
-+
-+/**
-+ * A Writer based on a wrapped Writer but ignoring requests to
-+ * close() and flush() it.  (Someone must have wrapped the
-+ * toilet in my office similarly...)
-+ */
-+public class UnclosableWriter extends Writer {
-+    // TODO: shouldn't we be delegating all methods?
-+    private Writer w;
-+
-+    public UnclosableWriter(Writer w) {
-+        this.w = w;
-+    }
-+
-+    public void close() {
-+    }
-+
-+    public void flush() {
-+    }
-+
-+    public void write(char[] cbuf, int off, int len) throws IOException {
-+        w.write(cbuf, off, len);
-+    }
-+}
---- /dev/null
-+++ b/standard/src/org/apache/taglibs/standard/util/UrlUtil.java
-@@ -0,0 +1,80 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements.  See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License.  You may obtain a copy of the License at
-+ *
-+ *      http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.taglibs.standard.util;
-+
-+import java.util.BitSet;
-+
-+/**
-+ * Utilities for working with URLs.
-+ */
-+public class UrlUtil {
-+    /**
-+     * <p>Valid characters in a scheme.</p>
-+     * <p>RFC 1738 says the following:</p>
-+     * <blockquote>
-+     * Scheme names consist of a sequence of characters. The lower
-+     * case letters "a"--"z", digits, and the characters plus ("+"),
-+     * period ("."), and hyphen ("-") are allowed. For resiliency,
-+     * programs interpreting URLs should treat upper case letters as
-+     * equivalent to lower case in scheme names (e.g., allow "HTTP" as
-+     * well as "http").
-+     * </blockquote>
-+     * <p>We treat as absolute any URL that begins with such a scheme name,
-+     * followed by a colon.</p>
-+     */
-+/*
-+    private static final String VALID_SCHEME_CHARS =
-+            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-";
-+*/
-+    private static final BitSet VALID_SCHEME_CHARS;
-+    static {
-+        VALID_SCHEME_CHARS = new BitSet(128);
-+        VALID_SCHEME_CHARS.set('A', 'Z' + 1);
-+        VALID_SCHEME_CHARS.set('a', 'z' + 1);
-+        VALID_SCHEME_CHARS.set('0', '9' + 1);
-+        VALID_SCHEME_CHARS.set('+');
-+        VALID_SCHEME_CHARS.set('.');
-+        VALID_SCHEME_CHARS.set('-');
-+    }
-+
-+    /**
-+     * Determine if a URL is absolute by JSTL's definition.
-+     */
-+    public static boolean isAbsoluteUrl(String url) {
-+        // a null URL is not absolute, by our definition
-+        if (url == null) {
-+            return false;
-+        }
-+
-+        // do a fast, simple check first
-+        int colonPos = url.indexOf(":");
-+        if (colonPos == -1) {
-+            return false;
-+        }
-+
-+        // if we DO have a colon, make sure that every character
-+        // leading up to it is a valid scheme character
-+        for (int i = 0; i < colonPos; i++) {
-+            if (!VALID_SCHEME_CHARS.get(url.charAt(i))) {
-+                return false;
-+            }
-+        }
-+
-+        // if so, we've got an absolute url
-+        return true;
-+    }
-+}
---- /dev/null
-+++ b/standard/src/org/apache/taglibs/standard/util/XmlUtil.java
-@@ -0,0 +1,345 @@
-+/*
-+ * Licensed to the Apache Software Foundation (ASF) under one or more
-+ * contributor license agreements.  See the NOTICE file distributed with
-+ * this work for additional information regarding copyright ownership.
-+ * The ASF licenses this file to You under the Apache License, Version 2.0
-+ * (the "License"); you may not use this file except in compliance with
-+ * the License.  You may obtain a copy of the License at
-+ *
-+ *      http://www.apache.org/licenses/LICENSE-2.0
-+ *
-+ * Unless required by applicable law or agreed to in writing, software
-+ * distributed under the License is distributed on an "AS IS" BASIS,
-+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-+ * See the License for the specific language governing permissions and
-+ * limitations under the License.
-+ */
-+package org.apache.taglibs.standard.util;
-+
-+import java.io.FileNotFoundException;
-+import java.io.InputStream;
-+import java.io.Reader;
-+import java.security.AccessController;
-+import java.security.PrivilegedActionException;
-+import java.security.PrivilegedExceptionAction;
-+import java.util.concurrent.Callable;
-+
-+import javax.servlet.http.HttpServletRequest;
-+import javax.servlet.jsp.PageContext;
-+import javax.xml.XMLConstants;
-+import javax.xml.parsers.DocumentBuilder;
-+import javax.xml.parsers.DocumentBuilderFactory;
-+import javax.xml.parsers.ParserConfigurationException;
-+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.sax.SAXSource;
-+import javax.xml.transform.sax.SAXTransformerFactory;
-+import javax.xml.transform.sax.TransformerHandler;
-+import javax.xml.transform.stream.StreamSource;
-+
-+import org.apache.taglibs.standard.resources.Resources;
-+import org.w3c.dom.Document;
-+import org.xml.sax.EntityResolver;
-+import org.xml.sax.InputSource;
-+import org.xml.sax.SAXException;
-+import org.xml.sax.XMLReader;
-+import org.xml.sax.helpers.XMLReaderFactory;
-+
-+/**
-+ * Utilities for working with JAXP and SAX.
-+ */
-+public class XmlUtil {
-+    /* Cache factory classes when this class is initialized (since Java1.5 factories are required
-+     * to be thread safe).
-+     *
-+     * As JavaEE 5 requires JSTL to be provided by the container we use our ClassLoader to locate
-+     * the implementations rather than the application's. As we don't know the actual implementation
-+     * class in use we can't use the newInstance() variant that allows the ClassLoader to be
-+     * specified so we use the no-arg form and coerce the TCCL (which may be restricted by the
-+     * AccessController).
-+     */
-+    private static final DocumentBuilderFactory PARSER_FACTORY;
-+    private static final SAXTransformerFactory TRANSFORMER_FACTORY;
-+    static {
-+        try {
-+            PARSER_FACTORY = runWithOurClassLoader(new Callable<DocumentBuilderFactory>() {
-+                public DocumentBuilderFactory call() throws ParserConfigurationException {
-+                    return DocumentBuilderFactory.newInstance();
-+                }
-+            }, ParserConfigurationException.class);
-+            PARSER_FACTORY.setNamespaceAware(true);
-+            PARSER_FACTORY.setValidating(false);
-+            PARSER_FACTORY.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-+        } catch (ParserConfigurationException e) {
-+            throw new ExceptionInInitializerError(e);
-+        }
-+        try {
-+            TRANSFORMER_FACTORY = runWithOurClassLoader(new Callable<SAXTransformerFactory>() {
-+                public SAXTransformerFactory call() throws TransformerConfigurationException {
-+                    TransformerFactory tf = TransformerFactory.newInstance();
-+                    if (!(tf instanceof SAXTransformerFactory)) {
-+                        throw new TransformerConfigurationException("TransformerFactory does not support SAX");
-+                    }
-+                    return (SAXTransformerFactory) tf;
-+                }
-+            }, TransformerConfigurationException.class);
-+            TRANSFORMER_FACTORY.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-+        } catch (TransformerConfigurationException e) {
-+            throw new ExceptionInInitializerError(e);
-+        }
-+    }
-+
-+    /**
-+     * Create a new empty document.
-+     *
-+     * @return a new empty document
-+     */
-+    public static Document newEmptyDocument() {
-+        return newDocumentBuilder().newDocument();
-+    }
-+
-+    /**
-+     * Create a new DocumentBuilder configured for namespaces but not validating.
-+     *
-+     * @return a new, configured DocumentBuilder
-+     */
-+    public static DocumentBuilder newDocumentBuilder() {
-+        try {
-+            return PARSER_FACTORY.newDocumentBuilder();
-+        } catch (ParserConfigurationException e) {
-+            throw (Error) new AssertionError().initCause(e);
-+        }
-+    }
-+
-+    /**
-+     * Create a new TransformerHandler.
-+     * @return a new TransformerHandler
-+     */
-+    public static TransformerHandler newTransformerHandler() throws TransformerConfigurationException {
-+        return TRANSFORMER_FACTORY.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 = TRANSFORMER_FACTORY.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 InputSource from a Reader.
-+     *
-+     * The systemId will be wrapped for use with JSTL's EntityResolver and UriResolver.
-+     *
-+     * @param reader the source of the XML
-+     * @param systemId the system id
-+     * @return a configured InputSource
-+     */
-+    public static InputSource newInputSource(Reader reader, String systemId) {
-+        InputSource source = new InputSource(reader);
-+        source.setSystemId(wrapSystemId(systemId));
-+        return source;
-+    }
-+
-+    /**
-+     * Create an XMLReader that resolves entities using JSTL semantics.
-+     * @param entityResolver for resolving using JSTL semamtics
-+     * @return a new XMLReader
-+     * @throws SAXException if there was a problem creating the reader
-+     */
-+    public static XMLReader newXMLReader(JstlEntityResolver entityResolver) throws SAXException {
-+        XMLReader xmlReader = runWithOurClassLoader(new Callable<XMLReader>() {
-+            public XMLReader call() throws SAXException {
-+                return XMLReaderFactory.createXMLReader();
-+            }
-+        }, SAXException.class);
-+        xmlReader.setEntityResolver(entityResolver);
-+        xmlReader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-+        return xmlReader;
-+    }
-+
-+    /**
-+     * Create a SAXSource from a Reader. Any entities will be resolved using JSTL semantics.
-+     *
-+     * @param reader the source of the XML
-+     * @param systemId the system id
-+     * @param entityResolver for resolving using JSTL semamtics
-+     * @return a new SAXSource
-+     * @throws SAXException if there was a problem creating the source
-+     */
-+    public static SAXSource newSAXSource(Reader reader, String systemId, JstlEntityResolver entityResolver)  throws SAXException {
-+        SAXSource source = new SAXSource(newXMLReader(entityResolver), new InputSource(reader));
-+        source.setSystemId(wrapSystemId(systemId));
-+        return source;
-+    }
-+
-+    /**
-+     * Wraps systemId with a "jstl:" prefix to prevent the parser from
-+     * thinking that the URI is truly relative and resolving it against
-+     * the current directory in the filesystem.
-+     */
-+    private static String wrapSystemId(String systemId) {
-+        if (systemId == null) {
-+            return "jstl:";
-+        } else if (UrlUtil.isAbsoluteUrl(systemId)) {
-+            return systemId;
-+        } else {
-+            return ("jstl:" + systemId);
-+        }
-+    }
-+
-+    /**
-+     * JSTL-specific implementation of EntityResolver.
-+     */
-+    public static class JstlEntityResolver implements EntityResolver {
-+        private final PageContext ctx;
-+
-+        public JstlEntityResolver(PageContext ctx) {
-+            this.ctx = ctx;
-+        }
-+
-+        public InputSource resolveEntity(String publicId, String systemId) throws FileNotFoundException {
-+
-+            // pass if we don't have a systemId
-+            if (systemId == null) {
-+                return null;
-+            }
-+
-+            // strip leading "jstl:" off URL if applicable
-+            if (systemId.startsWith("jstl:")) {
-+                systemId = systemId.substring(5);
-+            }
-+
-+            // we're only concerned with relative URLs
-+            if (UrlUtil.isAbsoluteUrl(systemId)) {
-+                return null;
-+            }
-+
-+            // for relative URLs, load and wrap the resource.
-+            // don't bother checking for 'null' since we specifically want
-+            // the parser to fail if the resource doesn't exist
-+            String path = systemId;
-+            if (!path.startsWith("/")) {
-+                String pagePath = ((HttpServletRequest) ctx.getRequest()).getServletPath();
-+                String basePath = pagePath.substring(0, pagePath.lastIndexOf("/"));
-+                path =  basePath + "/" + systemId;
-+            }
-+
-+            InputStream s = ctx.getServletContext().getResourceAsStream(path);
-+            if (s == null) {
-+                throw new FileNotFoundException(Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY", systemId));
-+            }
-+            return new InputSource(s);
-+        }
-+    }
-+
-+    /**
-+     * JSTL-specific implementation of URIResolver.
-+     */
-+    public static class JstlUriResolver implements URIResolver {
-+        private final PageContext ctx;
-+
-+        public JstlUriResolver(PageContext ctx) {
-+            this.ctx = ctx;
-+        }
-+
-+        public Source resolve(String href, String base) throws TransformerException {
-+
-+            // pass if we don't have a systemId
-+            if (href == null) {
-+                return null;
-+            }
-+
-+            // remove "jstl" marker from 'base'
-+            // NOTE: how 'base' is determined varies among different Xalan
-+            // xsltc implementations
-+            int index;
-+            if (base != null && (index = base.indexOf("jstl:")) != -1) {
-+                base = base.substring(index + 5);
-+            }
-+
-+            // we're only concerned with relative URLs
-+            if (UrlUtil.isAbsoluteUrl(href)
-+                    || (base != null && UrlUtil.isAbsoluteUrl(base))) {
-+                return null;
-+            }
-+
-+            // base is relative; remove everything after trailing '/'
-+            if (base == null || base.lastIndexOf("/") == -1) {
-+                base = "";
-+            } else {
-+                base = base.substring(0, base.lastIndexOf("/") + 1);
-+            }
-+
-+            // concatenate to produce the real URL we're interested in
-+            String target = base + href;
-+
-+            // for relative URLs, load and wrap the resource.
-+            // don't bother checking for 'null' since we specifically want
-+            // the parser to fail if the resource doesn't exist
-+            if (!target.startsWith("/")) {
-+                String pagePath = ((HttpServletRequest) ctx.getRequest()).getServletPath();
-+                String basePath = pagePath.substring(0, pagePath.lastIndexOf("/"));
-+                target = basePath + "/" + target;
-+            }
-+            InputStream s = ctx.getServletContext().getResourceAsStream(target);
-+            if (s == null) {
-+                throw new TransformerException(Resources.getMessage("UNABLE_TO_RESOLVE_ENTITY", href));
-+            }
-+            return new StreamSource(s);
-+        }
-+    }
-+
-+    /**
-+     * Performs an action using this Class's ClassLoader as the Thread context ClassLoader.
-+     *
-+     * @param action the action to perform
-+     * @param allowed an Exception that might be thrown by the action
-+     * @param <T> the type of the result
-+     * @param <E> the type of the allowed Exception
-+     * @return the result of the action
-+     * @throws E if the action threw the allowed Exception
-+     */
-+    private static <T, E extends Exception> T runWithOurClassLoader(final Callable<T> action, Class<E> allowed) throws E {
-+        PrivilegedExceptionAction<T> actionWithClassloader = new PrivilegedExceptionAction<T>() {
-+            public T run() throws Exception {
-+                ClassLoader original = Thread.currentThread().getContextClassLoader();
-+                ClassLoader ours = XmlUtil.class.getClassLoader();
-+                // Don't override the TCCL if it is not needed.
-+                if (original == ours) {
-+                    return action.call();
-+                } else {
-+                    try {
-+                        Thread.currentThread().setContextClassLoader(ours);
-+                        return action.call();
-+                    } finally {
-+                        Thread.currentThread().setContextClassLoader(original);
-+                    }
-+                }
-+            }
-+        };
-+        try {
-+            return AccessController.doPrivileged(actionWithClassloader);
-+        } catch (PrivilegedActionException e) {
-+            Throwable cause = e.getCause();
-+            if (allowed.isInstance(cause)) {
-+                throw allowed.cast(cause);
-+            } else {
-+                throw (Error) new AssertionError().initCause(cause);
-+            }
-+        }
-+    }
-+}
diff --git a/debian/patches/series b/debian/patches/series
index 56884ca..d668276 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,2 @@
 01-jdbc-compatibility.patch
 02-servlet-api-compatibility.patch
-CVE-2015-0254.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/taglibs-standard.git



More information about the pkg-java-commits mailing list