debian/0000775000000000000000000000000012504307575007200 5ustar debian/control0000664000000000000000000000314312001011115010552 0ustar Source: jakarta-taglibs-standard Section: java Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Debian Java Maintainers Uploaders: Onkar Shinde , James Page Build-Depends: ant, debhelper (>= 7.0.50~), javahelper, maven-repo-helper (>= 1.5~) Build-Depends-Indep: default-jdk, libservlet3.0-java, libxalan2-java Standards-Version: 3.9.3 DM-Upload-Allowed: yes Vcs-Git: git://git.debian.org/git/pkg-java/jakarta-taglibs-standard.git Vcs-Browser: http://git.debian.org/?p=pkg-java/jakarta-taglibs-standard.git Homepage: http://tomcat.apache.org/taglibs/standard/ Package: libjakarta-taglibs-standard-java Architecture: all Depends: ${java:Depends}, ${misc:Depends} Description: Implementation of JSP Standard Tag Library (JSTL) JSTL can be used to embed logic in JSP pages without using embedded java code. Various tags are defined for common tasks such as conditional execution, loops, internationalization, XML processing etc. . This package is Apache implementation of JSTL specification. Package: libjstl1.1-java Architecture: all Depends: ${java:Depends}, ${misc:Depends} Description: JSP Standard Tag Library API v1.1 Reference Implementation JSTL can be used to embed logic in JSP pages without using embedded java code. Various tags are defined for common tasks such as conditional execution, loops, internationalization, XML processing etc. . This package is the reference implementation of JSTL 1.1 specification based on Jakarta taglibs standard.. debian/libjstl1.1-java.classpath0000664000000000000000000000013111770243143013673 0ustar usr/share/java/jstl1.1.jar servlet-api-2.5.jar jsp-api-2.1.jar el-api-2.1.jar xalan2.jar debian/libjakarta-taglibs-standard-java.poms0000664000000000000000000000014111770177434016343 0ustar debian/poms/standard.pom --java-lib --artifact=standard/build/standard/standard/lib/standard.jar debian/changelog0000664000000000000000000000510612504310363011041 0ustar jakarta-taglibs-standard (1.1.2-2ubuntu1.14.04.1) trusty-security; urgency=medium * SECURITY UPDATE: abitrary code execution and XXE attacks - debian/patches/CVE-2015-0254.patch: thanks to Debian for the patch backport. - debian/ant.properties: bump source and target to 1.5. - CVE-2015-0254 -- Marc Deslauriers Tue, 24 Mar 2015 12:23:11 -0400 jakarta-taglibs-standard (1.1.2-2ubuntu1) quantal; urgency=low * Merge from Debian unstable. Remaining changes: - Transition from servlet 2.5 -> 3.0. -- James Page Mon, 16 Jul 2012 14:09:09 +0100 jakarta-taglibs-standard (1.1.2-2) unstable; urgency=low [ James Page ] * Fix FTBFS with openjdk-7 (Closes: #678166, LP: #888941): - d/patches/java7-compat.patch: Compatibility patch for compilation with Java 7 API. * Bumped Standards-Version: 3.9.3: - d/copyright: Tidied deprecated field names and referenced released version of DEP-5. * Switch to debhelper >= 7 style rules: - d/control: Drop cdbs Build-Depends, specify minimum versions for debhelper and maven-repo-helper. - d/rules: Refactor to use minimal overrides. * Provide taglibs:standard maven artifacts (Closes: #673119): - d/libjakarta-taglibs-standard-java.poms: Specify location of pom file and artifacts to install. - d/libjakarta-taglibs-standard-java.jlibs: Dropped - no longer required. - d/rules,d/poms/standard.pom: Grab pom file from maven central. [ Niels Thykier ] * Set DMUA to yes. -- James Page Wed, 20 Jun 2012 00:38:32 +0200 jakarta-taglibs-standard (1.1.2-1ubuntu2) quantal; urgency=low * Transition from servlet 2.5 -> 3.0: - d/control: Switch BDI from libservlet2.5-java to libservlet3.0-java. - d/rules: Use el-api-2.2 jar for build. - d/ant.properties: Update jar file names for libservlet3.0-java. * d/control: Bumped Standards-Version to 3.9.3 - d/copyright: Reference released version of DEP-5, tidy lintian warnings for deprecated field names. -- James Page Sun, 17 Jun 2012 21:28:08 +0100 jakarta-taglibs-standard (1.1.2-1ubuntu1) quantal; urgency=low * Fix FTBFS with openjdk-7 as default-jdk (LP: #888941): - d/patches/java7-compat.patch: Compatibility patch for compilation with Java 7 API. -- James Page Tue, 12 Jun 2012 21:42:00 +0100 jakarta-taglibs-standard (1.1.2-1) unstable; urgency=low * Initial version. (Closes: #630112) -- Onkar Shinde Thu, 09 Jun 2011 12:03:00 +0530 debian/source/0000775000000000000000000000000011770243143010472 5ustar debian/source/format0000664000000000000000000000001411770243143011700 0ustar 3.0 (quilt) debian/poms/0000775000000000000000000000000011770243143010150 5ustar debian/poms/jstl.pom0000664000000000000000000000054611770243143011646 0ustar 4.0.0 javax.servlet jstl 1.1.2 javax.servlet jsp-api 2.0 provided debian/poms/standard.pom0000664000000000000000000000022511770177434012475 0ustar 4.0.0 taglibs standard 1.1.2 debian/compat0000664000000000000000000000000211770243143010370 0ustar 7 debian/orig-tar.sh0000775000000000000000000000040311770243143011252 0ustar #!/bin/sh -e # called by uscan with '--upstream-version' DIR=jakarta-taglibs-standard-$2 TAR=../jakarta-taglibs-standard_$2.orig.tar.gz # clean up the upstream tarball tar zxvf $3 mv $DIR-src $DIR tar -c -z -f $TAR $DIR rm -rf $DIR exit 0 debian/patches/0000775000000000000000000000000012504307553010623 5ustar debian/patches/java7-compat.patch0000664000000000000000000000165111767432640014146 0ustar Index: jakarta-taglibs-standard/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java =================================================================== --- jakarta-taglibs-standard.orig/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java 2012-06-12 21:40:55.049170000 +0100 +++ jakarta-taglibs-standard/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java 2012-06-12 21:41:52.171712718 +0100 @@ -25,6 +25,9 @@ import org.apache.taglibs.standard.resources.Resources; +import java.sql.SQLFeatureNotSupportedException; +import java.util.logging.Logger; + /** *

