/* * 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;
/** * Performs validation on the page elements. Attributes are checked for * mandatory presence, entry value validity, and consistency. As a side effect, * some page global value (such as those from page directives) are stored, for * later use. * * @author Kin-man Chung * @author Jan Luehe * @author Shawn Bayern * @author Mark Roth
*/ class Validator {
/** * A visitor to validate and extract page directive info
*/ privatestaticclass DirectiveVisitor extends Node.Visitor {
privatefinal PageInfo pageInfo;
privatefinal ErrorDispatcher err;
privatestaticfinal JspUtil.ValidAttribute[] pageDirectiveAttrs = { new JspUtil.ValidAttribute("language"), new JspUtil.ValidAttribute("extends"), new JspUtil.ValidAttribute("import"), new JspUtil.ValidAttribute("session"), new JspUtil.ValidAttribute("buffer"), new JspUtil.ValidAttribute("autoFlush"), new JspUtil.ValidAttribute("isThreadSafe"), new JspUtil.ValidAttribute("info"), new JspUtil.ValidAttribute("errorPage"), new JspUtil.ValidAttribute("isErrorPage"), new JspUtil.ValidAttribute("contentType"), new JspUtil.ValidAttribute("pageEncoding"), new JspUtil.ValidAttribute("isELIgnored"), new JspUtil.ValidAttribute("errorOnELNotFound"), new JspUtil.ValidAttribute("deferredSyntaxAllowedAsLiteral"), new JspUtil.ValidAttribute("trimDirectiveWhitespaces")
};
@Override publicvoid visit(Node.IncludeDirective n) throws JasperException { // Since pageDirectiveSeen flag only applies to the Current page // save it here and restore it after the file is included. boolean pageEncodingSeenSave = pageEncodingSeen;
pageEncodingSeen = false;
visitBody(n);
pageEncodingSeen = pageEncodingSeenSave;
}
JspUtil.checkAttributes("Page directive", n, pageDirectiveAttrs,
err);
// JSP.2.10.1
Attributes attrs = n.getAttributes(); for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
String attr = attrs.getQName(i);
String value = attrs.getValue(i);
if ("language".equals(attr)) { if (pageInfo.getLanguage(false) == null) {
pageInfo.setLanguage(value, n, err, true);
} elseif (!pageInfo.getLanguage(false).equals(value)) {
err.jspError(n, "jsp.error.page.conflict.language",
pageInfo.getLanguage(false), value);
}
} elseif ("extends".equals(attr)) { if (pageInfo.getExtends(false) == null) {
pageInfo.setExtends(value);
} elseif (!pageInfo.getExtends(false).equals(value)) {
err.jspError(n, "jsp.error.page.conflict.extends",
pageInfo.getExtends(false), value);
}
} elseif ("contentType".equals(attr)) { if (pageInfo.getContentType() == null) {
pageInfo.setContentType(value);
} elseif (!pageInfo.getContentType().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.contenttype",
pageInfo.getContentType(), value);
}
} elseif ("session".equals(attr)) { if (pageInfo.getSession() == null) {
pageInfo.setSession(value, n, err);
} elseif (!pageInfo.getSession().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.session",
pageInfo.getSession(), value);
}
} elseif ("buffer".equals(attr)) { if (pageInfo.getBufferValue() == null) {
pageInfo.setBufferValue(value, n, err);
} elseif (!pageInfo.getBufferValue().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.buffer",
pageInfo.getBufferValue(), value);
}
} elseif ("autoFlush".equals(attr)) { if (pageInfo.getAutoFlush() == null) {
pageInfo.setAutoFlush(value, n, err);
} elseif (!pageInfo.getAutoFlush().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.autoflush",
pageInfo.getAutoFlush(), value);
}
} elseif ("isThreadSafe".equals(attr)) { if (pageInfo.getIsThreadSafe() == null) {
pageInfo.setIsThreadSafe(value, n, err);
} elseif (!pageInfo.getIsThreadSafe().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.isthreadsafe",
pageInfo.getIsThreadSafe(), value);
}
} elseif ("isELIgnored".equals(attr)) { if (pageInfo.getIsELIgnored() == null) {
pageInfo.setIsELIgnored(value, n, err, true);
} elseif (!pageInfo.getIsELIgnored().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.iselignored",
pageInfo.getIsELIgnored(), value);
}
} elseif ("errorOnELNotFound".equals(attr)) { if (pageInfo.getErrorOnELNotFound() == null) {
pageInfo.setErrorOnELNotFound(value, n, err, true);
} elseif (!pageInfo.getErrorOnELNotFound().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.errorOnELNotFound",
pageInfo.getErrorOnELNotFound(), value);
}
} elseif ("isErrorPage".equals(attr)) { if (pageInfo.getIsErrorPage() == null) {
pageInfo.setIsErrorPage(value, n, err);
} elseif (!pageInfo.getIsErrorPage().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.iserrorpage",
pageInfo.getIsErrorPage(), value);
}
} elseif ("errorPage".equals(attr)) { if (pageInfo.getErrorPage() == null) {
pageInfo.setErrorPage(value);
} elseif (!pageInfo.getErrorPage().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.errorpage",
pageInfo.getErrorPage(), value);
}
} elseif ("info".equals(attr)) { if (pageInfo.getInfo() == null) {
pageInfo.setInfo(value);
} elseif (!pageInfo.getInfo().equals(value)) {
err.jspError(n, "jsp.error.page.conflict.info",
pageInfo.getInfo(), value);
}
} elseif ("pageEncoding".equals(attr)) { if (pageEncodingSeen) {
err.jspError(n, "jsp.error.page.multi.pageencoding");
} // 'pageEncoding' can occur at most once per file
pageEncodingSeen = true;
String actual = comparePageEncodings(value, n);
n.getRoot().setPageEncoding(actual);
} elseif ("deferredSyntaxAllowedAsLiteral".equals(attr)) { if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) {
pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n,
err, true);
} elseif (!pageInfo.getDeferredSyntaxAllowedAsLiteral()
.equals(value)) {
err
.jspError(
n, "jsp.error.page.conflict.deferredsyntaxallowedasliteral",
pageInfo
.getDeferredSyntaxAllowedAsLiteral(),
value);
}
} elseif ("trimDirectiveWhitespaces".equals(attr)) { if (pageInfo.getTrimDirectiveWhitespaces() == null) {
pageInfo.setTrimDirectiveWhitespaces(value, n, err, true);
} elseif (!pageInfo.getTrimDirectiveWhitespaces().equals(
value)) {
err
.jspError(
n, "jsp.error.page.conflict.trimdirectivewhitespaces",
pageInfo.getTrimDirectiveWhitespaces(),
value);
}
}
}
// Check for bad combinations if (pageInfo.getBuffer() == 0 && !pageInfo.isAutoFlush()) {
err.jspError(n, "jsp.error.page.badCombo");
}
// Attributes for imports for this node have been processed by // the parsers, just add them to pageInfo.
pageInfo.addImports(n.getImports());
}
@Override publicvoid visit(Node.TagDirective n) throws JasperException { // Note: Most of the validation is done in TagFileProcessor // when it created a TagInfo object from the // tag file in which the directive appeared.
// This method does additional processing to collect page info
Attributes attrs = n.getAttributes(); for (int i = 0; attrs != null && i < attrs.getLength(); i++) {
String attr = attrs.getQName(i);
String value = attrs.getValue(i);
if ("language".equals(attr)) { if (pageInfo.getLanguage(false) == null) {
pageInfo.setLanguage(value, n, err, false);
} elseif (!pageInfo.getLanguage(false).equals(value)) {
err.jspError(n, "jsp.error.tag.conflict.language",
pageInfo.getLanguage(false), value);
}
} elseif ("isELIgnored".equals(attr)) { if (pageInfo.getIsELIgnored() == null) {
pageInfo.setIsELIgnored(value, n, err, false);
} elseif (!pageInfo.getIsELIgnored().equals(value)) {
err.jspError(n, "jsp.error.tag.conflict.iselignored",
pageInfo.getIsELIgnored(), value);
}
} elseif ("errorOnELNotFound".equals(attr)) { if (pageInfo.getErrorOnELNotFound() == null) {
pageInfo.setErrorOnELNotFound(value, n, err, false);
} elseif (!pageInfo.getErrorOnELNotFound().equals(value)) {
err.jspError(n, "jsp.error.tag.conflict.errorOnELNotFound",
pageInfo.getErrorOnELNotFound(), value);
}
} elseif ("pageEncoding".equals(attr)) { if (pageEncodingSeen) {
err.jspError(n, "jsp.error.tag.multi.pageencoding");
}
pageEncodingSeen = true;
compareTagEncodings(value, n);
n.getRoot().setPageEncoding(value);
} elseif ("deferredSyntaxAllowedAsLiteral".equals(attr)) { if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) {
pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n,
err, false);
} elseif (!pageInfo.getDeferredSyntaxAllowedAsLiteral()
.equals(value)) {
err
.jspError(
n, "jsp.error.tag.conflict.deferredsyntaxallowedasliteral",
pageInfo
.getDeferredSyntaxAllowedAsLiteral(),
value);
}
} elseif ("trimDirectiveWhitespaces".equals(attr)) { if (pageInfo.getTrimDirectiveWhitespaces() == null) {
pageInfo.setTrimDirectiveWhitespaces(value, n, err, false);
} elseif (!pageInfo.getTrimDirectiveWhitespaces().equals(
value)) {
err
.jspError(
n, "jsp.error.tag.conflict.trimdirectivewhitespaces",
pageInfo.getTrimDirectiveWhitespaces(),
value);
}
}
}
// Attributes for imports for this node have been processed by // the parsers, just add them to pageInfo.
pageInfo.addImports(n.getImports());
}
@Override publicvoid visit(Node.AttributeDirective n) throws JasperException { // Do nothing, since this attribute directive has already been // validated by TagFileProcessor when it created a TagInfo object // from the tag file in which the directive appeared
}
@Override publicvoid visit(Node.VariableDirective n) throws JasperException { // Do nothing, since this variable directive has already been // validated by TagFileProcessor when it created a TagInfo object // from the tag file in which the directive appeared
}
/* * Compares page encodings specified in various places, and throws * exception in case of page encoding mismatch. * * @param pageDirEnc The value of the pageEncoding attribute of the page * directive @param pageDir The page directive node * * @throws JasperException in case of page encoding mismatch
*/ private String comparePageEncodings(String thePageDirEnc,
Node.PageDirective pageDir) throws JasperException {
/* * Compare the 'pageEncoding' attribute of the page directive with * the encoding specified in the JSP config element whose URL * pattern matches this page. Treat "UTF-16", "UTF-16BE", and * "UTF-16LE" as identical.
*/ if (configEnc != null) {
configEnc = configEnc.toUpperCase(Locale.ENGLISH); if (!pageDirEnc.equals(configEnc)
&& (!pageDirEnc.startsWith("UTF-16") || !configEnc
.startsWith("UTF-16"))) {
err.jspError(pageDir, "jsp.error.config_pagedir_encoding_mismatch",
configEnc, pageDirEnc);
} else { return configEnc;
}
}
/* * Compare the 'pageEncoding' attribute of the page directive with * the encoding specified in the XML prolog (only for XML syntax, * and only if JSP document contains XML prolog with encoding * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as * identical.
*/ if ((root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) || root.isBomPresent()) {
String pageEnc = root.getPageEncoding().toUpperCase(Locale.ENGLISH); if (!pageDirEnc.equals(pageEnc)
&& (!pageDirEnc.startsWith("UTF-16") || !pageEnc
.startsWith("UTF-16"))) {
err.jspError(pageDir, "jsp.error.prolog_pagedir_encoding_mismatch",
pageEnc, pageDirEnc);
} else { return pageEnc;
}
}
return pageDirEnc;
}
/* * Compares page encodings specified in various places, and throws * exception in case of page encoding mismatch. * * @param thePageDirEnc The value of the pageEncoding attribute of the page * directive @param pageDir The page directive node * * @throws JasperException in case of page encoding mismatch
*/ privatevoid compareTagEncodings(String thePageDirEnc,
Node.TagDirective pageDir) throws JasperException {
Node.Root root = pageDir.getRoot();
String pageDirEnc = thePageDirEnc.toUpperCase(Locale.ENGLISH); /* * Compare the 'pageEncoding' attribute of the page directive with * the encoding specified in the XML prolog (only for XML syntax, * and only if JSP document contains XML prolog with encoding * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as * identical.
*/ if ((root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) || root.isBomPresent()) {
String pageEnc = root.getPageEncoding().toUpperCase(Locale.ENGLISH); if (!pageDirEnc.equals(pageEnc)
&& (!pageDirEnc.startsWith("UTF-16") || !pageEnc
.startsWith("UTF-16"))) {
err.jspError(pageDir, "jsp.error.prolog_pagedir_encoding_mismatch",
pageEnc, pageDirEnc);
}
}
}
}
/** * A visitor for validating nodes other than page directives
*/ privatestaticclass ValidateVisitor extends Node.Visitor {
// Pattern to extract a method name from a full method signature privatestaticfinal Pattern METHOD_NAME_PATTERN =
Pattern.compile(".*[ \t\n\r]+(.+?)[ \t\n\r]*\\(.*", Pattern.DOTALL);
privatefinal PageInfo pageInfo;
privatefinal ErrorDispatcher err;
privatefinal ClassLoader loader;
privatefinal StringBuilder buf = new StringBuilder(32);
privatestaticfinal JspUtil.ValidAttribute[] jspRootAttrs = { new JspUtil.ValidAttribute("xsi:schemaLocation"), new JspUtil.ValidAttribute("version", true) };
privatestaticfinal JspUtil.ValidAttribute[] includeDirectiveAttrs = { new JspUtil.ValidAttribute( "file", true) };
privatestaticfinal JspUtil.ValidAttribute[] taglibDirectiveAttrs = { new JspUtil.ValidAttribute("uri"), new JspUtil.ValidAttribute("tagdir"), new JspUtil.ValidAttribute("prefix", true) };
privatestaticfinal JspUtil.ValidAttribute[] includeActionAttrs = { new JspUtil.ValidAttribute("page", true), new JspUtil.ValidAttribute("flush") };
privatestaticfinal JspUtil.ValidAttribute[] paramActionAttrs = { new JspUtil.ValidAttribute("name", true), new JspUtil.ValidAttribute("value", true) };
privatestaticfinal JspUtil.ValidAttribute[] forwardActionAttrs = { new JspUtil.ValidAttribute("page", true) };
privatestaticfinal JspUtil.ValidAttribute[] getPropertyAttrs = { new JspUtil.ValidAttribute("name", true), new JspUtil.ValidAttribute("property", true) };
privatestaticfinal JspUtil.ValidAttribute[] setPropertyAttrs = { new JspUtil.ValidAttribute("name", true), new JspUtil.ValidAttribute("property", true), new JspUtil.ValidAttribute("value", false), new JspUtil.ValidAttribute("param") };
privatestaticfinal JspUtil.ValidAttribute[] useBeanAttrs = { new JspUtil.ValidAttribute("id", true), new JspUtil.ValidAttribute("scope"), new JspUtil.ValidAttribute("class"), new JspUtil.ValidAttribute("type"), new JspUtil.ValidAttribute("beanName", false) };
privatestaticfinal JspUtil.ValidAttribute[] plugInAttrs = { new JspUtil.ValidAttribute("type", true), new JspUtil.ValidAttribute("code", true), new JspUtil.ValidAttribute("codebase"), new JspUtil.ValidAttribute("align"), new JspUtil.ValidAttribute("archive"), new JspUtil.ValidAttribute("height", false), new JspUtil.ValidAttribute("hspace"), new JspUtil.ValidAttribute("jreversion"), new JspUtil.ValidAttribute("name"), new JspUtil.ValidAttribute("vspace"), new JspUtil.ValidAttribute("width", false), new JspUtil.ValidAttribute("nspluginurl"), new JspUtil.ValidAttribute("iepluginurl") };
privatestaticfinal JspUtil.ValidAttribute[] attributeAttrs = { new JspUtil.ValidAttribute("name", true), new JspUtil.ValidAttribute("trim"), new JspUtil.ValidAttribute("omit")};
privatestaticfinal JspUtil.ValidAttribute[] invokeAttrs = { new JspUtil.ValidAttribute("fragment", true), new JspUtil.ValidAttribute("var"), new JspUtil.ValidAttribute("varReader"), new JspUtil.ValidAttribute("scope") };
privatestaticfinal JspUtil.ValidAttribute[] doBodyAttrs = { new JspUtil.ValidAttribute("var"), new JspUtil.ValidAttribute("varReader"), new JspUtil.ValidAttribute("scope") };
privatestaticfinal JspUtil.ValidAttribute[] jspOutputAttrs = { new JspUtil.ValidAttribute("omit-xml-declaration"), new JspUtil.ValidAttribute("doctype-root-element"), new JspUtil.ValidAttribute("doctype-public"), new JspUtil.ValidAttribute("doctype-system") };
privatefinal ExpressionFactory expressionFactory;
/* * Constructor
*/
ValidateVisitor(Compiler compiler) { this.pageInfo = compiler.getPageInfo(); this.err = compiler.getErrorDispatcher(); this.loader = compiler.getCompilationContext().getClassLoader(); // Get the cached EL expression factory for this context
expressionFactory =
JspFactory.getDefaultFactory().getJspApplicationContext(
compiler.getCompilationContext().getServletContext()).
getExpressionFactory();
}
@Override publicvoid visit(Node.TaglibDirective n) throws JasperException {
JspUtil.checkAttributes("Taglib directive", n,
taglibDirectiveAttrs, err); // Either 'uri' or 'tagdir' attribute must be specified
String uri = n.getAttributeValue("uri");
String tagdir = n.getAttributeValue("tagdir"); if (uri == null && tagdir == null) {
err.jspError(n, "jsp.error.taglibDirective.missing.location");
} if (uri != null && tagdir != null) {
err
.jspError(n, "jsp.error.taglibDirective.both_uri_and_tagdir");
}
}
@Override publicvoid visit(Node.ParamAction n) throws JasperException {
JspUtil.checkAttributes("Param action", n, paramActionAttrs, err); // make sure the value of the 'name' attribute is not a // request-time expression
throwErrorIfExpression(n, "name", "jsp:param");
n.setValue(getJspAttribute(null, "value", null, null, n
.getAttributeValue("value"), n, null, false));
visitBody(n);
}
@Override publicvoid visit(Node.ParamsAction n) throws JasperException { // Make sure we've got at least one nested jsp:param
Node.Nodes subElems = n.getBody(); if (subElems == null) {
err.jspError(n, "jsp.error.params.emptyBody");
}
visitBody(n);
}
@Override publicvoid visit(Node.IncludeAction n) throws JasperException {
JspUtil.checkAttributes("Include action", n, includeActionAttrs,
err);
n.setPage(getJspAttribute(null, "page", null, null, n
.getAttributeValue("page"), n, null, false));
visitBody(n);
}
@Override publicvoid visit(Node.ForwardAction n) throws JasperException {
JspUtil.checkAttributes("Forward", n, forwardActionAttrs, err);
n.setPage(getJspAttribute(null, "page", null, null, n
.getAttributeValue("page"), n, null, false));
visitBody(n);
}
@SuppressWarnings("null") // type can't be null after initial test
@Override publicvoid visit(Node.PlugIn n) throws JasperException {
JspUtil.checkAttributes("Plugin", n, plugInAttrs, err);
@Override publicvoid visit(Node.ELExpression n) throws JasperException { // exit if we are ignoring EL all together if (pageInfo.isELIgnored()) { return;
}
// JSP.2.2 - '#{' not allowed in template text if (n.getType() == '#') { if (!pageInfo.isDeferredSyntaxAllowedAsLiteral()) {
err.jspError(n, "jsp.error.el.template.deferred");
} else { return;
}
}
Attributes attrs = n.getAttributes(); if (attrs != null) { int attrSize = attrs.getLength();
Node.JspAttribute[] jspAttrs = new Node.JspAttribute[attrSize]; for (int i = 0; i < attrSize; i++) { // JSP.2.2 - '#{' not allowed in template text
String value = attrs.getValue(i); if (!pageInfo.isDeferredSyntaxAllowedAsLiteral()) { if (containsDeferredSyntax(value)) {
err.jspError(n, "jsp.error.el.template.deferred");
}
}
jspAttrs[i] = getJspAttribute(null, attrs.getQName(i),
attrs.getURI(i), attrs.getLocalName(i), value, n, null, false);
}
n.setJspAttributes(jspAttrs);
}
visitBody(n);
}
/* * Look for a #{ sequence that isn't preceded by \.
*/ privateboolean containsDeferredSyntax(String value) { if (value == null) { returnfalse;
}
int i = 0; int len = value.length(); boolean prevCharIsEscape = false; while (i < value.length()) { char c = value.charAt(i); if (c == '#' && (i+1) < len && value.charAt(i+1) == '{' && !prevCharIsEscape) { returntrue;
} elseif (c == '\\') {
prevCharIsEscape = true;
} else {
prevCharIsEscape = false;
}
i++;
} returnfalse;
}
@SuppressWarnings("null") // tagInfo can't be null after initial test
@Override publicvoid visit(Node.CustomTag n) throws JasperException {
/* * The bodycontent of a SimpleTag cannot be JSP.
*/ if (n.implementsSimpleTag()
&& tagInfo.getBodyContent().equalsIgnoreCase(
TagInfo.BODY_CONTENT_JSP)) {
err.jspError(n, "jsp.error.simpletag.badbodycontent", tagInfo
.getTagClassName());
}
/* * If the tag handler declares in the TLD that it supports dynamic * attributes, it also must implement the DynamicAttributes * interface.
*/ if (tagInfo.hasDynamicAttributes()
&& !n.implementsDynamicAttributes()) {
err.jspError(n, "jsp.error.dynamic.attributes.not.implemented",
n.getQName());
}
/* * Make sure all required attributes are present, either as * attributes or named attributes (<jsp:attribute>). Also make sure * that the same attribute is not specified in both attributes or * named attributes.
*/
TagAttributeInfo[] tldAttrs = tagInfo.getAttributes();
String customActionUri = n.getURI();
Attributes attrs = n.getAttributes(); int attrsSize = (attrs == null) ? 0 : attrs.getLength(); for (TagAttributeInfo tldAttr : tldAttrs) {
String attr = null; if (attrs != null) {
attr = attrs.getValue(tldAttr.getName()); if (attr == null) {
attr = attrs.getValue(customActionUri, tldAttr
.getName());
}
}
Node.NamedAttribute na = n.getNamedAttributeNode(tldAttr
.getName());
if (tldAttr.isRequired() && attr == null && na == null) {
err.jspError(n, "jsp.error.missing_attribute", tldAttr
.getName(), n.getLocalName());
} if (attr != null && na != null) {
err.jspError(n, "jsp.error.duplicate.name.jspattribute",
tldAttr.getName());
}
}
Node.Nodes naNodes = n.getNamedAttributeNodes(); int jspAttrsSize = naNodes.size() + attrsSize;
Node.JspAttribute[] jspAttrs = null; if (jspAttrsSize > 0) {
jspAttrs = new Node.JspAttribute[jspAttrsSize];
}
Hashtable<String, Object> tagDataAttrs = new Hashtable<>(attrsSize);
// JSP.C1: It is a (translation time) error for an action that // has one or more variable subelements to have a TagExtraInfo // class that returns a non-null object.
TagExtraInfo tei = tagInfo.getTagExtraInfo(); if (tei != null && tei.getVariableInfo(tagData) != null
&& tei.getVariableInfo(tagData).length > 0
&& tagInfo.getTagVariableInfos().length > 0) {
err.jspError("jsp.error.non_null_tei_and_var_subelems", n
.getQName());
}
Attributes attrs = n.getAttributes(); if (attrs == null) {
err.jspError(n, "jsp.error.jspelement.missing.name");
}
@SuppressWarnings("null") // Exception will have been thrown above int xmlAttrLen = attrs.getLength();
// XML-style 'name' attribute, which is mandatory, must not be // included in JspAttribute array int jspAttrSize = xmlAttrLen - 1 + namedAttrs.size();
Node.JspAttribute[] jspAttrs = new Node.JspAttribute[jspAttrSize]; int jspAttrIndex = 0;
// Process XML-style attributes for (int i = 0; i < xmlAttrLen; i++) { if ("name".equals(attrs.getLocalName(i))) {
n.setNameAttribute(getJspAttribute(null, attrs.getQName(i),
attrs.getURI(i), attrs.getLocalName(i), attrs
.getValue(i), n, null, false));
} else { if (jspAttrIndex < jspAttrSize) {
jspAttrs[jspAttrIndex++] = getJspAttribute(null,
attrs.getQName(i), attrs.getURI(i),
attrs.getLocalName(i), attrs.getValue(i), n, null, false);
}
}
} if (n.getNameAttribute() == null) {
err.jspError(n, "jsp.error.jspelement.missing.name");
}
// Process named attributes for (int i = 0; i < namedAttrs.size(); i++) {
Node.NamedAttribute na = (Node.NamedAttribute) namedAttrs
.getNode(i);
jspAttrs[jspAttrIndex++] = new Node.JspAttribute(na, null, false);
}
JspUtil.checkAttributes("DoBody", n, doBodyAttrs, err);
String scope = n.getTextAttribute("scope");
JspUtil.checkScope(scope, n, err);
String var = n.getTextAttribute("var");
String varReader = n.getTextAttribute("varReader"); if (scope != null && var == null && varReader == null) {
err.jspError(n, "jsp.error.missing_var_or_varReader");
} if (var != null && varReader != null) {
err.jspError(n, "jsp.error.var_and_varReader");
}
}
/* * Make sure the given custom action does not have any invalid * attributes. * * A custom action and its declared attributes always belong to the same * namespace, which is identified by the prefix name of the custom tag * invocation. For example, in this invocation: * * <my:test a="1" b="2" c="3"/>, the action * * "test" and its attributes "a", "b", and "c" all belong to the * namespace identified by the prefix "my". The above invocation would * be equivalent to: * * <my:test my:a="1" my:b="2" my:c="3"/> * * An action attribute may have a prefix different from that of the * action invocation only if the underlying tag handler supports dynamic * attributes, in which case the attribute with the different prefix is * considered a dynamic attribute.
*/ privatevoid checkXmlAttributes(Node.CustomTag n,
Node.JspAttribute[] jspAttrs, Map<String, Object> tagDataAttrs) throws JasperException {
// When attribute is not an expression, // contains its textual value with \$ and \# escaping removed.
String textAttributeValue; if (!elExpression && el != null) { // Should be a single Text node
Iterator<ELNode> it = el.iterator(); if (it.hasNext()) {
textAttributeValue = ((ELNode.Text) it.next())
.getText();
} else {
textAttributeValue = "";
}
} else {
textAttributeValue = xmlAttributeValue;
} for (int j = 0; tldAttrs != null && j < tldAttrs.length; j++) { if (attrs.getLocalName(i).equals(tldAttrs[j].getName())
&& (attrs.getURI(i) == null
|| attrs.getURI(i).length() == 0 || attrs
.getURI(i).equals(n.getURI()))) {
String expectedType = null; if (tldAttr.isDeferredMethod()) { // The String literal must be castable to what is declared as type // for the attribute
String m = tldAttr.getMethodSignature(); if (m != null) {
m = m.trim(); int rti = m.indexOf(' '); if (rti > 0) {
expectedType = m.substring(0, rti).trim();
}
} else {
expectedType = "java.lang.Object";
} if ("void".equals(expectedType)) { // Can't specify a literal for a // deferred method with an expected type // of void - JSP.2.3.4
err.jspError(n, "jsp.error.literal_with_void",
tldAttr.getName());
}
} if (tldAttr.isDeferredValue()) { // The String literal must be castable to what is declared as type // for the attribute
expectedType = tldAttr.getExpectedTypeName();
} if (expectedType != null) { Class<?> expectedClass = String.class; try {
expectedClass = JspUtil.toClass(expectedType, loader);
} catch (ClassNotFoundException e) {
err.jspError
(n, "jsp.error.unknown_attribute_type",
tldAttr.getName(), expectedType);
} // Check casting - not possible for all types if (String.class.equals(expectedClass) ||
expectedClass == Long.TYPE ||
expectedClass == Double.TYPE ||
expectedClass == Byte.TYPE ||
expectedClass == Short.TYPE ||
expectedClass == Integer.TYPE ||
expectedClass == Float.TYPE ||
Number.class.isAssignableFrom(expectedClass) ||
Character.class.equals(expectedClass) ||
Character.TYPE == expectedClass || Boolean.class.equals(expectedClass) || Boolean.TYPE == expectedClass ||
expectedClass.isEnum()) { try {
expressionFactory.coerceToType(textAttributeValue, expectedClass);
} catch (Exception e) {
err.jspError
(n, "jsp.error.coerce_to_type",
tldAttr.getName(), expectedType, textAttributeValue);
}
}
}
if (deferred && !tldAttr.isDeferredMethod() && !tldAttr.isDeferredValue()) { // No deferred expressions allowed for this attribute
err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr",
tldAttr.getName());
} if (!deferred && !tldAttr.canBeRequestTime()) { // Only deferred expressions are allowed for this attribute
err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr",
tldAttr.getName());
}
// EL or Runtime expression
jspAttrs[i] = getJspAttribute(tldAttr,
attrs.getQName(i), attrs.getURI(i),
attrs.getLocalName(i),
xmlAttributeValue, n, el, false);
}
} else { // Attribute does not accept any expressions. // Make sure its value does not contain any. if (expression) {
err.jspError(n, "jsp.error.attribute.custom.non_rt_with_expr",
tldAttr.getName());
}
jspAttrs[i] = new Node.JspAttribute(tldAttr,
attrs.getQName(i), attrs.getURI(i),
attrs.getLocalName(i),
textAttributeValue, false, null, false);
} if (expression) {
tagDataAttrs.put(attrs.getQName(i),
TagData.REQUEST_TIME_VALUE);
} else {
tagDataAttrs.put(attrs.getQName(i),
textAttributeValue);
}
found = true; break;
}
} if (!found) { if (tagInfo.hasDynamicAttributes()) {
jspAttrs[i] = getJspAttribute(null, attrs.getQName(i),
attrs.getURI(i), attrs.getLocalName(i),
xmlAttributeValue, n, el, true);
} else {
err.jspError(n, "jsp.error.bad_attribute", attrs
.getQName(i), n.getLocalName());
}
}
}
}
/* * Make sure the given custom action does not have any invalid named * attributes
*/ privatevoid checkNamedAttributes(Node.CustomTag n,
Node.JspAttribute[] jspAttrs, int start,
Map<String, Object> tagDataAttrs) throws JasperException {
for (int i = 0; i < naNodes.size(); i++) {
Node.NamedAttribute na = (Node.NamedAttribute) naNodes
.getNode(i); boolean found = false; for (TagAttributeInfo tldAttr : tldAttrs) { /* * See above comment about namespace matches. For named * attributes, we use the prefix instead of URI as the match * criterion, because in the case of a JSP document, we'd * have to keep track of which namespaces are in scope when * parsing a named attribute, in order to determine the URI * that the prefix of the named attribute's name matches to.
*/
String attrPrefix = na.getPrefix(); if (na.getLocalName().equals(tldAttr.getName())
&& (attrPrefix == null || attrPrefix.length() == 0 || attrPrefix
.equals(n.getPrefix()))) {
jspAttrs[start + i] = new Node.JspAttribute(na,
tldAttr, false);
NamedAttributeVisitor nav = null; if (na.getBody() != null) {
nav = new NamedAttributeVisitor();
na.getBody().visit(nav);
} if (nav != null && nav.hasDynamicContent()) {
tagDataAttrs.put(na.getName(),
TagData.REQUEST_TIME_VALUE);
} else {
tagDataAttrs.put(na.getName(), na.getText());
}
found = true; break;
}
} if (!found) { if (tagInfo.hasDynamicAttributes()) {
jspAttrs[start + i] = new Node.JspAttribute(na, null, true);
} else {
err.jspError(n, "jsp.error.bad_attribute",
na.getName(), n.getLocalName());
}
}
}
}
/** * Preprocess attributes that can be expressions. Expression delimiters * are stripped. * <p> * If value is null, checks if there are any NamedAttribute subelements * in the tree node, and if so, constructs a JspAttribute out of a child * NamedAttribute node. * * @param el EL expression, if already parsed by the caller (so that we * can skip re-parsing it)
*/ private Node.JspAttribute getJspAttribute(TagAttributeInfo tai,
String qName, String uri, String localName, String value,
Node n, ELNode.Nodes el, boolean dynamic) throws JasperException {
Node.JspAttribute result = null;
// XXX Is it an error to see "%=foo%" in non-Xml page? // (We won't see "<%=foo%> in xml page because '<' is not a // valid attribute value in xml).
if (value != null) { if (n.getRoot().isXmlSyntax() && value.startsWith("%=")) {
result = new Node.JspAttribute(tai, qName, uri, localName,
value.substring(2, value.length() - 1), true, null,
dynamic);
} elseif (!n.getRoot().isXmlSyntax()
&& value.startsWith("<%=")) {
result = new Node.JspAttribute(tai, qName, uri, localName,
value.substring(3, value.length() - 2), true, null,
dynamic);
} else { if (!pageInfo.isELIgnored()) { // The attribute can contain expressions but is not a // scriptlet expression; thus, we want to run it through // the expression interpreter
// validate expression syntax if string contains // expression(s) if (el == null) {
el = ELParser.parse(value,
pageInfo.isDeferredSyntaxAllowedAsLiteral());
}
if (el.containsEL()) {
validateFunctions(el, n);
} else { // Get text with \$ and \# escaping removed. // Should be a single Text node
Iterator<ELNode> it = el.iterator(); if (it.hasNext()) {
value = ((ELNode.Text) it.next()).getText();
} else {
value = "";
}
el = null;
}
}
if (n instanceof Node.UninterpretedTag &&
n.getRoot().isXmlSyntax()) { // Attribute values of uninterpreted tags will have been // XML un-escaped during parsing. Since these attributes
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.37 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.