Author: jboynes Date: Sat Nov 29 16:06:54 2014 New Revision: 1642442 URL: http://svn.apache.org/r1642442 Log: Refactor and consolidate XML processing
Added: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java (with props) tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java (with props) tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java (with props) Modified: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java Modified: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/ImportSupport.java Sat Nov 29 16:06:54 2014 @@ -47,6 +47,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; /** * <p>Support for tag handlers for <import>, the general-purpose @@ -63,23 +64,6 @@ public abstract class ImportSupport exte // 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"; @@ -141,7 +125,7 @@ public abstract class ImportSupport exte } // 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 @@ -579,47 +563,11 @@ public abstract class ImportSupport exte 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) Modified: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/RedirectSupport.java Sat Nov 29 16:06:54 2014 @@ -23,6 +23,8 @@ import javax.servlet.jsp.JspTagException 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> @@ -108,7 +110,7 @@ public abstract class RedirectSupport ex // if the URL is relative, rewrite it with 'redirect' encoding rules HttpServletResponse response = ((HttpServletResponse) pageContext.getResponse()); - if (!ImportSupport.isAbsoluteUrl(result)) { + if (!UrlUtil.isAbsoluteUrl(result)) { result = response.encodeRedirectURL(result); } Modified: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/core/UrlSupport.java Sat Nov 29 16:06:54 2014 @@ -25,6 +25,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; /** * <p>Support for tag handlers for <url>, the URL creation @@ -110,7 +111,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); @@ -144,7 +145,7 @@ public abstract class UrlSupport extends String url, String context, PageContext pageContext) throws JspException { // don't touch absolute URLs - if (ImportSupport.isAbsoluteUrl(url)) { + if (UrlUtil.isAbsoluteUrl(url)) { return url; } Modified: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/ParseSupport.java Sat Nov 29 16:06:54 2014 @@ -17,36 +17,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> @@ -69,12 +59,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; //********************************************************************* @@ -90,15 +75,10 @@ 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 @@ -106,68 +86,41 @@ public abstract class ParseSupport exten @Override public int doEndTag() throws JspException { - try { - - // set up our DocumentBuilder - if (dbf == null) { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - } - 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); + // 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 { - throw new JspTagException( - Resources.getMessage("PARSE_INVALID_SOURCE")); + 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); - // 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); - } + Document d; + if (filter != null) { + d = parseInputSourceWithFilter(source, filter); + } else { + d = parseInputSource(source); + } - 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); + // 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; } // Releases any resources we may have (or inherit) @@ -184,151 +137,50 @@ public abstract class ParseSupport exten /** * 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); + + TransformerHandler th = XmlUtil.newTransformerHandler(); + Document o = XmlUtil.newEmptyDocument(); + th.setResult(new DOMResult(o)); f.setContentHandler(th); + f.parse(s); return o; - } else { - return parseInputSource(s); + } catch (IOException e) { + throw new JspException(e); + } catch (SAXException e) { + throw new JspException(e); + } catch (TransformerConfigurationException e) { + throw new JspException(e); } } /** - * 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); - } - - /** - * 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); - } - - /** - * 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); - } - - /** * 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); + 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); } - 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; - } - - 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); - } + @Override + public void setPageContext(PageContext pageContext) { + super.setPageContext(pageContext); + entityResolver = pageContext == null ? null: new XmlUtil.JstlEntityResolver(pageContext); } //********************************************************************* Modified: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/TransformSupport.java Sat Nov 29 16:06:54 2014 @@ -17,43 +17,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 @@ -79,24 +65,14 @@ 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 XmlUtil.JstlEntityResolver entityResolver; + private XmlUtil.JstlUriResolver uriResolver; //********************************************************************* // Constructor and initialization public TransformSupport() { - try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - db = dbf.newDocumentBuilder(); - tf = TransformerFactory.newInstance(); - } catch (ParserConfigurationException e) { - throw (AssertionError) new AssertionError("Unable to create DocumentBuilder").initCause(e); - } - init(); } @@ -106,7 +82,6 @@ public abstract class TransformSupport e xmlSystemId = xsltSystemId = null; var = null; result = null; - tf.setURIResolver(null); scope = PageContext.PAGE_SCOPE; } @@ -117,36 +92,69 @@ public abstract class TransformSupport e @Override public int doStartTag() throws JspException { // set up transformer in the start tag so that nested <param> tags can set parameters directly - t = getTransformer(xslt, xsltSystemId); + 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; } @Override public int doEndTag() throws JspException { - Source source = xmlSpecified ? getSourceFromXmlAttribute() : getDocumentFromBodyContent(); try { - //************************************ - // Conduct the transformation + Source source = xmlSpecified ? getSourceFromXmlAttribute() : getSourceFromBodyContent(); - // 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(); + // 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 { - Result page = new StreamResult(new SafeWriter(pageContext.getOut())); - t.transform(source, page); + // 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; } } @@ -161,7 +169,8 @@ public abstract class TransformSupport e @Override public void setPageContext(PageContext pageContext) { super.setPageContext(pageContext); - tf.setURIResolver(pageContext == null ? null : new JstlUriResolver(pageContext)); + uriResolver = pageContext == null ? null : new XmlUtil.JstlUriResolver(pageContext); + entityResolver = pageContext == null ? null : new XmlUtil.JstlEntityResolver(pageContext); } @@ -180,64 +189,12 @@ 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. - */ - private static String wrapSystemId(String systemId) { - if (systemId == null) { - return "jstl:"; - } else if (ImportSupport.isAbsoluteUrl(systemId)) { - return systemId; - } else { - return ("jstl:" + systemId); - } - } - - /** - * Create a Transformer from the xslt attribute. - * - * @param xslt the xslt attribute - * @param systemId the systemId for the transform - * @return an XSLT transformer - * @throws JspException if there was a problem creating the transformer - */ - Transformer getTransformer(Object xslt, String systemId) throws JspException { - if (xslt == null) { - throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_NULL")); - } - Source source; - 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")); - } - xslt = new StringReader(s); - } - if (xslt instanceof Reader) { - source = getSource((Reader) xslt, systemId); - } else { - throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_UNSUPPORTED_TYPE", xslt.getClass())); - } - } - try { - return tf.newTransformer(source); - } catch (TransformerConfigurationException e) { - throw new JspTagException(e); - } - } - - /** * 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 */ - Source getSourceFromXmlAttribute() throws JspTagException { + Source getSourceFromXmlAttribute() throws JspTagException, SAXException { Object xml = this.xml; if (xml == null) { throw new JspTagException(Resources.getMessage("TRANSFORM_XML_IS_NULL")); @@ -261,10 +218,10 @@ public abstract class TransformSupport e if (s.length() == 0) { throw new JspTagException(Resources.getMessage("TRANSFORM_XML_IS_EMPTY")); } - return getSource(new StringReader(s), xmlSystemId); + return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, entityResolver); } if (xml instanceof Reader) { - return getSource((Reader) xml, xmlSystemId); + return XmlUtil.newSAXSource((Reader) xml, xmlSystemId, entityResolver); } if (xml instanceof Node) { return new DOMSource((Node) xml, xmlSystemId); @@ -278,7 +235,7 @@ public abstract class TransformSupport e * @return the document Source * @throws JspTagException if there is a problem with the body content */ - Source getDocumentFromBodyContent() throws JspTagException { + Source getSourceFromBodyContent() throws JspTagException, SAXException { if (bodyContent == null) { throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_NULL")); } @@ -290,31 +247,7 @@ public abstract class TransformSupport e if (s.length() == 0) { throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_EMPTY")); } - return getSource(new StringReader(s), xmlSystemId); - } - - /** - * Create a Source from a Reader - * - * @param reader the Reader to read - * @param systemId the systemId for the document - * @return a SAX Source - * @throws JspTagException if there is a problem creating the Source - */ - Source getSource(Reader reader, String systemId) throws JspTagException { - try { - // 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); - s.setSystemId(wrapSystemId(systemId)); - Source source = new SAXSource(xr, s); - source.setSystemId(wrapSystemId(systemId)); - return source; - } catch (SAXException e) { - throw new JspTagException(e); - } + return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, entityResolver); } @@ -328,109 +261,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 { - // TODO: shouldn't we be delegating all methods? - private Writer w; - - public SafeWriter(Writer w) { - this.w = w; - } - - @Override - public void close() { - } - - @Override - public void flush() { - } - - @Override - 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); - } - } - } Modified: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XalanUtil.java Sat Nov 29 16:06:54 2014 @@ -19,9 +19,6 @@ package org.apache.taglibs.standard.tag. import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; import javax.servlet.jsp.tagext.TagSupport; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import org.apache.xpath.VariableStack; @@ -31,21 +28,11 @@ 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.Document; import org.w3c.dom.NodeList; /** */ public class XalanUtil { - private static final DocumentBuilderFactory dbf; - - static { - // from Java5 on DocumentBuilderFactory is thread safe and hence can be cached - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - } - /** * Return the XPathContext to be used for evaluating expressions. * @@ -67,29 +54,12 @@ public class XalanUtil { XPathContext context = new XPathContext(false); VariableStack variableStack = new JSTLVariableStack(pageContext); context.setVarStack(variableStack); - int dtm = context.getDTMHandleFromNode(newEmptyDocument()); + int dtm = context.getDTMHandleFromNode(XmlUtil.newEmptyDocument()); context.pushCurrentNodeAndExpression(dtm, dtm); return context; } /** - * 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 - */ - private static Document newEmptyDocument() { - try { - DocumentBuilder db = dbf.newDocumentBuilder(); - return db.newDocument(); - } catch (ParserConfigurationException e) { - throw new AssertionError(); - } - } - - /** * Return the Java value corresponding to an XPath result. * * @param xo the XPath type Added: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java?rev=1642442&view=auto ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java (added) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java Sat Nov 29 16:06:54 2014 @@ -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); + } + } +} Propchange: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/tag/common/xml/XmlUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java?rev=1642442&view=auto ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java (added) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java Sat Nov 29 16:06:54 2014 @@ -0,0 +1,47 @@ +/* + * 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; + } + + @Override + public void close() { + } + + @Override + public void flush() { + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + w.write(cbuf, off, len); + } +} Propchange: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UnclosableWriter.java ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java?rev=1642442&view=auto ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java (added) +++ tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java Sat Nov 29 16:06:54 2014 @@ -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; + } +} Propchange: tomcat/taglibs/standard/trunk/impl/src/main/java/org/apache/taglibs/standard/util/UrlUtil.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ExprSupportTest.java Sat Nov 29 16:06:54 2014 @@ -21,7 +21,6 @@ import java.io.InputStream; import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.PageContext; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import org.junit.Before; import org.junit.BeforeClass; @@ -45,10 +44,7 @@ public class ExprSupportTest { @BeforeClass public static void loadXml() throws Exception { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - DocumentBuilder db = dbf.newDocumentBuilder(); + DocumentBuilder db = XmlUtil.newDocumentBuilder(); InputStream is = ExprSupportTest.class.getResourceAsStream("test.xml"); try { test = db.parse(is); Modified: tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/ForEachTagTest.java Sat Nov 29 16:06:54 2014 @@ -20,41 +20,33 @@ import java.io.InputStream; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.IterationTag; -import javax.servlet.jsp.tagext.Tag; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPathConstants; -import org.apache.xpath.XPath; -import org.apache.xpath.XPathContext; -import org.apache.xpath.objects.XObject; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import sun.security.krb5.internal.TGSRep; +import org.apache.xpath.XPath; +import org.apache.xpath.XPathContext; +import org.apache.xpath.objects.XObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; /** */ public class ForEachTagTest { private static Document test; - private static DocumentBuilderFactory dbf; @BeforeClass public static void loadXml() throws Exception { - dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - DocumentBuilder db = dbf.newDocumentBuilder(); + DocumentBuilder db = XmlUtil.newDocumentBuilder(); InputStream is = ExprSupportTest.class.getResourceAsStream("test.xml"); try { test = db.parse(is); @@ -126,8 +118,7 @@ public class ForEachTagTest { public void testIterationPerformance() throws Exception { // create a large document final int SIZE = 200000; - DocumentBuilder db = dbf.newDocumentBuilder(); - test = db.newDocument(); + test = XmlUtil.newEmptyDocument(); Element root = test.createElement("root"); test.appendChild(root); for (int i = 0; i < SIZE; i++) { Modified: tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java URL: http://svn.apache.org/viewvc/tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java?rev=1642442&r1=1642441&r2=1642442&view=diff ============================================================================== --- tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java (original) +++ tomcat/taglibs/standard/trunk/impl/src/test/java/org/apache/taglibs/standard/tag/common/xml/JSTLVariableStackTest.java Sat Nov 29 16:06:54 2014 @@ -20,11 +20,13 @@ import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.jsp.PageContext; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + import org.apache.xml.utils.QName; import org.apache.xpath.XPathContext; import org.apache.xpath.objects.XBoolean; @@ -32,16 +34,12 @@ import org.apache.xpath.objects.XNodeSet import org.apache.xpath.objects.XNumber; import org.apache.xpath.objects.XObjectFactory; import org.apache.xpath.objects.XString; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; +import org.w3c.dom.Document; +import org.w3c.dom.Element; /** */ @@ -156,11 +154,7 @@ public class JSTLVariableStackTest { Assert.assertTrue(XObjectFactory.create(1234, xpathContext) instanceof XNumber); Assert.assertTrue(XObjectFactory.create("Hello", xpathContext) instanceof XString); - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document d = db.newDocument(); + Document d = XmlUtil.newEmptyDocument(); Element root = d.createElement("root"); XNodeSetForDOM xo = (XNodeSetForDOM) XObjectFactory.create(root, xpathContext); Assert.assertEquals(root, xo.object()); --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org