A simple DataSource wrapper for the standard @@ -125,4 +128,10 @@ return null; } + /* + * JDBC 4.1 + */ + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException(); + } } debian/patches/01_fix_build.diff0000664000000000000000000000301311770243143013715 0ustar Description: Added method stubs to fix compilation against servlet-api-2.5. Forwarded: not-needed Author: Onkar Shinde --- a/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java 2011-06-09 11:41:17.000000000 +0530 +++ b/standard/src/org/apache/taglibs/standard/tag/common/sql/DataSourceWrapper.java 2011-06-09 11:41:22.000000000 +0530 @@ -111,5 +111,18 @@ throw new SQLException(Resources.getMessage("NOT_SUPPORTED")); } + /** + * Placeholder method to fix compilation. + */ + public boolean isWrapperFor(Class iface) throws SQLException { + return true; + } + + /** + * Placeholder method to fix compilation. + */ + public Object unwrap(Class iface) throws SQLException { + return null; + } } --- a/standard/src/org/apache/taglibs/standard/lang/jstl/test/PageContextImpl.java 2011-06-09 11:41:17.000000000 +0530 +++ b/standard/src/org/apache/taglibs/standard/lang/jstl/test/PageContextImpl.java 2011-06-09 11:41:22.000000000 +0530 @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.Map; +import javax.el.ELContext; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; @@ -297,5 +298,7 @@ public void include(java.lang.String relativeUrlPath, boolean flush) {} public ExpressionEvaluator getExpressionEvaluator() { return null; } public VariableResolver getVariableResolver() { return null; } + + public ELContext getELContext() { return null; } } debian/patches/series0000664000000000000000000000007112504307553012036 0ustar 01_fix_build.diff java7-compat.patch CVE-2015-0254.patch debian/patches/CVE-2015-0254.patch0000664000000000000000000025044712504307553013252 0ustar Description: Fix CVE-2015-0254 XXE and RCE via XSL extension in JSTL XML tags When an application uses or 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 +++ jakarta-taglibs-standard-1.1.2/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() { + 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. + } + } + } +} --- jakarta-taglibs-standard-1.1.2.orig/standard/src/javax/servlet/jsp/jstl/tlv/PermittedTaglibsTLV.java +++ jakarta-taglibs-standard-1.1.2/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 @@ public class PermittedTaglibsTLV extends //********************************************************************* // 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 @@ public class PermittedTaglibsTLV extends 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( --- jakarta-taglibs-standard-1.1.2.orig/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java +++ jakarta-taglibs-standard-1.1.2/standard/src/javax/servlet/jsp/jstl/tlv/ScriptFreeTLV.java @@ -24,7 +24,6 @@ import javax.servlet.jsp.tagext.PageData import javax.servlet.jsp.tagext.TagLibraryValidator; import javax.servlet.jsp.tagext.ValidationMessage; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; @@ -100,32 +99,19 @@ public class ScriptFreeTLV extends TagLi * @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. --- jakarta-taglibs-standard-1.1.2.orig/standard/src/org/apache/taglibs/standard/tag/common/core/ImportSupport.java +++ jakarta-taglibs-standard-1.1.2/standard/src/org/apache/taglibs/standard/tag/common/core/ImportSupport.java @@ -45,6 +45,7 @@ import javax.servlet.jsp.tagext.BodyTagS import javax.servlet.jsp.tagext.TryCatchFinally; import org.apache.taglibs.standard.resources.Resources; +import org.apache.taglibs.standard.util.UrlUtil; /** *

