[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