http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java
b/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java
deleted file mode 100644
index cf15f02..0000000
--- a/src/main/java/freemarker/ext/servlet/FreemarkerServlet.java
+++ /dev/null
@@ -1,1674 +0,0 @@
-/*
- * 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 freemarker.ext.servlet;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Enumeration;
-import java.util.GregorianCalendar;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.regex.Pattern;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import freemarker.cache.ClassTemplateLoader;
-import freemarker.cache.FileTemplateLoader;
-import freemarker.cache.MultiTemplateLoader;
-import freemarker.cache.TemplateLoader;
-import freemarker.cache.WebAppTemplateLoader;
-import freemarker.core.Configurable;
-import freemarker.core.Environment;
-import freemarker.core.OutputFormat;
-import freemarker.core.UndefinedOutputFormat;
-import freemarker.ext.jsp.TaglibFactory;
-import freemarker.ext.jsp.TaglibFactory.ClasspathMetaInfTldSource;
-import freemarker.ext.jsp.TaglibFactory.ClearMetaInfTldSource;
-import freemarker.ext.jsp.TaglibFactory.MetaInfTldSource;
-import freemarker.ext.jsp.TaglibFactory.WebInfPerLibJarMetaInfTldSource;
-import freemarker.template.Configuration;
-import freemarker.template.ObjectWrapper;
-import freemarker.template.Template;
-import freemarker.template.TemplateException;
-import freemarker.template.TemplateExceptionHandler;
-import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
-import freemarker.template.TemplateNotFoundException;
-import freemarker.template.utility.SecurityUtilities;
-import freemarker.template.utility.StringUtil;
-
-/**
- * FreeMarker MVC View servlet that can be used similarly to JSP views. That
is, you put the variables to expose into
- * HTTP servlet request attributes, then forward to an FTL file (instead of to
a JSP file) that's mapped to this servet
- * (usually via the {@code <url-pattern>*.ftl<url-pattern>}). See web.xml
example (and more) in the FreeMarker Manual!
- *
- *
- * <p>
- * <b>Main features</b>
- * </p>
- *
- *
- * <ul>
- *
- * <li>It makes all request, request parameters, session, and servlet context
attributes available to templates through
- * <code>Request</code>, <code>RequestParameters</code>, <code>Session</code>,
and <code>Application</code> variables.
- *
- * <li>The scope variables are also available via automatic scope discovery.
That is, writing
- * <code>Application.attrName</code>, <code>Session.attrName</code>,
<code>Request.attrName</code> is not mandatory;
- * it's enough to write <code>attrName</code>, and if no such variable was
created in the template, it will search the
- * variable in <code>Request</code>, and then in <code>Session</code>, and
finally in <code>Application</code>.
- *
- * <li>It creates a variable with name <code>JspTaglibs</code> that can be
used to load JSP taglibs. For example:<br>
- * <code><#assign dt=JspTaglibs["http://displaytag.sf.net"]></code> or
- * <code><#assign tiles=JspTaglibs["/WEB-INF/struts-tiles.tld"]></code>.
- *
- * <li>A custom directive named {@code include_page} allows you to include the
output of another servlet resource from
- * your servlet container, just as if you used {@code
ServletRequest.getRequestDispatcher(path).include()}: {@code
- * <@include_page path="/myWebapp/somePage.jsp"/>}. You can also pass
parameters to the newly included page by passing a
- * hash named {@code params}:
- * <code><@include_page path="/myWebapp/somePage.jsp" params= lang: "en",
q="5"}/></code>. By default, the request
- * parameters of the original request (the one being processed by
FreemarkerServlet) are also inherited by the include.
- * You can explicitly control this inheritance using the {@code
inherit_params} parameter:
- * <code><@include_page path="/myWebapp/somePage.jsp" params={lang: "en",
q="5"} inherit_params=false/></code>.
- *
- * </ul>
- *
- *
- * <p>
- * <b>Supported {@code init-param}-s</b>
- * </p>
- *
- *
- * <ul>
- *
- * <li><strong>{@value #INIT_PARAM_TEMPLATE_PATH}</strong>: Specifies the
location of the template files. By default,
- * this is interpreted as a {@link ServletContext} resource path, which
practically means a web application directory
- * relative path, or a {@code WEB-INF/lib/*.jar/META-INF/resources}-relative
path (note that this last haven't always
- * worked before FreeMarker 2.3.23).<br>
- * Alternatively, you can prepend it with <tt>file://</tt> to indicate a
literal path in the file system (i.e.
- * <tt>file:///var/www/project/templates/</tt>). Note that three slashes were
used to specify an absolute path.<br>
- * Also, you can prepend it with {@code classpath:}, like in
<tt>classpath:com/example/templates</tt>, to indicate that
- * you want to load templates from the specified package accessible through
the Thread Context Class Loader of the
- * thread that initializes this servlet.<br>
- * If {@code incompatible_improvements} is set to 2.3.22 (or higher), you can
specify multiple comma separated locations
- * inside square brackets, like: {@code [ WEB-INF/templates,
classpath:com/example/myapp/templates ]}. This internally
- * creates a {@link MultiTemplateLoader}. Note again that if {@code
incompatible_improvements} isn't set to at least
- * 2.3.22, the initial {@code [} has no special meaning, and so this feature
is unavailable.<br>
- * Any of the above can have a {@code ?setting(name=value, ...)} postfix to
set the JavaBeans properties of the
- * {@link TemplateLoader} created. For example,
- * {@code /templates?settings(attemptFileAccess=false,
URLConnectionUsesCaches=true)} calls
- * {@link WebAppTemplateLoader#setAttemptFileAccess(boolean)} and
- * {@link WebAppTemplateLoader#setURLConnectionUsesCaches(Boolean)} to tune
the {@link WebAppTemplateLoader}. For
- * backward compatibility (not recommended!), you can use the {@code class://}
prefix, like in
- * <tt>class://com/example/templates</tt> format, which is similar to {@code
classpath:}, except that it uses the
- * defining class loader of this servlet's class. This can cause
template-not-found errors, if that class (in
- * {@code freemarer.jar} usually) is not local to the web application, while
the templates are.<br>
- * The default value is <tt>class://</tt> (that is, the root of the class
hierarchy), which is not recommended anymore,
- * and should be overwritten with the {@value #INIT_PARAM_TEMPLATE_PATH}
init-param.</li>
- *
- * <li><strong>{@value #INIT_PARAM_NO_CACHE}</strong>: If set to {@code true},
generates headers in the response that
- * advise the HTTP client not to cache the returned page. If {@code false},
the HTTP response is not modified for this
- * purpose. The default is {@code false}.</li>
- *
- * <li><strong>{@value #INIT_PARAM_CONTENT_TYPE}</strong>: The Content-type
HTTP header value used in the HTTP responses
- * when nothing else specifies the MIME type. The things that may specify the
MIME type (and hence this init-param is
- * ignored), starting with the highest precedence, are:
- * <ol>
- * <li>If the {@value #INIT_PARAM_OVERRIDE_RESPONSE_CONTENT_TYPE} init-param
is {@value #INIT_PARAM_VALUE_NEVER} (the
- * default is {@value #INIT_PARAM_VALUE_ALWAYS}), then the value of {@link
HttpServletResponse#getContentType()} is used
- * if that's non-{@code null}.
- * <li>The template's <tt>content_type</tt> custom attribute, usually
specified via the <tt>attributes</tt> parameter of
- * the <tt><#ftl></tt> directive. This is a legacy feature, deprecated
by the {@link OutputFormat} mechanism.
- * <li>The {@linkplain Template#getOutputFormat() output format of the
template}, if that has non-{@code null} MIME-type
- * ({@link OutputFormat#getMimeType()}). When a template has no output format
specified, {@link UndefinedOutputFormat}
- * is used, which has {@code null} MIME-type. (The output format of a template
is deduced from {@link Configuration}
- * settings, or can be specified directly in the template, like {@code <#ftl
outputFormat="HTML">}. See the FreeMarker
- * Manual for more about the output format mechanism. Note that setting an
output format may turns on auto-escaping, so
- * it's not just about MIME types.)
- * <li>If the {@value #INIT_PARAM_OVERRIDE_RESPONSE_CONTENT_TYPE} init-param
is not {@value #INIT_PARAM_VALUE_ALWAYS}
- * (the default is {@value #INIT_PARAM_VALUE_ALWAYS}), then the value of
{@link HttpServletResponse#getContentType()} is
- * used if that's non-{@code null}.
- * </ol>
- * If none of the above gives a MIME type, then this init-param does. Defaults
to <tt>"text/html"</tt>. If and only if
- * the {@value #INIT_PARAM_RESPONSE_CHARACTER_ENCODING} init-param is set to
{@value #INIT_PARAM_VALUE_LEGACY} (which is
- * the default of it), the content type may include the charset (as in
<tt>"text/html; charset=utf-8"</tt>), in which
- * case that specifies the actual charset of the output. If the the {@value
#INIT_PARAM_RESPONSE_CHARACTER_ENCODING}
- * init-param is not set to {@value #INIT_PARAM_VALUE_LEGACY}, then specifying
the charset in the
- * {@value #INIT_PARAM_CONTENT_TYPE} init-param is not allowed, and will cause
servlet initialization error.</li>
- *
- * <li><strong>{@value #INIT_PARAM_OVERRIDE_RESPONSE_CONTENT_TYPE}</strong>
(since 2.3.24): Specifies when we should
- * override the {@code contentType} that might be already set (i.e.,
non-{@code null}) in the
- * {@link HttpServletResponse}. The default is {@value
#INIT_PARAM_VALUE_ALWAYS}, which means that we always set the
- * content type. Another possible value is {@value #INIT_PARAM_VALUE_NEVER},
which means that we don't set the content
- * type in the response, unless {@link HttpServletResponse#getContentType()}
is {@code null}. The third possible value
- * is {@value #INIT_PARAM_VALUE_WHEN_TEMPLATE_HAS_MIME_TYPE}, which means that
we only set the content type if either
- * the template has an associated {@link OutputFormat} with non-{@code null}
{@link OutputFormat#getMimeType()}, or it
- * has a custom attribute with name <tt>content_type</tt>, or {@link
HttpServletResponse#getContentType()} is
- * {@code null}. Setting this init-param allows you to specify the content
type before forwarding to
- * {@link FreemarkerServlet}.</li>
- *
- * <li><strong>{@value #INIT_PARAM_OVERRIDE_RESPONSE_LOCALE}</strong> (since
2.3.24): Specifies if we should override
- * the template {@code locale} that might be already set (i.e., non-{@code
null}) in the {@link HttpServletRequest}. The
- * default is {@value #INIT_PARAM_VALUE_ALWAYS}, which means that we always
deduce the template {@code locale} by
- * invoking {@link #deduceLocale(String, HttpServletRequest,
HttpServletResponse)}. Another possible value is
- * {@value #INIT_PARAM_VALUE_NEVER}, which means that we don't deduce the
template {@code locale}, unless
- * {@link HttpServletRequest#getLocale()} is {@code null}.
- *
- * <li><strong>{@value #INIT_PARAM_RESPONSE_CHARACTER_ENCODING}</strong>
(since 2.3.24): Specifies how the
- * {@link HttpServletResponse} "character encoding" (as in {@link
HttpServletResponse#setCharacterEncoding(String)})
- * will be deduced. The possible modes are:
- * <ul>
- * <li>{@value #INIT_PARAM_VALUE_LEGACY}: This is the default for backward
compatibility; in new applications, use
- * {@value #INIT_PARAM_VALUE_FROM_TEMPLATE} (or some of the other options)
instead. {@value #INIT_PARAM_VALUE_LEGACY}
- * will use the charset of the template file to set the charset of the servlet
response. Except, if the
- * {@value #INIT_PARAM_CONTENT_TYPE} init-param contains a charset, it will
use that instead. A quirk of this legacy
- * mode is that it's not aware of the {@link Configurable#getOutputEncoding()}
FreeMarker setting, and thus never reads
- * or writes it (though very few applications utilize that setting anyway).
Also, it sets the charset of the servlet
- * response by adding it to the response content type via calling {@link
HttpServletResponse#setContentType(String)} (as
- * that was the only way before Servlet 2.4), not via the more modern
- * {@link HttpServletResponse#setCharacterEncoding(String)} method. Note that
the charset of a template usually comes
- * from {@link Configuration#getDefaultEncoding()} (i.e., from the {@code
default_encoding} FreeMarker setting),
- * occasionally from {@link Configuration#getEncoding(Locale)} (when
FreeMarker was configured to use different charsets
- * depending on the locale) or even more rarely from {@link
Configuration#getTemplateConfigurations()} (when FreeMarker was
- * configured to use a specific charset for certain templates).
- * <li>{@value #INIT_PARAM_VALUE_FROM_TEMPLATE}: This should be used in most
applications, but it's not the default for
- * backward compatibility. It reads the {@link
Configurable#getOutputEncoding()} setting of the template (note that the
- * template usually just inherits that from the {@link Configuration}), and if
that's not set, then reads the source
- * charset of the template, just like {@value #INIT_PARAM_VALUE_LEGACY}, and
if that's {@code null} (which happens if
- * the template was loaded from a non-binary source) then it will be UTF-8.
Then it passes the charset acquired this way
- * to {@link HttpServletResponse#setCharacterEncoding(String)} and {@link
Environment#setOutputEncoding(String)}. (It
- * doesn't call the legacy {@link HttpServletResponse#setContentType(String)}
API to set the charset.) (Note that if the
- * template has a {@code content_type} template attribute (which is
deprecated) that specifies a charset, it will be
- * used as the output charset of that template.)
- * <li>{@value #INIT_PARAM_VALUE_DO_NOT_SET}: {@link FreemarkerServlet} will
not set the {@link HttpServletResponse}
- * "character encoding". It will still call {@link
Environment#setOutputEncoding(String)}, so that the running template
- * will be aware of the charset used for the output.
- * <li>{@value #INIT_PARAM_VALUE_FORCE_PREFIX} + charset name, for example
{@code force UTF-8}: The output charset will
- * be the one specified after "force" + space, regardless of everything. The
charset specified this way is passed to
- * {@link HttpServletResponse#setCharacterEncoding(String)} and {@link
Environment#setOutputEncoding(String)}. If the
- * charset name is not recognized by Java, the servlet initialization will
fail.
- * </ul>
- *
- * <li><strong>{@value #INIT_PARAM_BUFFER_SIZE}</strong>: Sets the size of the
output buffer in bytes, or if "KB" or
- * "MB" is written after the number (like {@code <param-value>256
KB</param-value>}) then in kilobytes or megabytes.
- * This corresponds to {@link HttpServletResponse#setBufferSize(int)}. If the
{@link HttpServletResponse} state doesn't
- * allow changing the buffer size, it will silently do nothing. If this init
param isn't specified, then the buffer size
- * is not set by {@link FreemarkerServlet} in the HTTP response, which usually
means that the default buffer size of the
- * servlet container will be used.</li>
- *
- * <li><strong>{@value #INIT_PARAM_EXCEPTION_ON_MISSING_TEMPLATE}</strong>
(since 2.3.22): If {@code false} (default,
- * but not recommended), if a template is requested that's missing, this
servlet responses with a HTTP 404 "Not found"
- * error, and only logs the problem with debug level. If {@code true}
(recommended), the servlet will log the issue with
- * error level, then throws an exception that bubbles up to the servlet
container, which usually then creates a HTTP 500
- * "Internal server error" response (and maybe logs the event into the
container log). See "Error handling" later for
- * more!</li>
- *
- * <li><strong>{@value #INIT_PARAM_META_INF_TLD_LOCATIONS}</strong> (since
2.3.22): Comma separated list of items, each
- * is either {@value #META_INF_TLD_LOCATION_WEB_INF_PER_LIB_JARS}, or {@value
#META_INF_TLD_LOCATION_CLASSPATH}
- * optionally followed by colon and a regular expression, or {@value
#META_INF_TLD_LOCATION_CLEAR}. For example {@code
- * <param-value>classpath:.*myoverride.*\.jar$, webInfPerLibJars,
classpath:.*taglib.*\.jar$</param-value>}, or {@code
- * <param-value>classpath</param-value>}. (Whitespace around the commas and
list items will be ignored.) See
- * {@link TaglibFactory#setMetaInfTldSources(List)} for more information.
Defaults to a list that contains
- * {@value #META_INF_TLD_LOCATION_WEB_INF_PER_LIB_JARS} only (can be
overridden with
- * {@link #createDefaultMetaInfTldSources()}). Note that this can be also
specified with the
- * {@value #SYSTEM_PROPERTY_META_INF_TLD_SOURCES} system property. If both the
init-param and the system property
- * exists, the sources listed in the system property will be added after those
specified by the init-param. This is
- * where the special entry, {@value #META_INF_TLD_LOCATION_CLEAR} comes handy,
as it will remove all previous list
- * items. (An intended usage of the system property is setting it to {@code
clear, classpath} in the Eclipse run
- * configuration if you are running the application without putting the
dependency jar-s into {@code WEB-INF/lib}.)
- * Also, note that further {@code classpath:<pattern>} items are added
automatically at the end of this list based on
- * Jetty's {@code
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern"} servlet context
attribute.</li>
- *
- * <li><strong>{@value #INIT_PARAM_CLASSPATH_TLDS}</strong> (since 2.3.22):
Comma separated list of paths; see
- * {@link TaglibFactory#setClasspathTlds(List)}. Whitespace around the list
items will be ignored. Defaults to no paths
- * (can be overidden with {@link #createDefaultClassPathTlds()}). Note that
this can also be specified with the
- * {@value #SYSTEM_PROPERTY_CLASSPATH_TLDS} system property. If both the
init-param and the system property exists, the
- * items listed in system property will be added after those specified by the
init-param.</li>
- *
- * <li><strong>"Debug"</strong>: Deprecated, has no effect since 2.3.22.
(Earlier it has enabled/disabled sending
- * debug-level log messages to the servlet container log, but this servlet
doesn't log debug level messages into the
- * servlet container log anymore, only into the FreeMarker log.)</li>
- *
- * <li>The following init-params are supported only for backward
compatibility, and their usage is discouraged:
- * {@code TemplateUpdateInterval}, {@code DefaultEncoding}, {@code
ObjectWrapper}, {@code TemplateExceptionHandler}.
- * Instead, use init-params with the setting names documented at {@link
Configuration#setSetting(String, String)}, such
- * as {@code object_wrapper}.
- *
- * <li><strong>Any other init-params</strong> will be interpreted as {@link
Configuration}-level FreeMarker setting. See
- * the possible names and values at {@link Configuration#setSetting(String,
String)}. Note that these init-param names
- * are starting with lower-case letter (upper-case init-params are used for
FreemarkerSerlvet settings).</li>
- *
- * </ul>
- *
- *
- * <p>
- * <b>Error handling</b>
- * </p>
- *
- *
- * <p>
- * Notes:
- * </p>
- *
- * <ul>
- *
- * <li>Logging below, where not said otherwise, always refers to logging with
FreeMarker's logging facility (see
- * {@link Logger}), under the "freemarker.servlet" category.</li>
- * <li>Throwing a {@link ServletException} to the servlet container is
mentioned at a few places below. That in practice
- * usually means HTTP 500 "Internal server error" response, and maybe a log
entry in the servlet container's log.</li>
- * </ul>
- *
- * <p>
- * Errors types:
- * </p>
- *
- * <ul>
- *
- * <li>If the servlet initialization fails, the servlet won't be started as
usual. The cause is usually logged with
- * error level. When it isn't, check the servlet container's log.
- *
- * <li>If the requested template doesn't exist, by default the servlet returns
a HTTP 404 "Not found" response, and logs
- * the problem with <em>debug</em> level. Responding with HTTP 404 is how JSP
behaves, but it's actually not a
- * recommended setting anymore. By setting {@value
#INIT_PARAM_EXCEPTION_ON_MISSING_TEMPLATE} init-param to {@code true}
- * (recommended), it will instead log the problem with error level, then the
servlet throws {@link ServletException} to
- * the servlet container (with the proper cause exception). After all, if the
visited URL had an associated "action" but
- * the template behind it is missing, that's an internal server error, not a
wrong URL.</li>
- *
- * <li>If the template contains parsing errors, it will log it with error
level, then the servlet throws
- * {@link ServletException} to the servlet container (with the proper cause
exception).</li>
- *
- * <li>If the template throws exception during its execution, and the value of
the {@code template_exception_handler}
- * init-param is {@code rethrow} (recommended), it will log it with error
level and then the servlet throws
- * {@link ServletException} to the servlet container (with the proper cause
exception). But beware, the default value of
- * the {@code template_exception_handler} init-param is {@code html_debug},
which is for development only! Set it to
- * {@code rethrow} for production. The {@code html_debug} (and {@code debug})
handlers will print error details to the
- * page and then commit the HTTP response with response code 200 "OK", thus,
the server wont be able roll back the
- * response and send back an HTTP 500 page. This is so that the template
developers will see the error without digging
- * the logs.
- *
- * </ul>
- */
-public class FreemarkerServlet extends HttpServlet {
- private static final Logger LOG =
LoggerFactory.getLogger("freemarker.servlet");
-
- @Deprecated
- private static final Logger LOG_RT =
LoggerFactory.getLogger("freemarker.runtime");
-
- public static final long serialVersionUID = -2440216393145762479L;
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params. (This init-param
- * has existed long before 2.3.22, but this constant was only added then.)
- *
- * @since 2.3.22
- */
- public static final String INIT_PARAM_TEMPLATE_PATH = "TemplatePath";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params. (This init-param
- * has existed long before 2.3.22, but this constant was only added then.)
- *
- * @since 2.3.22
- */
- public static final String INIT_PARAM_NO_CACHE = "NoCache";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params. (This init-param
- * has existed long before 2.3.22, but this constant was only added then.)
- *
- * @since 2.3.22
- */
- public static final String INIT_PARAM_CONTENT_TYPE = "ContentType";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params.
- *
- * @since 2.3.24
- */
- public static final String INIT_PARAM_OVERRIDE_RESPONSE_CONTENT_TYPE =
"OverrideResponseContentType";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params.
- *
- * @since 2.3.24
- */
- public static final String INIT_PARAM_RESPONSE_CHARACTER_ENCODING =
"ResponseCharacterEncoding";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params.
- *
- * @since 2.3.24
- */
- public static final String INIT_PARAM_OVERRIDE_RESPONSE_LOCALE =
"OverrideResponseLocale";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params.
- *
- * @since 2.3.22
- */
- public static final String INIT_PARAM_BUFFER_SIZE = "BufferSize";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params.
- *
- * @since 2.3.22
- */
- public static final String INIT_PARAM_META_INF_TLD_LOCATIONS =
"MetaInfTldSources";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params.
- *
- * @since 2.3.22
- */
- public static final String INIT_PARAM_EXCEPTION_ON_MISSING_TEMPLATE =
"ExceptionOnMissingTemplate";
-
- /**
- * Init-param name - see the {@link FreemarkerServlet} class documentation
about the init-params.
- *
- * @since 2.3.22
- */
- public static final String INIT_PARAM_CLASSPATH_TLDS = "ClasspathTlds";
-
- private static final String INIT_PARAM_DEBUG = "Debug";
-
- private static final String DEPR_INITPARAM_TEMPLATE_DELAY =
"TemplateDelay";
- private static final String DEPR_INITPARAM_ENCODING = "DefaultEncoding";
- private static final String DEPR_INITPARAM_OBJECT_WRAPPER =
"ObjectWrapper";
- private static final String DEPR_INITPARAM_WRAPPER_SIMPLE = "simple";
- private static final String DEPR_INITPARAM_WRAPPER_BEANS = "beans";
- private static final String DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER =
"TemplateExceptionHandler";
- private static final String
DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW = "rethrow";
- private static final String
DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_DEBUG = "debug";
- private static final String
DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_HTML_DEBUG = "htmlDebug";
- private static final String
DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_IGNORE = "ignore";
- private static final String DEPR_INITPARAM_DEBUG = "debug";
-
- private static final ContentType DEFAULT_CONTENT_TYPE = new
ContentType("text/html");
-
- public static final String INIT_PARAM_VALUE_NEVER = "never";
- public static final String INIT_PARAM_VALUE_ALWAYS = "always";
- public static final String INIT_PARAM_VALUE_WHEN_TEMPLATE_HAS_MIME_TYPE =
"whenTemplateHasMimeType";
- public static final String INIT_PARAM_VALUE_FROM_TEMPLATE = "fromTemplate";
- public static final String INIT_PARAM_VALUE_LEGACY = "legacy";
- public static final String INIT_PARAM_VALUE_DO_NOT_SET = "doNotSet";
- public static final String INIT_PARAM_VALUE_FORCE_PREFIX = "force ";
-
- /**
- * When set, the items defined in it will be added after those coming from
the
- * {@value #INIT_PARAM_META_INF_TLD_LOCATIONS} init-param. The value
syntax is the same as of the init-param. Note
- * that {@value #META_INF_TLD_LOCATION_CLEAR} can be used to re-start the
list, rather than continue it.
- *
- * @since 2.3.22
- */
- public static final String SYSTEM_PROPERTY_META_INF_TLD_SOURCES =
"org.freemarker.jsp.metaInfTldSources";
-
- /**
- * When set, the items defined in it will be added after those coming from
the
- * {@value #INIT_PARAM_CLASSPATH_TLDS} init-param. The value syntax is the
same as of the init-param.
- *
- * @since 2.3.22
- */
- public static final String SYSTEM_PROPERTY_CLASSPATH_TLDS =
"org.freemarker.jsp.classpathTlds";
-
- /**
- * Used as part of the value of the {@value
#INIT_PARAM_META_INF_TLD_LOCATIONS} init-param.
- *
- * @since 2.3.22
- */
- public static final String META_INF_TLD_LOCATION_WEB_INF_PER_LIB_JARS =
"webInfPerLibJars";
-
- /**
- * Used as part of the value of the {@value
#INIT_PARAM_META_INF_TLD_LOCATIONS} init-param.
- *
- * @since 2.3.22
- */
- public static final String META_INF_TLD_LOCATION_CLASSPATH = "classpath";
-
- /**
- * Used as part of the value of the {@value
#INIT_PARAM_META_INF_TLD_LOCATIONS} init-param.
- *
- * @since 2.3.22
- */
- public static final String META_INF_TLD_LOCATION_CLEAR = "clear";
-
- public static final String KEY_REQUEST = "Request";
- public static final String KEY_INCLUDE = "include_page";
- public static final String KEY_REQUEST_PRIVATE =
"__FreeMarkerServlet.Request__";
- public static final String KEY_REQUEST_PARAMETERS = "RequestParameters";
- public static final String KEY_SESSION = "Session";
- public static final String KEY_APPLICATION = "Application";
- public static final String KEY_APPLICATION_PRIVATE =
"__FreeMarkerServlet.Application__";
- public static final String KEY_JSP_TAGLIBS = "JspTaglibs";
-
- // Note these names start with dot, so they're essentially invisible from
- // a freemarker script.
- private static final String ATTR_REQUEST_MODEL = ".freemarker.Request";
- private static final String ATTR_REQUEST_PARAMETERS_MODEL =
".freemarker.RequestParameters";
- private static final String ATTR_SESSION_MODEL = ".freemarker.Session";
-
- /** @deprecated We only keeps this attribute for backward compatibility,
but actually aren't using it. */
- @Deprecated
- private static final String ATTR_APPLICATION_MODEL =
".freemarker.Application";
-
- /** @deprecated We only keeps this attribute for backward compatibility,
but actually aren't using it. */
- @Deprecated
- private static final String ATTR_JSP_TAGLIBS_MODEL =
".freemarker.JspTaglibs";
-
- private static final String ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS
- = "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern";
-
- private static final String EXPIRATION_DATE;
-
- static {
- // Generate expiration date that is one year from now in the past
- GregorianCalendar expiration = new GregorianCalendar();
- expiration.roll(Calendar.YEAR, -1);
- SimpleDateFormat httpDate =
- new SimpleDateFormat(
- "EEE, dd MMM yyyy HH:mm:ss z",
- java.util.Locale.US);
- EXPIRATION_DATE = httpDate.format(expiration.getTime());
- }
-
- // Init-param values:
- private String templatePath;
- private boolean noCache;
- private Integer bufferSize;
- private boolean exceptionOnMissingTemplate;
-
- /**
- * @deprecated Not used anymore; to enable/disable debug logging, just set
the logging level of the logging library
- * used by {@link Logger}.
- */
- @Deprecated
- protected boolean debug;
-
- @SuppressFBWarnings(value="SE_BAD_FIELD", justification="Not investing
into making this Servlet serializable")
- private Configuration config;
- @SuppressFBWarnings(value="SE_BAD_FIELD", justification="Not investing
into making this Servlet serializable")
- private ObjectWrapper wrapper;
- private ContentType contentType;
- private OverrideResponseContentType overrideResponseContentType =
initParamValueToEnum(
- getDefaultOverrideResponseContentType(),
OverrideResponseContentType.values());
- private ResponseCharacterEncoding responseCharacterEncoding =
ResponseCharacterEncoding.LEGACY;
- @SuppressFBWarnings(value="SE_BAD_FIELD", justification="Not investing
into making this Servlet serializable")
- private Charset forcedResponseCharacterEncoding;
- private OverrideResponseLocale overrideResponseLocale =
OverrideResponseLocale.ALWAYS;
- private List/*<MetaInfTldSource>*/ metaInfTldSources;
- private List/*<String>*/ classpathTlds;
-
- private Object lazyInitFieldsLock = new Object();
- @SuppressFBWarnings(value="SE_BAD_FIELD", justification="Not investing
into making this Servlet serializable")
- private ServletContextHashModel servletContextModel;
- @SuppressFBWarnings(value="SE_BAD_FIELD", justification="Not investing
into making this Servlet serializable")
- private TaglibFactory taglibFactory;
-
- private boolean objectWrapperMismatchWarnLogged;
-
- /**
- * Don't override this method to adjust FreeMarker settings! Override the
protected methods for that, such as
- * {@link #createConfiguration()}, {@link #createTemplateLoader(String)},
{@link #createDefaultObjectWrapper()},
- * etc. Also note that lot of things can be changed with init-params
instead of overriding methods, so if you
- * override settings, usually you should only override their defaults.
- */
- @Override
- public void init() throws ServletException {
- try {
- initialize();
- } catch (Exception e) {
- // At least Jetty doesn't log the ServletException itself, only
its cause exception. Thus we add some
- // message here that (re)states the obvious.
- throw new ServletException("Error while initializing " +
this.getClass().getName()
- + " servlet; see cause exception.", e);
- }
- }
-
- private void initialize() throws InitParamValueException,
MalformedWebXmlException, ConflictingInitParamsException {
- config = createConfiguration();
-
- // Only override what's coming from the config if it was explicitly
specified:
- final String iciInitParamValue =
getInitParameter(Configuration.INCOMPATIBLE_IMPROVEMENTS_KEY);
- if (iciInitParamValue != null) {
- try {
- config.setSetting(Configuration.INCOMPATIBLE_IMPROVEMENTS_KEY,
iciInitParamValue);
- } catch (Exception e) {
- throw new
InitParamValueException(Configuration.INCOMPATIBLE_IMPROVEMENTS_KEY,
iciInitParamValue, e);
- }
- }
-
- // Set FreemarkerServlet-specific defaults, except where
createConfiguration() has already set them:
- if (!config.isTemplateExceptionHandlerExplicitlySet()) {
-
config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
- }
- if (!config.isLogTemplateExceptionsExplicitlySet()) {
- config.setLogTemplateExceptions(false);
- }
-
- contentType = DEFAULT_CONTENT_TYPE;
-
- // Process object_wrapper init-param out of order:
- wrapper = createObjectWrapper();
- LOG.debug("Using object wrapper {}", wrapper);
- config.setObjectWrapper(wrapper);
-
- // Process TemplatePath init-param out of order:
- templatePath = getInitParameter(INIT_PARAM_TEMPLATE_PATH);
- if (templatePath == null && !config.isTemplateLoaderExplicitlySet()) {
- templatePath = InitParamParser.TEMPLATE_PATH_PREFIX_CLASS;
- }
- if (templatePath != null) {
- try {
- config.setTemplateLoader(createTemplateLoader(templatePath));
- } catch (Exception e) {
- throw new InitParamValueException(INIT_PARAM_TEMPLATE_PATH,
templatePath, e);
- }
- }
-
- metaInfTldSources = createDefaultMetaInfTldSources();
- classpathTlds = createDefaultClassPathTlds();
-
- // Process all other init-params:
- Enumeration initpnames = getServletConfig().getInitParameterNames();
- while (initpnames.hasMoreElements()) {
- final String name = (String) initpnames.nextElement();
- final String value = getInitParameter(name);
- if (name == null) {
- throw new MalformedWebXmlException(
- "init-param without param-name. "
- + "Maybe the web.xml is not well-formed?");
- }
- if (value == null) {
- throw new MalformedWebXmlException(
- "init-param " + StringUtil.jQuote(name) + " without
param-value. "
- + "Maybe the web.xml is not well-formed?");
- }
-
- try {
- if (name.equals(DEPR_INITPARAM_OBJECT_WRAPPER)
- || name.equals(Configurable.OBJECT_WRAPPER_KEY)
- || name.equals(INIT_PARAM_TEMPLATE_PATH)
- ||
name.equals(Configuration.INCOMPATIBLE_IMPROVEMENTS)) {
- // ignore: we have already processed these
- } else if (name.equals(DEPR_INITPARAM_ENCODING)) { // BC
- if (getInitParameter(Configuration.DEFAULT_ENCODING_KEY)
!= null) {
- throw new ConflictingInitParamsException(
- Configuration.DEFAULT_ENCODING_KEY,
DEPR_INITPARAM_ENCODING);
- }
- config.setDefaultEncoding(value);
- } else if (name.equals(DEPR_INITPARAM_TEMPLATE_DELAY)) { // BC
- if
(getInitParameter(Configuration.TEMPLATE_UPDATE_DELAY_KEY) != null) {
- throw new ConflictingInitParamsException(
- Configuration.TEMPLATE_UPDATE_DELAY_KEY,
DEPR_INITPARAM_TEMPLATE_DELAY);
- }
- try {
- config.setTemplateUpdateDelay(Integer.parseInt(value));
- } catch (NumberFormatException e) {
- // Intentionally ignored
- }
- } else if
(name.equals(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER)) { // BC
- if
(getInitParameter(Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY) != null) {
- throw new ConflictingInitParamsException(
- Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY,
DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER);
- }
-
- if
(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_RETHROW.equals(value)) {
-
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
- } else if
(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_DEBUG.equals(value)) {
-
config.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
- } else if
(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_HTML_DEBUG.equals(value)) {
-
config.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
- } else if
(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER_IGNORE.equals(value)) {
-
config.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
- } else {
- throw new
InitParamValueException(DEPR_INITPARAM_TEMPLATE_EXCEPTION_HANDLER, value,
- "Not one of the supported values.");
- }
- } else if (name.equals(INIT_PARAM_NO_CACHE)) {
- noCache = StringUtil.getYesNo(value);
- } else if (name.equals(INIT_PARAM_BUFFER_SIZE)) {
- bufferSize = Integer.valueOf(parseSize(value));
- } else if (name.equals(DEPR_INITPARAM_DEBUG)) { // BC
- if (getInitParameter(INIT_PARAM_DEBUG) != null) {
- throw new
ConflictingInitParamsException(INIT_PARAM_DEBUG, DEPR_INITPARAM_DEBUG);
- }
- debug = StringUtil.getYesNo(value);
- } else if (name.equals(INIT_PARAM_DEBUG)) {
- debug = StringUtil.getYesNo(value);
- } else if (name.equals(INIT_PARAM_CONTENT_TYPE)) {
- contentType = new ContentType(value);
- } else if
(name.equals(INIT_PARAM_OVERRIDE_RESPONSE_CONTENT_TYPE)) {
- overrideResponseContentType = initParamValueToEnum(value,
OverrideResponseContentType.values());
- } else if
(name.equals(INIT_PARAM_RESPONSE_CHARACTER_ENCODING)) {
- responseCharacterEncoding = initParamValueToEnum(value,
ResponseCharacterEncoding.values());
- if (responseCharacterEncoding ==
ResponseCharacterEncoding.FORCE_CHARSET) {
- String charsetName =
value.substring(INIT_PARAM_VALUE_FORCE_PREFIX.length()).trim();
- forcedResponseCharacterEncoding =
Charset.forName(charsetName);
- }
- } else if (name.equals(INIT_PARAM_OVERRIDE_RESPONSE_LOCALE)) {
- overrideResponseLocale = initParamValueToEnum(value,
OverrideResponseLocale.values());
- } else if
(name.equals(INIT_PARAM_EXCEPTION_ON_MISSING_TEMPLATE)) {
- exceptionOnMissingTemplate = StringUtil.getYesNo(value);
- } else if (name.equals(INIT_PARAM_META_INF_TLD_LOCATIONS)) {;
- metaInfTldSources = parseAsMetaInfTldLocations(value);
- } else if (name.equals(INIT_PARAM_CLASSPATH_TLDS)) {;
- List newClasspathTlds = new ArrayList();
- if (classpathTlds != null) {
- newClasspathTlds.addAll(classpathTlds);
- }
-
newClasspathTlds.addAll(InitParamParser.parseCommaSeparatedList(value));
- classpathTlds = newClasspathTlds;
- } else {
- config.setSetting(name, value);
- }
- } catch (ConflictingInitParamsException e) {
- throw e;
- } catch (Exception e) {
- throw new InitParamValueException(name, value, e);
- }
- } // while initpnames
-
- if (contentType.containsCharset && responseCharacterEncoding !=
ResponseCharacterEncoding.LEGACY) {
- throw new InitParamValueException(INIT_PARAM_CONTENT_TYPE,
contentType.httpHeaderValue,
- new IllegalStateException("You can't specify the charset
in the content type, because the \"" +
- INIT_PARAM_RESPONSE_CHARACTER_ENCODING + "\"
init-param isn't set to "
- + "\"" + INIT_PARAM_VALUE_LEGACY + "\"."));
- }
- }
-
- private List/*<MetaInfTldSource>*/ parseAsMetaInfTldLocations(String
value) throws ParseException {
- List/*<MetaInfTldSource>*/ metaInfTldSources = null;
-
- List/*<String>*/ values =
InitParamParser.parseCommaSeparatedList(value);
- for (Iterator it = values.iterator(); it.hasNext(); ) {
- final String itemStr = (String) it.next();
- final MetaInfTldSource metaInfTldSource;
- if (itemStr.equals(META_INF_TLD_LOCATION_WEB_INF_PER_LIB_JARS)) {
- metaInfTldSource = WebInfPerLibJarMetaInfTldSource.INSTANCE;
- } else if (itemStr.startsWith(META_INF_TLD_LOCATION_CLASSPATH)) {
- String itemRightSide =
itemStr.substring(META_INF_TLD_LOCATION_CLASSPATH.length()).trim();
- if (itemRightSide.length() == 0) {
- metaInfTldSource = new
ClasspathMetaInfTldSource(Pattern.compile(".*", Pattern.DOTALL));
- } else if (itemRightSide.startsWith(":")) {
- final String regexpStr = itemRightSide.substring(1).trim();
- if (regexpStr.length() == 0) {
- throw new ParseException("Empty regular expression
after \""
- + META_INF_TLD_LOCATION_CLASSPATH + ":\"", -1);
- }
- metaInfTldSource = new
ClasspathMetaInfTldSource(Pattern.compile(regexpStr));
- } else {
- throw new ParseException("Invalid \"" +
META_INF_TLD_LOCATION_CLASSPATH
- + "\" value syntax: " + value, -1);
- }
- } else if (itemStr.startsWith(META_INF_TLD_LOCATION_CLEAR)) {
- metaInfTldSource = ClearMetaInfTldSource.INSTANCE;
- } else {
- throw new ParseException("Item has no recognized source type
prefix: " + itemStr, -1);
- }
- if (metaInfTldSources == null) {
- metaInfTldSources = new ArrayList();
- }
- metaInfTldSources.add(metaInfTldSource);
- }
-
- return metaInfTldSources;
- }
-
- /**
- * Create the template loader. The default implementation will create a
{@link ClassTemplateLoader} if the template
- * path starts with {@code "class://"}, a {@link FileTemplateLoader} if
the template path starts with
- * {@code "file://"}, and a {@link WebAppTemplateLoader} otherwise. Also,
if
- * {@link Configuration#Configuration(freemarker.template.Version)
incompatible_improvements} is 2.3.22 or higher,
- * it will create a {@link MultiTemplateLoader} if the template path
starts with {@code "["}.
- *
- * @param templatePath
- * the template path to create a loader for
- * @return a newly created template loader
- */
- protected TemplateLoader createTemplateLoader(String templatePath) throws
IOException {
- return InitParamParser.createTemplateLoader(templatePath,
getConfiguration(), getClass(), getServletContext());
- }
-
- @Override
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- process(request, response);
- }
-
- @Override
- public void doPost(
- HttpServletRequest request,
- HttpServletResponse response)
- throws ServletException, IOException {
- process(request, response);
- }
-
- private void process(
- HttpServletRequest request,
- HttpServletResponse response)
- throws ServletException, IOException {
- // Give chance to subclasses to perform preprocessing
- if (preprocessRequest(request, response)) {
- return;
- }
-
- if (bufferSize != null && !response.isCommitted()) {
- try {
- response.setBufferSize(bufferSize.intValue());
- } catch (IllegalStateException e) {
- LOG.debug("Can't set the response buffer size any more", e);
- }
- }
-
- String templatePath = requestUrlToTemplatePath(request);
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Requested template " +
StringUtil.jQuoteNoXSS(templatePath) + ".");
- }
-
- Locale locale = request.getLocale();
- if (locale == null || overrideResponseLocale !=
OverrideResponseLocale.NEVER) {
- locale = deduceLocale(templatePath, request, response);
- }
-
- final Template template;
- try {
- template = config.getTemplate(templatePath, locale);
- } catch (TemplateNotFoundException e) {
- if (exceptionOnMissingTemplate) {
- throw newServletExceptionWithFreeMarkerLogging(
- "Template not found for name " +
StringUtil.jQuoteNoXSS(templatePath) + ".", e);
- } else {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Responding HTTP 404 \"Not found\" for missing
template "
- + StringUtil.jQuoteNoXSS(templatePath) + ".", e);
- }
- response.sendError(HttpServletResponse.SC_NOT_FOUND, "Page
template not found");
- return;
- }
- } catch (freemarker.core.ParseException e) {
- throw newServletExceptionWithFreeMarkerLogging(
- "Parsing error with template " +
StringUtil.jQuoteNoXSS(templatePath) + ".", e);
- } catch (Exception e) {
- throw newServletExceptionWithFreeMarkerLogging(
- "Unexpected error when loading template " +
StringUtil.jQuoteNoXSS(templatePath) + ".", e);
- }
-
- boolean tempSpecContentTypeContainsCharset = false;
- if (response.getContentType() == null || overrideResponseContentType
!= OverrideResponseContentType.NEVER) {
- ContentType templateSpecificContentType =
getTemplateSpecificContentType(template);
- if (templateSpecificContentType != null) {
- // With ResponseCharacterEncoding.LEGACY we should append the
charset, but we don't do that for b. c.
- response.setContentType(
- responseCharacterEncoding !=
ResponseCharacterEncoding.DO_NOT_SET
- ? templateSpecificContentType.httpHeaderValue
- : templateSpecificContentType.getMimeType());
- tempSpecContentTypeContainsCharset =
templateSpecificContentType.containsCharset;
- } else if (response.getContentType() == null
- || overrideResponseContentType ==
OverrideResponseContentType.ALWAYS) {
- if (responseCharacterEncoding ==
ResponseCharacterEncoding.LEGACY && !contentType.containsCharset) {
- // In legacy mode we don't call
response.setCharacterEncoding, so the charset must be set here:
- response.setContentType(
- contentType.httpHeaderValue + "; charset=" +
getOutputEncodingForTemplate(template));
- } else {
- response.setContentType(contentType.httpHeaderValue);
- }
- }
- }
-
- if (responseCharacterEncoding != ResponseCharacterEncoding.LEGACY
- && responseCharacterEncoding !=
ResponseCharacterEncoding.DO_NOT_SET) {
- // Using the Servlet 2.4 way of setting character encoding.
- if (responseCharacterEncoding !=
ResponseCharacterEncoding.FORCE_CHARSET) {
- if (!tempSpecContentTypeContainsCharset) {
-
response.setCharacterEncoding(getOutputEncodingForTemplate(template));
- }
- } else {
-
response.setCharacterEncoding(forcedResponseCharacterEncoding.name());
- }
- }
-
- setBrowserCachingPolicy(response);
-
- ServletContext servletContext = getServletContext();
- try {
- logWarnOnObjectWrapperMismatch();
-
- TemplateModel model = createModel(wrapper, servletContext,
request, response);
-
- // Give subclasses a chance to hook into preprocessing
- if (preTemplateProcess(request, response, template, model)) {
- try {
- // Process the template
- Environment env =
template.createProcessingEnvironment(model, response.getWriter());
- if (responseCharacterEncoding !=
ResponseCharacterEncoding.LEGACY) {
- String actualOutputCharset =
response.getCharacterEncoding();
- if (actualOutputCharset != null) {
- env.setOutputEncoding(actualOutputCharset);
- }
- }
- processEnvironment(env, request, response);
- } finally {
- // Give subclasses a chance to hook into postprocessing
- postTemplateProcess(request, response, template, model);
- }
- }
- } catch (TemplateException e) {
- final TemplateExceptionHandler teh =
config.getTemplateExceptionHandler();
- // Ensure that debug handler responses aren't rolled back:
- if (teh == TemplateExceptionHandler.HTML_DEBUG_HANDLER || teh ==
TemplateExceptionHandler.DEBUG_HANDLER
- || teh.getClass().getName().indexOf("Debug") != -1) {
- response.flushBuffer();
- }
- throw newServletExceptionWithFreeMarkerLogging("Error executing
FreeMarker template", e);
- }
- }
-
- /**
- * This is the method that actually executes the template. The original
implementation coming from
- * {@link FreemarkerServlet} simply calls {@link Environment#process()}.
Overriding this method allows you to
- * prepare the {@link Environment} before the execution, or extract
information from the {@link Environment} after
- * the execution. It also allows you to capture exceptions throw by the
template.
- *
- * @param env
- * The {@link Environment} object already set up to execute the
template. You only have to call
- * {@link Environment#process()} and the output will be
produced by the template.
- *
- * @since 2.3.24
- */
- protected void processEnvironment(Environment env, HttpServletRequest
request, HttpServletResponse response)
- throws TemplateException, IOException {
- env.process();
- }
-
- private String getOutputEncodingForTemplate(Template template) {
- String outputEncoding = responseCharacterEncoding ==
ResponseCharacterEncoding.LEGACY ? null
- : template.getOutputEncoding();
- // [FM3] Don't use template.getEncoding() here; it might can't encode
the dynamic values inserted.
- return outputEncoding != null ? outputEncoding
- : template.getEncoding() != null ? template.getEncoding()
- : StandardCharsets.UTF_8.name();
- }
-
- private ContentType getTemplateSpecificContentType(final Template
template) {
- Object contentTypeAttr = template.getCustomAttribute("content_type");
- if (contentTypeAttr != null) {
- // Converted with toString() for backward compatibility.
- return new ContentType(contentTypeAttr.toString());
- }
-
- String outputFormatMimeType = template.getOutputFormat().getMimeType();
- if (outputFormatMimeType != null) {
- if (responseCharacterEncoding == ResponseCharacterEncoding.LEGACY)
{
- // In legacy mode we won't call
serlvetResponse.setCharacterEncoding(...), so:
- return new ContentType(
- outputFormatMimeType + "; charset=" +
getOutputEncodingForTemplate(template),
- true);
- } else {
- return new ContentType(outputFormatMimeType, false);
- }
- }
-
- return null;
- }
-
- private ServletException newServletExceptionWithFreeMarkerLogging(String
message, Throwable cause) throws ServletException {
- if (cause instanceof TemplateException) {
- // For backward compatibility, we log into the same category as
Environment did when
- // log_template_exceptions was true.
- LOG_RT.error(message, cause);
- } else {
- LOG.error(message, cause);
- }
-
- ServletException e = new ServletException(message, cause);
- try {
- // Prior to Servlet 2.5, the cause exception wasn't set by the
above constructor.
- // If we are on 2.5+ then this will throw an exception as the
cause was already set.
- e.initCause(cause);
- } catch (Exception ex) {
- // Ignored; see above
- }
- throw e;
- }
-
- @SuppressFBWarnings(value={ "MSF_MUTABLE_SERVLET_FIELD", "DC_DOUBLECHECK"
}, justification="Performance trick")
- private void logWarnOnObjectWrapperMismatch() {
- // Deliberately uses double check locking.
- if (wrapper != config.getObjectWrapper() &&
!objectWrapperMismatchWarnLogged && LOG.isWarnEnabled()) {
- final boolean logWarn;
- synchronized (this) {
- logWarn = !objectWrapperMismatchWarnLogged;
- if (logWarn) {
- objectWrapperMismatchWarnLogged = true;
- }
- }
- if (logWarn) {
- LOG.warn(
- this.getClass().getName()
- + ".wrapper != config.getObjectWrapper(); possibly the
result of incorrect extension of "
- + FreemarkerServlet.class.getName() + ".");
- }
- }
- }
-
- /**
- * Returns the locale used for the {@link
Configuration#getTemplate(String, Locale)} call (as far as the
- * {@value #INIT_PARAM_OVERRIDE_RESPONSE_LOCALE} Servlet init-param allows
that). The base implementation in
- * {@link FreemarkerServlet} simply returns the {@code locale} setting of
the configuration. Override this method to
- * provide different behavior, for example, to use the locale indicated in
the HTTP request.
- *
- * @param templatePath
- * The template path (template name) as it will be passed to
{@link Configuration#getTemplate(String)}.
- * (Not to be confused with the servlet init-param of identical
name; they aren't related.)
- *
- * @throws ServletException
- * Can be thrown since 2.3.22, if the locale can't be deduced
from the URL.
- */
- protected Locale deduceLocale(String templatePath, HttpServletRequest
request, HttpServletResponse response)
- throws ServletException {
- return config.getLocale();
- }
-
- protected TemplateModel createModel(ObjectWrapper objectWrapper,
- ServletContext servletContext,
- final HttpServletRequest request,
- final HttpServletResponse response)
throws TemplateModelException {
- try {
- AllHttpScopesHashModel params = new
AllHttpScopesHashModel(objectWrapper, servletContext, request);
-
- // Create hash model wrapper for servlet context (the application)
- final ServletContextHashModel servletContextModel;
- final TaglibFactory taglibFactory;
- synchronized (lazyInitFieldsLock) {
- if (this.servletContextModel == null) {
- servletContextModel = new ServletContextHashModel(this,
objectWrapper);
- taglibFactory = createTaglibFactory(objectWrapper,
servletContext);
-
- // For backward compatibility only. We don't use these:
- servletContext.setAttribute(ATTR_APPLICATION_MODEL,
servletContextModel);
- servletContext.setAttribute(ATTR_JSP_TAGLIBS_MODEL,
taglibFactory);
-
- initializeServletContext(request, response);
-
- this.taglibFactory = taglibFactory;
- this.servletContextModel = servletContextModel;
- } else {
- servletContextModel = this.servletContextModel;
- taglibFactory = this.taglibFactory;
- }
- }
-
- params.putUnlistedModel(KEY_APPLICATION, servletContextModel);
- params.putUnlistedModel(KEY_APPLICATION_PRIVATE,
servletContextModel);
- params.putUnlistedModel(KEY_JSP_TAGLIBS, taglibFactory);
- // Create hash model wrapper for session
- HttpSessionHashModel sessionModel;
- HttpSession session = request.getSession(false);
- if (session != null) {
- sessionModel = (HttpSessionHashModel)
session.getAttribute(ATTR_SESSION_MODEL);
- if (sessionModel == null || sessionModel.isOrphaned(session)) {
- sessionModel = new HttpSessionHashModel(session,
objectWrapper);
- initializeSessionAndInstallModel(request, response,
- sessionModel, session);
- }
- } else {
- sessionModel = new HttpSessionHashModel(this, request,
response, objectWrapper);
- }
- params.putUnlistedModel(KEY_SESSION, sessionModel);
-
- // Create hash model wrapper for request
- HttpRequestHashModel requestModel =
- (HttpRequestHashModel)
request.getAttribute(ATTR_REQUEST_MODEL);
- if (requestModel == null || requestModel.getRequest() != request) {
- requestModel = new HttpRequestHashModel(request, response,
objectWrapper);
- request.setAttribute(ATTR_REQUEST_MODEL, requestModel);
- request.setAttribute(
- ATTR_REQUEST_PARAMETERS_MODEL,
- createRequestParametersHashModel(request));
- }
- params.putUnlistedModel(KEY_REQUEST, requestModel);
- params.putUnlistedModel(KEY_INCLUDE, new IncludePage(request,
response));
- params.putUnlistedModel(KEY_REQUEST_PRIVATE, requestModel);
-
- // Create hash model wrapper for request parameters
- HttpRequestParametersHashModel requestParametersModel =
- (HttpRequestParametersHashModel) request.getAttribute(
- ATTR_REQUEST_PARAMETERS_MODEL);
- params.putUnlistedModel(KEY_REQUEST_PARAMETERS,
requestParametersModel);
- return params;
- } catch (ServletException e) {
- throw new TemplateModelException(e);
- } catch (IOException e) {
- throw new TemplateModelException(e);
- }
- }
-
- /**
- * Called to create the {@link TaglibFactory} once per servlet context.
- * The default implementation configures it based on the servlet-init
parameters and various other environmental
- * settings, so if you override this method, you should call super, then
adjust the result.
- *
- * @since 2.3.22
- */
- protected TaglibFactory createTaglibFactory(ObjectWrapper objectWrapper,
- ServletContext servletContext) throws TemplateModelException {
- TaglibFactory taglibFactory = new TaglibFactory(servletContext);
-
- taglibFactory.setObjectWrapper(objectWrapper);
-
- {
- List/*<MetaInfTldSource>*/ mergedMetaInfTldSources = new
ArrayList();
-
- if (metaInfTldSources != null) {
- mergedMetaInfTldSources.addAll(metaInfTldSources);
- }
-
- String sysPropVal =
SecurityUtilities.getSystemProperty(SYSTEM_PROPERTY_META_INF_TLD_SOURCES, null);
- if (sysPropVal != null) {
- try {
- List metaInfTldSourcesSysProp =
parseAsMetaInfTldLocations(sysPropVal);
- if (metaInfTldSourcesSysProp != null) {
-
mergedMetaInfTldSources.addAll(metaInfTldSourcesSysProp);
- }
- } catch (ParseException e) {
- throw new TemplateModelException("Failed to parse system
property \""
- + SYSTEM_PROPERTY_META_INF_TLD_SOURCES + "\"", e);
- }
- }
-
- List/*<Pattern>*/ jettyTaglibJarPatterns = null;
- try {
- final String attrVal = (String)
servletContext.getAttribute(ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS);
- jettyTaglibJarPatterns = attrVal != null ?
InitParamParser.parseCommaSeparatedPatterns(attrVal) : null;
- } catch (Exception e) {
- LOG.error("Failed to parse application context attribute \""
- + ATTR_JETTY_CP_TAGLIB_JAR_PATTERNS + "\" - it will be
ignored", e);
- }
- if (jettyTaglibJarPatterns != null) {
- for (Iterator/*<Pattern>*/ it =
jettyTaglibJarPatterns.iterator(); it.hasNext(); ) {
- Pattern pattern = (Pattern) it.next();
- mergedMetaInfTldSources.add(new
ClasspathMetaInfTldSource(pattern));
- }
- }
-
- taglibFactory.setMetaInfTldSources(mergedMetaInfTldSources);
- }
-
- {
- List/*<String>*/ mergedClassPathTlds = new ArrayList();
- if (classpathTlds != null) {
- mergedClassPathTlds.addAll(classpathTlds);
- }
-
- String sysPropVal =
SecurityUtilities.getSystemProperty(SYSTEM_PROPERTY_CLASSPATH_TLDS, null);
- if (sysPropVal != null) {
- try {
- List/*<String>*/ classpathTldsSysProp =
InitParamParser.parseCommaSeparatedList(sysPropVal);
- if (classpathTldsSysProp != null) {
- mergedClassPathTlds.addAll(classpathTldsSysProp);
- }
- } catch (ParseException e) {
- throw new TemplateModelException("Failed to parse system
property \""
- + SYSTEM_PROPERTY_CLASSPATH_TLDS + "\"", e);
- }
- }
-
- taglibFactory.setClasspathTlds(mergedClassPathTlds);
- }
-
- return taglibFactory;
- }
-
- /**
- * Creates the default of the {@value #INIT_PARAM_CLASSPATH_TLDS}
init-param; if this init-param is specified, it
- * will be appended <em>after</em> the default, not replace it.
- *
- * <p>
- * The implementation in {@link FreemarkerServlet} returns {@link
TaglibFactory#DEFAULT_CLASSPATH_TLDS}.
- *
- * @return A {@link List} of {@link String}-s; not {@code null}.
- *
- * @since 2.3.22
- */
- protected List/*<MetaInfTldSource>*/ createDefaultClassPathTlds() {
- return TaglibFactory.DEFAULT_CLASSPATH_TLDS;
- }
-
- /**
- * Creates the default of the {@value #INIT_PARAM_META_INF_TLD_LOCATIONS}
init-param; if this init-param is
- * specified, it will completelly <em>replace</em> the default value.
- *
- * <p>
- * The implementation in {@link FreemarkerServlet} returns {@link
TaglibFactory#DEFAULT_META_INF_TLD_SOURCES}.
- *
- * @return A {@link List} of {@link MetaInfTldSource}-s; not {@code null}.
- *
- * @since 2.3.22
- */
- protected List/*<MetaInfTldSource>*/ createDefaultMetaInfTldSources() {
- return TaglibFactory.DEFAULT_META_INF_TLD_SOURCES;
- }
-
- void initializeSessionAndInstallModel(HttpServletRequest request,
- HttpServletResponse response, HttpSessionHashModel sessionModel,
- HttpSession session)
- throws ServletException, IOException {
- session.setAttribute(ATTR_SESSION_MODEL, sessionModel);
- initializeSession(request, response);
- }
-
- /**
- * Maps the request URL to a template path (template name) that is passed
to
- * {@link Configuration#getTemplate(String, Locale)}. You can override it
(i.e. to provide advanced rewriting
- * capabilities), but you are strongly encouraged to call the overridden
method first, then only modify its return
- * value.
- *
- * @param request
- * The currently processed HTTP request
- * @return The template path (template name); can't be {@code null}. This
is what's passed to
- * {@link Configuration#getTemplate(String)} later. (Not to be
confused with the {@code templatePath}
- * servlet init-param of identical name; that basically specifies
the "virtual file system" to which this
- * will be relative to.)
- *
- * @throws ServletException
- * Can be thrown since 2.3.22, if the template path can't be
deduced from the URL.
- */
- protected String requestUrlToTemplatePath(HttpServletRequest request)
throws ServletException {
- // First, see if it's an included request
- String includeServletPath = (String)
request.getAttribute("javax.servlet.include.servlet_path");
- if (includeServletPath != null) {
- // Try path info; only if that's null (servlet is mapped to an
- // URL extension instead of to prefix) use servlet path.
- String includePathInfo = (String)
request.getAttribute("javax.servlet.include.path_info");
- return includePathInfo == null ? includeServletPath :
includePathInfo;
- }
- // Seems that the servlet was not called as the result of a
- // RequestDispatcher.include(...). Try pathInfo then servletPath again,
- // only now directly on the request object:
- String path = request.getPathInfo();
- if (path != null) return path;
- path = request.getServletPath();
- if (path != null) return path;
- // Seems that it's a servlet mapped with prefix, and there was no
extra path info.
- return "";
- }
-
- /**
- * Called as the first step in request processing, before the templating
mechanism
- * is put to work. By default does nothing and returns false. This method
is
- * typically overridden to manage serving of non-template resources (i.e.
images)
- * that reside in the template directory.
- * @param request the HTTP request
- * @param response the HTTP response
- * @return true to indicate this method has processed the request entirely,
- * and that the further request processing should not take place.
- */
- protected boolean preprocessRequest(
- HttpServletRequest request,
- HttpServletResponse response)
- throws ServletException, IOException {
- return false;
- }
-
- /**
- * Creates the FreeMarker {@link Configuration} singleton and (when
overidden) maybe sets its defaults. Servlet
- * init-params will be applied later, and thus can overwrite the settings
specified here.
- *
- * <p>
- * By overriding this method you can set your preferred {@link
Configuration} setting defaults, as only the settings
- * for which an init-param was specified will be overwritten later. (Note
that {@link FreemarkerServlet} also has
- * its own defaults for a few settings, but since 2.3.22, the servlet
detects if those settings were already set
- * here and then it won't overwrite them.)
- *
- * <p>
- * The default implementation simply creates a new instance with {@link
Configuration#Configuration()} and returns
- * it.
- */
- protected Configuration createConfiguration() {
- // We can only set incompatible_improvements later, so ignore the
deprecation warning here.
- return new Configuration();
- }
-
- /**
- * Sets the defaults of the configuration that are specific to the {@link
FreemarkerServlet} subclass.
- * This is called after the common (wired in) {@link FreemarkerServlet}
setting defaults was set, also the
- */
- protected void setConfigurationDefaults() {
- // do nothing
- }
-
- /**
- * Called from {@link #init()} to create the {@link ObjectWrapper}; to
customzie this aspect, in most cases you
- * should override {@link #createDefaultObjectWrapper()} instead.
Overriding this method is necessary when you want
- * to customize how the {@link ObjectWrapper} is created <em>from the
init-param values</em>, or you want to do some
- * post-processing (like checking) on the created {@link ObjectWrapper}.
To customize init-param interpretation,
- * call {@link #getInitParameter(String)} with {@link
Configurable#OBJECT_WRAPPER_KEY} as argument, and see if it
- * returns a value that you want to interpret yourself. If was {@code
null} or you don't want to interpret the
- * value, fall back to the super method.
- *
- * <p>
- * The default implementation interprets the {@code object_wrapper}
servlet init-param with
- * calling {@link Configurable#setSetting(String, String)} (see valid
values there), or if there's no such servlet
- * init-param, then it calls {@link #createDefaultObjectWrapper()}.
- *
- * @return The {@link ObjectWrapper} that will be used for adapting
request, session, and servlet context attributes
- * to {@link TemplateModel}-s, and also as the object wrapper
setting of {@link Configuration}.
- */
- protected ObjectWrapper createObjectWrapper() {
- String wrapper =
getServletConfig().getInitParameter(DEPR_INITPARAM_OBJECT_WRAPPER);
- if (wrapper != null) { // BC
- if (getInitParameter(Configurable.OBJECT_WRAPPER_KEY) != null) {
- throw new RuntimeException("Conflicting init-params: "
- + Configurable.OBJECT_WRAPPER_KEY + " and "
- + DEPR_INITPARAM_OBJECT_WRAPPER);
- }
- if (DEPR_INITPARAM_WRAPPER_BEANS.equals(wrapper)) {
- return ObjectWrapper.BEANS_WRAPPER;
- }
- if (DEPR_INITPARAM_WRAPPER_SIMPLE.equals(wrapper)) {
- return ObjectWrapper.SIMPLE_WRAPPER;
- }
- return createDefaultObjectWrapper();
- } else {
- wrapper = getInitParameter(Configurable.OBJECT_WRAPPER_KEY);
- if (wrapper == null) {
- if (!config.isObjectWrapperExplicitlySet()) {
- return createDefaultObjectWrapper();
- } else {
- return config.getObjectWrapper();
- }
- } else {
- try {
- config.setSetting(Configurable.OBJECT_WRAPPER_KEY,
wrapper);
- } catch (TemplateException e) {
- throw new RuntimeException("Failed to set " +
Configurable.OBJECT_WRAPPER_KEY, e);
- }
- return config.getObjectWrapper();
- }
- }
- }
-
- /**
- * Override this to specify what the default {@link ObjectWrapper} will be
when the
- * {@code object_wrapper} Servlet init-param wasn't specified. Note that
this is called by
- * {@link #createConfiguration()}, and so if that was also overidden but
improperly then this method might won't be
- * ever called. Also note that if you set the {@code object_wrapper} in
{@link #createConfiguration()}, then this
- * won't be called, since then that has already specified the default.
- *
- * <p>
- * The default implementation calls {@link
Configuration#getDefaultObjectWrapper(freemarker.template.Version)}. You
- * should also pass in the version paramter when creating an {@link
ObjectWrapper} that supports that. You can get
- * the version by calling {@link #getConfiguration()} and then {@link
Configuration#getIncompatibleImprovements()}.
- *
- * @since 2.3.22
- */
- protected ObjectWrapper createDefaultObjectWrapper() {
- return
Configuration.getDefaultObjectWrapper(config.getIncompatibleImprovements());
- }
-
- /**
- * Should be final; don't override it. Override {@link
#createObjectWrapper()} instead.
- */
- // [2.4] Make it final
- protected ObjectWrapper getObjectWrapper() {
- return wrapper;
- }
-
- /**
- * The value of the {@code TemplatePath} init-param. {@code null} if the
{@code template_loader} setting was set in
- * a custom {@link #createConfiguration()}.
- *
- * @deprecated Not called by FreeMarker code, and there's no point to
override this (unless to cause confusion).
- */
- @Deprecated
- protected final String getTemplatePath() {
- return templatePath;
- }
-
- protected HttpRequestParametersHashModel
createRequestParametersHashModel(HttpServletRequest request) {
- return new HttpRequestParametersHashModel(request);
- }
-
- /**
- * Called when servlet detects in a request processing that
- * application-global (that is, ServletContext-specific) attributes are
not yet
- * set.
- * This is a generic hook you might use in subclasses to perform a specific
- * action on first request in the context. By default it does nothing.
- * @param request the actual HTTP request
- * @param response the actual HTTP response
- */
- protected void initializeServletContext(
- HttpServletRequest request,
- HttpServletResponse response)
- throws ServletException, IOException {
- }
-
- /**
- * Called when servlet detects in a request processing that session-global
- * (that is, HttpSession-specific) attributes are not yet set.
- * This is a generic hook you might use in subclasses to perform a specific
- * action on first request in the session. By default it does nothing. It
- * is only invoked on newly created sessions; it's not invoked when a
- * replicated session is reinstantiated in another servlet container.
- *
- * @param request the actual HTTP request
- * @param response the actual HTTP response
- */
- protected void initializeSession(
- HttpServletRequest request,
- HttpServletResponse response)
- throws ServletException, IOException {
- }
-
- /**
- * Called before the execution is passed to {@link
Template#process(Object, java.io.Writer)}. This is a
- * generic hook you might use in subclasses to perform a specific action
before the template is processed.
- *
- * @param request
- * The HTTP request that we will response to.
- * @param response
- * The HTTP response. The HTTP headers are already initialized
here, such as the {@code conteType} and
- * the {@code responseCharacterEncoding} are already set, but
you can do the final adjustments here. The
- * response {@link Writer} isn't created yet, so changing HTTP
headers and buffering parameters works.
- * @param template
- * The template that will get executed
- * @param model
- * The data model that will be passed to the template. By
default this will be an
- * {@link AllHttpScopesHashModel} (which is a {@link
freemarker.template.SimpleHash} subclass). Thus, you
- * can add new variables to the data-model with the
- * {@link freemarker.template.SimpleHash#put(String, Object)}
subclass) method. However, to adjust the
- * data-model, overriding
- * {@link #createModel(ObjectWrapper, ServletContext,
HttpServletRequest, HttpServletResponse)} is
- * probably a more appropriate place.
- *
- * @return true to process the template, false to suppress template
processing.
- */
- protected boolean preTemplateProcess(
- HttpServletRequest request,
- HttpServletResponse response,
- Template template,
- TemplateModel model)
- throws ServletException, IOException {
- return true;
- }
-
- /**
- * Called after the execution returns from {@link Template#process(Object,
java.io.Writer)}.
- * This is a generic hook you might use in subclasses to perform a specific
- * action after the template is processed. It will be invoked even if the
- * template processing throws an exception. By default does nothing.
- * @param request the actual HTTP request
- * @param response the actual HTTP response
- * @param template the template that was executed
- * @param data the data that was passed to the template
- */
- protected void postTemplateProcess(
- HttpServletRequest request,
- HttpServletResponse response,
- Template template,
- TemplateModel data)
- throws ServletException, IOException {
- }
-
- /**
- * Returns the {@link freemarker.template.Configuration} object used by
this servlet.
- * Please don't forget that {@link freemarker.template.Configuration} is
not thread-safe
- * when you modify it.
- */
- protected Configuration getConfiguration() {
- return config;
- }
-
- /**
- * Returns the default value of the {@value
#INIT_PARAM_OVERRIDE_RESPONSE_CONTENT_TYPE} Servlet init-param.
- * The method inherited from {@link FreemarkerServlet} returns {@value
#INIT_PARAM_VALUE_ALWAYS}; subclasses my
- * override this.
- *
- * @since 2.3.24
- */
- protected String getDefaultOverrideResponseContentType() {
- return INIT_PARAM_VALUE_ALWAYS;
- }
-
- /**
- * If the parameter "nocache" was set to true, generate a set of headers
- * that will advise the HTTP client not to cache the returned page.
- */
- private void setBrowserCachingPolicy(HttpServletResponse res) {
- if (noCache) {
- // HTTP/1.1 + IE extensions
- res.setHeader("Cache-Control", "no-store, no-cache,
must-revalidate, "
- + "post-check=0, pre-check=0");
- // HTTP/1.0
- res.setHeader("Pragma", "no-cache");
- // Last resort for those that ignore all of the above
- res.setHeader("Expires", EXPIRATION_DATE);
- }
- }
-
- private int parseSize(String value) throws ParseException {
- int lastDigitIdx;
- for (lastDigitIdx = value.length() - 1; lastDigitIdx >= 0;
lastDigitIdx--) {
- char c = value.charAt(lastDigitIdx);
- if (c >= '0' && c <= '9') {
- break;
- }
- }
-
- final int n = Integer.parseInt(value.substring(0, lastDigitIdx +
1).trim());
-
- final String unitStr = value.substring(lastDigitIdx +
1).trim().toUpperCase();
- final int unit;
- if (unitStr.length() == 0 || unitStr.equals("B")) {
- unit = 1;
- } else if (unitStr.equals("K") || unitStr.equals("KB") ||
unitStr.equals("KIB")) {
- unit = 1024;
- } else if (unitStr.equals("M") || unitStr.equals("MB") ||
unitStr.equals("MIB")) {
- unit = 1024 * 1024;
- } else {
- throw new ParseException("Unknown unit: " + unitStr, lastDigitIdx
+ 1);
- }
-
- long size = (long) n * unit;
- if (size < 0) {
- throw new IllegalArgumentException("Buffer size can't be
negative");
- }
- if (size > Integer.MAX_VALUE) {
- throw new IllegalArgumentException("Buffer size can't bigger than
" + Integer.MAX_VALUE);
- }
- return (int) size;
- }
-
- private static class InitParamValueException extends Exception {
-
- InitParamValueException(String initParamName, String initParamValue,
Throwable casue) {
- super("Failed to set the " + StringUtil.jQuote(initParamName) + "
servlet init-param to "
- + StringUtil.jQuote(initParamValue) + "; see cause
exception.",
- casue);
- }
-
- public InitParamValueException(String initParamName, String
initParamValue, String cause) {
- super("Failed to set the " + StringUtil.jQuote(initParamName) + "
servlet init-param to "
- + StringUtil.jQuote(initParamValue) + ": " + cause);
- }
-
- }
-
- private static class ConflictingInitParamsException extends Exception {
-
- ConflictingInitParamsException(String recommendedName, String
otherName) {
- super("Conflicting servlet init-params: "
- + StringUtil.jQuote(recommendedName) + " and " +
StringUtil.jQuote(otherName)
- + ". Only use " + StringUtil.jQuote(recommendedName) +
".");
- }
- }
-
- private static class MalformedWebXmlException extends Exception {
-
- MalformedWebXmlException(String message) {
- super(message);
- }
-
- }
-
- private static class ContentType {
- private final String httpHeaderValue;
- private final boolean containsCharset;
-
- public ContentType(String httpHeaderValue) {
- this(httpHeaderValue, contentTypeContainsCharset(httpHeaderValue));
- }
-
- public ContentType(String httpHeaderValue, boolean containsCharset) {
- this.httpHeaderValue = httpHeaderValue;
- this.containsCharset = containsCharset;
- }
-
- private static boolean contentTypeContainsCharset(String contentType) {
- int charsetIdx = contentType.toLowerCase().indexOf("charset=");
- if (charsetIdx != -1) {
- char c = 0;
- charsetIdx--;
- while (charsetIdx >= 0) {
- c = contentType.charAt(charsetIdx);
- if (!Character.isWhitespace(c)) break;
- charsetIdx--;
- }
- if (charsetIdx == -1 || c == ';') {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Extracts the MIME type without the charset specifier or other such
extras.
- */
- private String getMimeType() {
- int scIdx = httpHeaderValue.indexOf(';');
- return (scIdx == -1 ? httpHeaderValue :
httpHeaderValue.substring(0, scIdx)).trim();
- }
-
- }
-
- private <T extends InitParamValueEnum> T initParamValueToEnum(String
initParamValue, T[] enumValues) {
- for (T enumValue : enumValues) {
- String enumInitParamValue = enumValue.getInitParamValue();
- if (initParamValue.equals(enumInitParamValue)
- || enumInitParamValue.endsWith("}") &&
initParamValue.startsWith(
- enumInitParamValue.substring(0,
enumInitParamValue.indexOf("${")))) {
- return enumValue;
- }
- }
-
- StringBuilder sb = new StringBuilder();
- sb.append(StringUtil.jQuote(initParamValue));
- sb.append(" is not a one of the enumeration values: ");
- boolean first = true;
- for (T value : enumValues) {
- if (!first) {
- sb.append(", ");
- } else {
- first = false;
- }
- sb.append(StringUtil.jQuote(value.getInitParamValue()));
- }
- throw new IllegalArgumentException(sb.toString());
- }
-
- /**
- * Superclass of all (future) init-param value enums.
- *
- * @see #initParamValueToEnum
- */
- private interface InitParamValueEnum {
- String getInitParamValue();
- }
-
- private enum OverrideResponseContentType implements InitParamValueEnum {
- ALWAYS(INIT_PARAM_VALUE_ALWAYS),
- NEVER(INIT_PARAM_VALUE_NEVER),
-
WHEN_TEMPLATE_HAS_MIME_TYPE(INIT_PARAM_VALUE_WHEN_TEMPLATE_HAS_MIME_TYPE);
-
- private final String initParamValue;
-
- OverrideResponseContentType(String initParamValue) {
- this.initParamValue = initParamValue;
- }
-
- @Override
- public String getInitParamValue() {
- return initParamValue;
- }
- }
-
- private enum ResponseCharacterEncoding implements InitParamValueEnum {
- // [FM3] Get rid of LEGACY
- LEGACY(INIT_PARAM_VALUE_LEGACY),
- FROM_TEMPLATE(INIT_PARAM_VALUE_FROM_TEMPLATE),
- DO_NOT_SET(INIT_PARAM_VALUE_DO_NOT_SET),
- FORCE_CHARSET(INIT_PARAM_VALUE_FORCE_PREFIX + "${charsetName}");
-
- private final String initParamValue;
-
- ResponseCharacterEncoding(String initParamValue) {
- this.initParamValue = initParamValue;
- }
-
- @Override
- public String getInitParamValue() {
- return initParamValue;
- }
- }
-
- private enum OverrideResponseLocale implements InitParamValueEnum {
- ALWAYS(INIT_PARAM_VALUE_ALWAYS),
- NEVER(INIT_PARAM_VALUE_NEVER);
-
- private final String initParamValue;
-
- OverrideResponseLocale(String initParamValue) {
- this.initParamValue = initParamValue;
- }
-
- @Override
- public String getInitParamValue() {
- return initParamValue;
- }
- }
-
-}