Support for tag handlers for <import>, the general-purpose @@ -60,22 +61,6 @@ public abstract class ImportSupport exte //********************************************************************* // Public constants - /**

Valid characters in a scheme.

- *

RFC 1738 says the following:

- *
- * 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"). - *
- *

We treat as absolute any URL that begins with such a scheme name, - * followed by a colon.

- */ - 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 @@ public abstract class ImportSupport exte 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 @@ -494,43 +479,10 @@ public abstract class ImportSupport exte return urlWithParams; } - /** - * Returns true if our current URL is absolute, - * false otherwise. - */ - private boolean isAbsoluteUrl() throws JspTagException { - return isAbsoluteUrl(url); - } - - //********************************************************************* // Public utility methods /** - * Returns true if our current URL is absolute, - * false 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 url. The session ID * is encoded as a URL "path parameter" beginning with "jsessionid=". * We thus remove anything we find between ";jsessionid=" (inclusive) --- jakarta-taglibs-standard-1.1.2.orig/standard/src/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java +++ jakarta-taglibs-standard-1.1.2/standard/src/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java @@ -22,6 +22,8 @@ import javax.servlet.jsp.JspTagException import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyTagSupport; +import org.apache.taglibs.standard.util.UrlUtil; + /** *

Support for tag handlers for <redirect>, JSTL 1.0's tag * for redirecting to a new URL (with optional query parameters).

