ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/jasper/compiler/PageDataImpl.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/jasper/compiler/PageDataImpl.java
Status
scanned
Type
file
Name
PageDataImpl.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
25915 (25.3 KB)
MD5
c5ac35df63c13491deb354c683a96731
SHA1
c787738cebfb26147562ad2a1ef77c5e712e45dc
SHA256
0bba93760eb6ba0a72a3010464910aa4e90d46495c8f5b5c8ec272e0efee1e0e
SHA512

      
    
SHA1_git
217d0209329289479979721af1d03157b1163d0f
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
PageDataImpl.java | 25.3 KB |

/* * 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.jasper.compiler; import java.io.ByteArrayInputStream; import java.io.CharArrayWriter; import java.io.InputStream; import java.nio.charset.StandardCharsets; import jakarta.servlet.jsp.tagext.PageData; import org.apache.jasper.JasperException; import org.apache.tomcat.util.security.Escape; import org.xml.sax.Attributes; import org.xml.sax.helpers.AttributesImpl; /** * An implementation of <code>jakarta.servlet.jsp.tagext.PageData</code> which builds the XML view of a given page. The * XML view is built in two passes: During the first pass, the FirstPassVisitor collects the attributes of the top-level * jsp:root and those of the jsp:root elements of any included pages, and adds them to the jsp:root element of the XML * view. In addition, any taglib directives are converted into xmlns: attributes and added to the jsp:root element of * the XML view. This pass ignores any nodes other than JspRoot and TaglibDirective. During the second pass, the * SecondPassVisitor produces the XML view, using the combined jsp:root attributes determined in the first pass and any * remaining pages nodes (this pass ignores any JspRoot and TaglibDirective nodes). */ class PageDataImpl extends PageData implements TagConstants { private static final String JSP_VERSION = "2.0"; private static final String CDATA_START_SECTION = "<![CDATA[ "; private static final String CDATA_END_SECTION = "]]> "; // string buffer used to build XML view private final StringBuilder buf; /** * @param page the page nodes from which to generate the XML view * @param compiler The compiler for this page * * @throws JasperException If an error occurs */ PageDataImpl(Node.Nodes page, Compiler compiler) throws JasperException { // First pass FirstPassVisitor firstPass = new FirstPassVisitor(page.getRoot(), compiler.getPageInfo()); page.visit(firstPass); // Second pass buf = new StringBuilder(); SecondPassVisitor secondPass = new SecondPassVisitor(page.getRoot(), buf, compiler, firstPass.getJspIdPrefix()); page.visit(secondPass); } /** * Returns the input stream of the XML view. * * @return the input stream of the XML view */ @Override public InputStream getInputStream() { return new ByteArrayInputStream(buf.toString().getBytes(StandardCharsets.UTF_8)); } /* * First-pass Visitor for JspRoot nodes (representing jsp:root elements) and TaglibDirective nodes, ignoring any * other nodes. * * The purpose of this Visitor is to collect the attributes of the top-level jsp:root and those of the jsp:root * elements of any included pages, and add them to the jsp:root element of the XML view. In addition, this Visitor * converts any taglib directives into xmlns: attributes and adds them to the jsp:root element of the XML view. */ private static class FirstPassVisitor extends Node.Visitor implements TagConstants { private final Node.Root root; private final AttributesImpl rootAttrs; private final PageInfo pageInfo; // Prefix for the 'id' attribute private String jspIdPrefix; /* * Constructor */ FirstPassVisitor(Node.Root root, PageInfo pageInfo) { this.root = root; this.pageInfo = pageInfo; this.rootAttrs = new AttributesImpl(); this.rootAttrs.addAttribute("", "", "version", "CDATA", JSP_VERSION); this.jspIdPrefix = "jsp"; } @Override public void visit(Node.Root n) throws JasperException { visitBody(n); if (n == root) { /* * Top-level page. * * Add xmlns:jsp="http://java.sun.com/JSP/Page" attribute only if not already present. */ if (!JSP_URI.equals(rootAttrs.getValue("xmlns:jsp"))) { rootAttrs.addAttribute("", "", "xmlns:jsp", "CDATA", JSP_URI); } if (pageInfo.isJspPrefixHijacked()) { /* * 'jsp' prefix has been hijacked, that is, bound to a namespace other than the JSP namespace. This * means that when adding an 'id' attribute to each element, we can't use the 'jsp' prefix. * Therefore, create a new prefix (one that is unique across the translation unit) for use by the * 'id' attribute, and bind it to the JSP namespace */ do { jspIdPrefix += "jsp"; } while (pageInfo.containsPrefix(jspIdPrefix)); rootAttrs.addAttribute("", "", "xmlns:" + jspIdPrefix, "CDATA", JSP_URI); } root.setAttributes(rootAttrs); } } @Override public void visit(Node.JspRoot n) throws JasperException { addAttributes(n.getTaglibAttributes()); addAttributes(n.getNonTaglibXmlnsAttributes()); addAttributes(n.getAttributes()); visitBody(n); } /* * Converts taglib directive into "xmlns:..." attribute of jsp:root element. */ @Override public void visit(Node.TaglibDirective n) throws JasperException { Attributes attrs = n.getAttributes(); if (attrs != null) { String qName = "xmlns:" + attrs.getValue("prefix"); /* * According to javadocs of org.xml.sax.helpers.AttributesImpl, the addAttribute method does not check * to see if the specified attribute is already contained in the list: This is the application's * responsibility! */ if (rootAttrs.getIndex(qName) == -1) { String location = attrs.getValue("uri"); if (location != null) { if (location.startsWith("/")) { location = URN_JSPTLD + location; } rootAttrs.addAttribute("", "", qName, "CDATA", location); } else { location = attrs.getValue("tagdir"); rootAttrs.addAttribute("", "", qName, "CDATA", URN_JSPTAGDIR + location); } } } } public String getJspIdPrefix() { return jspIdPrefix; } private void addAttributes(Attributes attrs) { if (attrs != null) { int len = attrs.getLength(); for (int i = 0; i < len; i++) { String qName = attrs.getQName(i); if ("version".equals(qName)) { continue; } // Bugzilla 35252: https://bz.apache.org/bugzilla/show_bug.cgi?id=35252 if (rootAttrs.getIndex(qName) == -1) { rootAttrs.addAttribute(attrs.getURI(i), attrs.getLocalName(i), qName, attrs.getType(i), attrs.getValue(i)); } } } } } /* * Second-pass Visitor responsible for producing XML view and assigning each element a unique jsp:id attribute. */ private static class SecondPassVisitor extends Node.Visitor implements TagConstants { private final Node.Root root; private final StringBuilder buf; private final Compiler compiler; private final String jspIdPrefix; private boolean resetDefaultNS = false; // Current value of jsp:id attribute private int jspId; /* * Constructor */ SecondPassVisitor(Node.Root root, StringBuilder buf, Compiler compiler, String jspIdPrefix) { this.root = root; this.buf = buf; this.compiler = compiler; this.jspIdPrefix = jspIdPrefix; } /* * Visits root node. */ @Override public void visit(Node.Root n) throws JasperException { if (n == this.root) { // top-level page appendXmlProlog(); appendTag(n); } else { boolean resetDefaultNSSave = resetDefaultNS; if (n.isXmlSyntax()) { resetDefaultNS = true; } visitBody(n); resetDefaultNS = resetDefaultNSSave; } } /* * Visits jsp:root element of JSP page in XML syntax. * * Any nested jsp:root elements (from pages included via an include directive) are ignored. */ @Override public void visit(Node.JspRoot n) throws JasperException { visitBody(n); } @Override public void visit(Node.PageDirective n) throws JasperException { appendPageDirective(n); } @Override public void visit(Node.IncludeDirective n) throws JasperException { // expand in place visitBody(n); } @Override public void visit(Node.Comment n) throws JasperException { // Comments are ignored in XML view } @Override public void visit(Node.Declaration n) throws JasperException { appendTag(n); } @Override public void visit(Node.Expression n) throws JasperException { appendTag(n); } @Override public void visit(Node.Scriptlet n) throws JasperException { appendTag(n); } @Override public void visit(Node.JspElement n) throws JasperException { appendTag(n); } @Override public void visit(Node.ELExpression n) throws JasperException { if (!n.getRoot().isXmlSyntax()) { buf.append('<').append(JSP_TEXT_ACTION); buf.append(' '); buf.append(jspIdPrefix); buf.append(":id=\""); buf.append(jspId++).append("\">"); } buf.append("${"); buf.append(Escape.xml(n.getText())); buf.append('}'); if (!n.getRoot().isXmlSyntax()) { buf.append(JSP_TEXT_ACTION_END); } buf.append(" "); } @Override public void visit(Node.IncludeAction n) throws JasperException { appendTag(n); } @Override public void visit(Node.ForwardAction n) throws JasperException { appendTag(n); } @Override public void visit(Node.GetProperty n) throws JasperException { appendTag(n); } @Override public void visit(Node.SetProperty n) throws JasperException { appendTag(n); } @Override public void visit(Node.ParamAction n) throws JasperException { appendTag(n); } @Override public void visit(Node.UseBean n) throws JasperException { appendTag(n); } @Override public void visit(Node.NamedAttribute n) throws JasperException { appendTag(n); } @Override public void visit(Node.JspBody n) throws JasperException { appendTag(n); } @Override public void visit(Node.CustomTag n) throws JasperException { boolean resetDefaultNSSave = resetDefaultNS; appendTag(n, resetDefaultNS); resetDefaultNS = resetDefaultNSSave; } @Override public void visit(Node.UninterpretedTag n) throws JasperException { boolean resetDefaultNSSave = resetDefaultNS; appendTag(n, resetDefaultNS); resetDefaultNS = resetDefaultNSSave; } @Override public void visit(Node.JspText n) throws JasperException { appendTag(n); } @Override public void visit(Node.DoBodyAction n) throws JasperException { appendTag(n); } @Override public void visit(Node.InvokeAction n) throws JasperException { appendTag(n); } @Override public void visit(Node.TagDirective n) throws JasperException { appendTagDirective(n); } @Override public void visit(Node.AttributeDirective n) throws JasperException { appendTag(n); } @Override public void visit(Node.VariableDirective n) throws JasperException { appendTag(n); } @Override public void visit(Node.TemplateText n) throws JasperException { /* * If the template text came from a JSP page written in JSP syntax, create a jsp:text element for it (JSP * 5.3.2). */ appendText(n.getText(), !n.getRoot().isXmlSyntax()); } /* * Appends the given tag, including its body, to the XML view. */ private void appendTag(Node n) throws JasperException { appendTag(n, false); } /* * Appends the given tag, including its body, to the XML view, and optionally reset default namespace to "", if * none specified. */ private void appendTag(Node n, boolean addDefaultNS) throws JasperException { Node.Nodes body = n.getBody(); String text = n.getText(); buf.append('<').append(n.getQName()); buf.append(" "); printAttributes(n, addDefaultNS); buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); buf.append(jspId++).append("\" "); if (ROOT_ACTION.equals(n.getLocalName()) || body != null || text != null) { buf.append("> "); if (ROOT_ACTION.equals(n.getLocalName())) { if (compiler.getCompilationContext().isTagFile()) { appendTagDirective(); } else { appendPageDirective(); } } if (body != null) { body.visit(this); } else { appendText(text, false); } buf.append("</").append(n.getQName()).append("> "); } else { buf.append("/> "); } } /* * Appends the page directive with the given attributes to the XML view. * * Since the import attribute of the page directive is the only page attribute that is allowed to appear * multiple times within the same document, and since XML allows only single-value attributes, the values of * multiple import attributes must be combined into one, separated by comma. * * If the given page directive contains just 'contentType' and/or 'pageEncoding' attributes, we ignore it, as * we've already appended a page directive containing just these two attributes. */ private void appendPageDirective(Node.PageDirective n) { boolean append = false; Attributes attrs = n.getAttributes(); int len = (attrs == null) ? 0 : attrs.getLength(); for (int i = 0; i < len; i++) { @SuppressWarnings("null") // If attrs==null, len == 0 String attrName = attrs.getQName(i); if (!"pageEncoding".equals(attrName) && !"contentType".equals(attrName)) { append = true; break; } } if (!append) { return; } buf.append('<').append(n.getQName()); buf.append(" "); // append jsp:id buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); buf.append(jspId++).append("\" "); // append remaining attributes for (int i = 0; i < len; i++) { @SuppressWarnings("null") // If attrs==null, len == 0 String attrName = attrs.getQName(i); if ("import".equals(attrName) || "contentType".equals(attrName) || "pageEncoding".equals(attrName)) { /* * Page directive's 'import' attribute is considered further down, and its 'pageEncoding' and * 'contentType' attributes are ignored, since we've already appended a new page directive * containing just these two attributes */ continue; } String value = attrs.getValue(i); buf.append(" ").append(attrName).append("=\""); buf.append(JspUtil.getExprInXml(value)).append("\" "); } if (!n.getImports().isEmpty()) { // Concatenate names of imported classes/packages boolean first = true; for (String i : n.getImports()) { if (first) { first = false; buf.append(" import=\""); } else { buf.append(','); } buf.append(JspUtil.getExprInXml(i)); } buf.append("\" "); } buf.append("/> "); } /* * Appends a page directive with 'pageEncoding' and 'contentType' attributes. * * The value of the 'pageEncoding' attribute is hard-coded to UTF-8, whereas the value of the 'contentType' * attribute, which is identical to what the container will pass to ServletResponse.setContentType(), is derived * from the pageInfo. */ private void appendPageDirective() { buf.append('<').append(JSP_PAGE_DIRECTIVE_ACTION); buf.append(" "); // append jsp:id buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); buf.append(jspId++).append("\" "); buf.append(" ").append("pageEncoding").append("=\"UTF-8\" "); buf.append(" ").append("contentType").append("=\""); buf.append(compiler.getPageInfo().getContentType()).append("\" "); buf.append("/> "); } /* * Appends the tag directive with the given attributes to the XML view. * * If the given tag directive contains just a 'pageEncoding' attributes, we ignore it, as we've already appended * a tag directive containing just this attributes. */ private void appendTagDirective(Node.TagDirective n) throws JasperException { boolean append = false; Attributes attrs = n.getAttributes(); int len = (attrs == null) ? 0 : attrs.getLength(); for (int i = 0; i < len; i++) { @SuppressWarnings("null") // If attrs==null, len == 0 String attrName = attrs.getQName(i); if (!"pageEncoding".equals(attrName)) { append = true; break; } } if (!append) { return; } appendTag(n); } /* * Appends a tag directive containing a single 'pageEncoding' attribute whose value is hard-coded to UTF-8. */ private void appendTagDirective() { buf.append('<').append(JSP_TAG_DIRECTIVE_ACTION); buf.append(" "); // append jsp:id buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); buf.append(jspId++).append("\" "); buf.append(" ").append("pageEncoding").append("=\"UTF-8\" "); buf.append("/> "); } private void appendText(String text, boolean createJspTextElement) { if (createJspTextElement) { buf.append('<').append(JSP_TEXT_ACTION); buf.append(" "); // append jsp:id buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); buf.append(jspId++).append("\" "); buf.append("> "); appendCDATA(text); buf.append(JSP_TEXT_ACTION_END); buf.append(" "); } else { appendCDATA(text); } } /* * Appends the given text as a CDATA section to the XML view, unless the text has already been marked as CDATA. */ private void appendCDATA(String text) { buf.append(CDATA_START_SECTION); buf.append(escapeCDATA(text)); buf.append(CDATA_END_SECTION); } /* * Escapes any occurrences of "]]>" (by replacing them with "]]&gt;") within the given text, so it can be * included in a CDATA section. */ private String escapeCDATA(String text) { if (text == null) { return ""; } int len = text.length(); CharArrayWriter result = new CharArrayWriter(len); for (int i = 0; i < len; i++) { if (((i + 2) < len) && (text.charAt(i) == ']') && (text.charAt(i + 1) == ']') && (text.charAt(i + 2) == '>')) { // match found result.write(']'); result.write(']'); result.write('&'); result.write('g'); result.write('t'); result.write(';'); i += 2; } else { result.write(text.charAt(i)); } } return result.toString(); } /* * Appends the attributes of the given Node to the XML view. */ private void printAttributes(Node n, boolean addDefaultNS) { /* * Append "xmlns" attributes that represent tag libraries */ Attributes attrs = n.getTaglibAttributes(); int len = (attrs == null) ? 0 : attrs.getLength(); for (int i = 0; i < len; i++) { @SuppressWarnings("null") // If attrs==null, len == 0 String name = attrs.getQName(i); String value = attrs.getValue(i); buf.append(" ").append(name).append("=\"").append(value).append("\" "); } /* * Append "xmlns" attributes that do not represent tag libraries */ attrs = n.getNonTaglibXmlnsAttributes(); len = (attrs == null) ? 0 : attrs.getLength(); boolean defaultNSSeen = false; for (int i = 0; i < len; i++) { @SuppressWarnings("null") // If attrs==null, len == 0 String name = attrs.getQName(i); String value = attrs.getValue(i); buf.append(" ").append(name).append("=\"").append(value).append("\" "); defaultNSSeen |= "xmlns".equals(name); } if (addDefaultNS && !defaultNSSeen) { buf.append(" xmlns=\"\" "); } resetDefaultNS = false; /* * Append all other attributes */ attrs = n.getAttributes(); len = (attrs == null) ? 0 : attrs.getLength(); for (int i = 0; i < len; i++) { @SuppressWarnings("null") // If attrs==null, len == 0 String name = attrs.getQName(i); String value = attrs.getValue(i); buf.append(" ").append(name).append("=\""); buf.append(JspUtil.getExprInXml(value)).append("\" "); } } /* * Appends XML prolog with encoding declaration. */ private void appendXmlProlog() { buf.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?> "); } } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
5.0
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9
http://java.sun.com/JSP/Page 112 112
https://bz.apache.org/bugzilla/show_bug.cgi?id=35252 186 186