/* * 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.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.net.JarURLConnection; import java.net.URL; import java.util.Stack; import java.util.jar.JarFile; import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; import org.apache.jasper.xmlparser.XMLEncodingDetector; import org.xml.sax.Attributes; /** * Controller for the parsing of a JSP page. *
* The same ParserController instance is used for a JSP page and any JSP
* segments included by it (via an include directive), where each segment may
* be provided in standard or XML syntax. This class selects and invokes the
* appropriate parser for the JSP page and its included segments.
*
* @author Pierre Delisle
* @author Jan Luehe
*/
class ParserController implements TagConstants {
private static final String CHARSET = "charset=";
private JspCompilationContext ctxt;
private Compiler compiler;
private ErrorDispatcher err;
/*
* Indicates the syntax (XML or standard) of the file being processed
*/
private boolean isXml;
/*
* A stack to keep track of the 'current base directory'
* for include directives that refer to relative paths.
*/
private Stack baseDirStack = new Stack();
private boolean isEncodingSpecifiedInProlog;
private boolean isBomPresent;
private int skip;
private String sourceEnc;
private boolean isDefaultPageEncoding;
private boolean isTagFile;
private boolean directiveOnly;
/*
* Constructor
*/
public ParserController(JspCompilationContext ctxt, Compiler compiler) {
this.ctxt = ctxt;
this.compiler = compiler;
this.err = compiler.getErrorDispatcher();
}
public JspCompilationContext getJspCompilationContext () {
return ctxt;
}
public Compiler getCompiler () {
return compiler;
}
/**
* Parses a JSP page or tag file. This is invoked by the compiler.
*
* @param inFileName The path to the JSP page or tag file to be parsed.
*/
public Node.Nodes parse(String inFileName)
throws FileNotFoundException, JasperException, IOException {
// If we're parsing a packaged tag file or a resource included by it
// (using an include directive), ctxt.getTagFileJar() returns the
// JAR file from which to read the tag file or included resource,
// respectively.
isTagFile = ctxt.isTagFile();
directiveOnly = false;
return doParse(inFileName, null, ctxt.getTagFileJarUrl());
}
/**
* Parses the directives of a JSP page or tag file. This is invoked by the
* compiler.
*
* @param inFileName The path to the JSP page or tag file to be parsed.
*/
public Node.Nodes parseDirectives(String inFileName)
throws FileNotFoundException, JasperException, IOException {
// If we're parsing a packaged tag file or a resource included by it
// (using an include directive), ctxt.getTagFileJar() returns the
// JAR file from which to read the tag file or included resource,
// respectively.
isTagFile = ctxt.isTagFile();
directiveOnly = true;
return doParse(inFileName, null, ctxt.getTagFileJarUrl());
}
/**
* Processes an include directive with the given path.
*
* @param inFileName The path to the resource to be included.
* @param parent The parent node of the include directive.
* @param jarFile The JAR file from which to read the included resource,
* or null of the included resource is to be read from the filesystem
*/
public Node.Nodes parse(String inFileName, Node parent,
URL jarFileUrl)
throws FileNotFoundException, JasperException, IOException {
// For files that are statically included, isTagfile and directiveOnly
// remain unchanged.
return doParse(inFileName, parent, jarFileUrl);
}
/**
* Extracts tag file directive information from the tag file with the
* given name.
*
* This is invoked by the compiler
*
* @param inFileName The name of the tag file to be parsed.
* @deprecated Use {@link #parseTagFileDirectives(String, URL)}
* See https://issues.apache.org/bugzilla/show_bug.cgi?id=46471
*/
public Node.Nodes parseTagFileDirectives(String inFileName)
throws FileNotFoundException, JasperException, IOException {
return parseTagFileDirectives(
inFileName, ctxt.getTagFileJarUrl(inFileName));
}
/**
* Extracts tag file directive information from the given tag file.
*
* This is invoked by the compiler
*
* @param inFileName The name of the tag file to be parsed.
* @param tagFileJarUrl The location of the tag file.
*/
public Node.Nodes parseTagFileDirectives(String inFileName,
URL tagFileJarUrl)
throws FileNotFoundException, JasperException, IOException {
boolean isTagFileSave = isTagFile;
boolean directiveOnlySave = directiveOnly;
isTagFile = true;
directiveOnly = true;
Node.Nodes page = doParse(inFileName, null, tagFileJarUrl);
directiveOnly = directiveOnlySave;
isTagFile = isTagFileSave;
return page;
}
/**
* Parses the JSP page or tag file with the given path name.
*
* @param inFileName The name of the JSP page or tag file to be parsed.
* @param parent The parent node (non-null when processing an include
* directive)
* @param isTagFile true if file to be parsed is tag file, and false if it
* is a regular JSP page
* @param directivesOnly true if the file to be parsed is a tag file and
* we are only interested in the directives needed for constructing a
* TagFileInfo.
* @param jarFile The JAR file from which to read the JSP page or tag file,
* or null if the JSP page or tag file is to be read from the filesystem
*/
private Node.Nodes doParse(String inFileName,
Node parent,
URL jarFileUrl)
throws FileNotFoundException, JasperException, IOException {
Node.Nodes parsedPage = null;
isEncodingSpecifiedInProlog = false;
isBomPresent = false;
isDefaultPageEncoding = false;
JarFile jarFile = getJarFile(jarFileUrl);
String absFileName = resolveFileName(inFileName);
String jspConfigPageEnc = getJspConfigPageEncoding(absFileName);
// Figure out what type of JSP document and encoding type we are
// dealing with
determineSyntaxAndEncoding(absFileName, jarFile, jspConfigPageEnc);
if (parent != null) {
// Included resource, add to dependent list
if (jarFile == null) {
compiler.getPageInfo().addDependant(absFileName);
} else {
compiler.getPageInfo().addDependant(
jarFileUrl.toExternalForm() + absFileName.substring(1));
}
}
if ((isXml && isEncodingSpecifiedInProlog) || isBomPresent) {
/*
* Make sure the encoding explicitly specified in the XML
* prolog (if any) matches that in the JSP config element
* (if any), treating "UTF-16", "UTF-16BE", and "UTF-16LE" as
* identical.
*/
if (jspConfigPageEnc != null && !jspConfigPageEnc.equals(sourceEnc)
&& (!jspConfigPageEnc.startsWith("UTF-16")
|| !sourceEnc.startsWith("UTF-16"))) {
err.jspError("jsp.error.prolog_config_encoding_mismatch",
sourceEnc, jspConfigPageEnc);
}
}
// Dispatch to the appropriate parser
if (isXml) {
// JSP document (XML syntax)
// InputStream for jspx page is created and properly closed in
// JspDocumentParser.
parsedPage = JspDocumentParser.parse(this, absFileName,
jarFile, parent,
isTagFile, directiveOnly,
sourceEnc,
jspConfigPageEnc,
isEncodingSpecifiedInProlog,
isBomPresent);
} else {
// Standard syntax
InputStreamReader inStreamReader = null;
try {
inStreamReader = JspUtil.getReader(absFileName, sourceEnc,
jarFile, ctxt, err, skip);
JspReader jspReader = new JspReader(ctxt, absFileName,
sourceEnc, inStreamReader,
err);
parsedPage = Parser.parse(this, jspReader, parent, isTagFile,
directiveOnly, jarFileUrl,
sourceEnc, jspConfigPageEnc,
isDefaultPageEncoding, isBomPresent);
} finally {
if (inStreamReader != null) {
try {
inStreamReader.close();
} catch (Exception any) {
}
}
}
}
if (jarFile != null) {
try {
jarFile.close();
} catch (Throwable t) {}
}
baseDirStack.pop();
return parsedPage;
}
/*
* Checks to see if the given URI is matched by a URL pattern specified in
* a jsp-property-group in web.xml, and if so, returns the value of the
*