@@ -90,29 +92,30 @@ public abstract class RedirectSupport ex 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) --- jakarta-taglibs-standard-1.1.2.orig/standard/src/org/apache/taglibs/standard/tag/common/core/UrlSupport.java +++ jakarta-taglibs-standard-1.1.2/standard/src/org/apache/taglibs/standard/tag/common/core/UrlSupport.java @@ -24,6 +24,7 @@ import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.BodyTagSupport; import org.apache.taglibs.standard.resources.Resources; +import org.apache.taglibs.standard.util.UrlUtil; /** *

Support for tag handlers for <url>, the URL creation @@ -104,7 +105,7 @@ public abstract class UrlSupport extends 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 abstract class UrlSupport extends 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 +++ jakarta-taglibs-standard-1.1.2/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 SCOPES; + static { + SCOPES = new HashMap(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(); + } + } +} --- jakarta-taglibs-standard-1.1.2.orig/standard/src/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java +++ jakarta-taglibs-standard-1.1.2/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; /** *

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

@@ -68,12 +58,7 @@ public abstract class ParseSupport exten 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 @@ public abstract class ParseSupport exten 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 @@ public abstract class ParseSupport exten // 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); } //********************************************************************* --- jakarta-taglibs-standard-1.1.2.orig/standard/src/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java +++ jakarta-taglibs-standard-1.1.2/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; /** *

Support for tag handlers for <transform>, the XML transformation @@ -66,6 +52,7 @@ public abstract class TransformSupport e // 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 @@ public abstract class TransformSupport e 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 @@ public abstract class TransformSupport e // 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 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 @@ public abstract class TransformSupport e 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 @@ public abstract class TransformSupport e // 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 abstract class TransformSupport e 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 +++ jakarta-taglibs-standard-1.1.2/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 +++ jakarta-taglibs-standard-1.1.2/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); + } + } +} --- jakarta-taglibs-standard-1.1.2.orig/standard/src/org/apache/taglibs/standard/tlv/JstlBaseTLV.java +++ jakarta-taglibs-standard-1.1.2/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.PageData 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 @@ public abstract class JstlBaseTLV extend 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 @@ public abstract class JstlBaseTLV extend } catch (SAXException ex) { return vmFromString(ex.toString()); - } catch (ParserConfigurationException ex) { - return vmFromString(ex.toString()); } catch (IOException ex) { return vmFromString(ex.toString()); } --- /dev/null +++ jakarta-taglibs-standard-1.1.2/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 +++ jakarta-taglibs-standard-1.1.2/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 { + /** + *

Valid characters in a scheme.

+ *

RFC 1738 says the following:

+ *
+ * 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"). + *
+ *

We treat as absolute any URL that begins with such a scheme name, + * followed by a colon.

+ */ +/* + 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 +++ jakarta-taglibs-standard-1.1.2/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() { + 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() { + 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() { + 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 the type of the result + * @param the type of the allowed Exception + * @return the result of the action + * @throws E if the action threw the allowed Exception + */ + private static T runWithOurClassLoader(final Callable action, Class allowed) throws E { + PrivilegedExceptionAction actionWithClassloader = new PrivilegedExceptionAction() { + 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); + } + } + } +} debian/ant.properties0000664000000000000000000000032512504310356012067 0ustar build.dir=build dist.dir=dist ant.build.javac.source=1.5 ant.build.javac.target=1.5 servlet24.jar=/usr/share/java/servlet-api-3.0.jar jsp20.jar=/usr/share/java/jsp-api-2.2.jar xalan.jar=/usr/share/java/xalan2.jar debian/copyright0000664000000000000000000000074711770243143011135 0ustar Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: jakarta-taglibs-standard Source: http://tomcat.apache.org/taglibs/standard/ Files: * Copyright: 1999-2004, The Apache Software Foundation License: Apache-2.0 Files: debian/* Copyright: 2010, Onkar Shinde License: Apache-2.0 License: Apache-2.0 On Debian systems the full text of the Apache-2.0 license can be found in the `/usr/share/common-licenses/Apache-2.0' file. debian/watch0000664000000000000000000000021411770243143010220 0ustar version=3 http://archive.apache.org/dist/jakarta/taglibs/standard/source jakarta-taglibs-standard-(.*)-src.tar.gz debian debian/orig-tar.sh debian/libjstl1.1-java.poms0000664000000000000000000000015411770243143012674 0ustar debian/poms/jstl.pom --java-lib --usj-name=jstl1.1 --artifact=standard/build/standard/standard/lib/jstl.jar debian/libjakarta-taglibs-standard-java.classpath0000664000000000000000000000013211770243143017336 0ustar usr/share/java/standard.jar servlet-api-2.5.jar jsp-api-2.1.jar el-api-2.1.jar xalan2.jar debian/maven.rules0000664000000000000000000000015211770243143011352 0ustar # Remap JSTL to 1.1 as this is the version of the API # Implemented javax.servlet jstl jar s/.*/1.1/ * * debian/rules0000775000000000000000000000142112001011156010231 0ustar #!/usr/bin/make -f export JAVA_HOME=/usr/lib/jvm/default-java export CLASSPATH=/usr/share/java/el-api-2.2.jar DEB_UPSTREAM_VERSION := $(shell dpkg-parsechangelog | sed -rne 's,^Version: ([^+]+)-.*,\1,p') MAVEN_REPO := http://repo1.maven.org/maven2 %: dh $@ --with maven_repo_helper,javahelper override_dh_auto_build: ant -propertyfile debian/ant.properties -f standard/build.xml get-orig-source: uscan --force-download --rename get-orig-pom: mkdir -p debian/poms wget -U NoSuchBrowser/1.0 -O debian/poms/jstl.pom \ $(MAVEN_REPO)/javax/servlet/jstl/$(DEB_UPSTREAM_VERSION)/jstl-$(DEB_UPSTREAM_VERSION).pom wget -U NoSuchBrowser/1.0 -O debian/poms/standard.pom \ $(MAVEN_REPO)/taglibs/standard/$(DEB_UPSTREAM_VERSION)/standard-$(DEB_UPSTREAM_VERSION).pom