Class ExpiresFilter
- java.lang.Object
- 
- org.apache.catalina.filters.FilterBase
- 
- org.apache.catalina.filters.ExpiresFilter
 
 
- 
- All Implemented Interfaces:
- Filter
 
 public class ExpiresFilter extends FilterBase ExpiresFilter is a Java Servlet API port of Apache mod_expires to add ' Expires' and 'Cache-Control: max-age=' headers to HTTP response according to its 'Content-Type'.Following documentation is inspired by mod_expires SummaryThis filter controls the setting of the ExpiresHTTP header and themax-agedirective of theCache-ControlHTTP header in server responses. The expiration date can set to be relative to either the time the source file was last modified, or to the time of the client access.These HTTP headers are an instruction to the client about the document's validity and persistence. If cached, the document may be fetched from the cache rather than from the source until this time has passed. After that, the cache copy is considered "expired" and invalid, and a new copy must be obtained from the source. To modify Cache-Controldirectives other thanmax-age(see RFC 2616 section 14.9), you can use other servlet filters or Apache Httpd mod_headers module.Filter ConfigurationBasic configuration to add 'Expires' and 'Cache-Control: max-age=' headers to images, CSS and JavaScript<web-app ...> ... <filter> <filter-name>ExpiresFilter</filter-name> <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class> <init-param> <param-name>ExpiresByType image</param-name> <param-value>access plus 10 minutes</param-value> </init-param> <init-param> <param-name>ExpiresByType text/css</param-name> <param-value>access plus 10 minutes</param-value> </init-param> <init-param> <param-name>ExpiresByType application/javascript</param-name> <param-value>access plus 10 minutes</param-value> </init-param> </filter> ... <filter-mapping> <filter-name>ExpiresFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping> ... </web-app>Configuration ParametersExpiresByType <content-type>This directive defines the value of the Expiresheader and themax-agedirective of theCache-Controlheader generated for documents of the specified type (e.g.,text/html). The second argument sets the number of seconds that will be added to a base time to construct the expiration date. TheCache-Control: max-ageis calculated by subtracting the request time from the expiration date and expressing the result in seconds.The base time is either the last modification time of the file, or the time of the client's access to the document. Which should be used is specified by the <code>field;Mmeans that the file's last modification time should be used as the base time, andAmeans the client's access time should be used. The duration is expressed in seconds.A2592000stands foraccess plus 30 daysin alternate syntax.The difference in effect is subtle. If M(modificationin alternate syntax) is used, all current copies of the document in all caches will expire at the same time, which can be good for something like a weekly notice that's always found at the same URL. IfA(accessornowin alternate syntax) is used, the date of expiration is different for each client; this can be good for image files that don't change very often, particularly for a set of related documents that all refer to the same images (i.e., the images will be accessed repeatedly within a relatively short timespan).Example: <init-param> <param-name>ExpiresByType text/html</param-name> <param-value>access plus 1 month 15 days 2 hours</param-value> </init-param> <init-param> <!-- 2592000 seconds = 30 days --> <param-name>ExpiresByType image/gif</param-name> <param-value>A2592000</param-value> </init-param>Note that this directive only has effect if ExpiresActive Onhas been specified. It overrides, for the specified MIME type only, any expiration date set by theExpiresDefaultdirective.You can also specify the expiration time calculation using an alternate syntax, described earlier in this document. ExpiresExcludedResponseStatusCodesThis directive defines the http response status codes for which the ExpiresFilterwill not generate expiration headers. By default, the304status code ("Not modified") is skipped. The value is a comma separated list of http status codes.This directive is useful to ease usage of ExpiresDefaultdirective. Indeed, the behavior of304 Not modified(which does specify aContent-Typeheader) combined withExpiresandCache-Control:max-age=headers can be unnecessarily tricky to understand.Configuration sample : <init-param> <param-name>ExpiresExcludedResponseStatusCodes</param-name> <param-value>302, 500, 503</param-value> </init-param>ExpiresDefaultThis directive sets the default algorithm for calculating the expiration time for all documents in the affected realm. It can be overridden on a type-by-type basis by the ExpiresByTypedirective. See the description of that directive for details about the syntax of the argument, and the "alternate syntax" description as well.Alternate SyntaxThe ExpiresDefaultandExpiresByTypedirectives can also be defined in a more readable syntax of the form:<init-param> <param-name>ExpiresDefault</param-name> <param-value><base> [plus] (<num> <type>)*</param-value> </init-param> <init-param> <param-name>ExpiresByType type/encoding</param-name> <param-value><base> [plus] (<num> <type>)*</param-value> </init-param>where <base>is one of:- access
- now(equivalent to '- access')
- modification
 The pluskeyword is optional.<num>should be an integer value (acceptable toInteger.parseInt()), and<type>is one of:- years
- months
- weeks
- days
- hours
- minutes
- seconds
 For example, any of the following directives can be used to make documents expire 1 month after being accessed, by default: <init-param> <param-name>ExpiresDefault</param-name> <param-value>access plus 1 month</param-value> </init-param> <init-param> <param-name>ExpiresDefault</param-name> <param-value>access plus 4 weeks</param-value> </init-param> <init-param> <param-name>ExpiresDefault</param-name> <param-value>access plus 30 days</param-value> </init-param>The expiry time can be fine-tuned by adding several ' <num> <type>' clauses:<init-param> <param-name>ExpiresByType text/html</param-name> <param-value>access plus 1 month 15 days 2 hours</param-value> </init-param> <init-param> <param-name>ExpiresByType image/gif</param-name> <param-value>modification plus 5 hours 3 minutes</param-value> </init-param>Note that if you use a modification date based setting, the Expiresheader will not be added to content that does not come from a file on disk. This is due to the fact that there is no modification time for such content.Expiration headers generation eligibilityA response is eligible to be enriched by ExpiresFilterif :- no expiration header is defined (Expiresheader or themax-agedirective of theCache-Controlheader),
- the response status code is not excluded by the directive
 ExpiresExcludedResponseStatusCodes,
- the Content-Typeof the response matches one of the types defined the inExpiresByTypedirectives or theExpiresDefaultdirective is defined.
 Note : - If Cache-Controlheader contains other directives thanmax-age, they are concatenated with themax-agedirective that is added by theExpiresFilter.
 Expiration configuration selectionThe expiration configuration if elected according to the following algorithm: - ExpiresByTypematching the exact content-type returned by- HttpServletResponse.getContentType()possibly including the charset (e.g. '- text/xml;charset=UTF-8'),
- ExpiresByTypematching the content-type without the charset if- HttpServletResponse.getContentType()contains a charset (e.g. '- text/xml;charset=UTF-8' -> '- text/xml'),
- ExpiresByTypematching the major type (e.g. substring before '- /') of- HttpServletResponse.getContentType()(e.g. '- text/xml;charset=UTF-8' -> '- text'),
- ExpiresDefault
 Implementation DetailsWhen to write the expiration headers ?The ExpiresFiltertraps the 'on before write response body' event to decide whether it should generate expiration headers or not.To trap the 'before write response body' event, the ExpiresFilterwraps the http servlet response's writer and outputStream to intercept calls to the methodswrite(),print(),close()andflush(). For empty response body (e.g. empty files), thewrite(),print(),close()andflush()methods are not called; to handle this case, theExpiresFilter, at the end of itsdoFilter()method, manually triggers theonBeforeWriteResponseBody()method.Configuration syntaxThe ExpiresFiltersupports the same configuration syntax as Apache Httpd mod_expires.A challenge has been to choose the name of the <param-name>associated withExpiresByTypein the<filter>declaration. Indeed, SeveralExpiresByTypedirectives can be declared whenweb.xmlsyntax does not allow to declare several<init-param>with the same name.The workaround has been to declare the content type in the <param-name>rather than in the<param-value>.Designed for extension : the open/close principleThe ExpiresFilterhas been designed for extension following the open/close principle.Key methods to override for extension are : - 
 isEligibleToExpirationHeaderGeneration(HttpServletRequest, XHttpServletResponse)
- 
 getExpirationDate(HttpServletRequest, XHttpServletResponse)
 TroubleshootingTo troubleshoot, enable logging on the org.apache.catalina.filters.ExpiresFilter.Extract of logging.properties org.apache.catalina.filters.ExpiresFilter.level = FINESample of initialization log message : Mar 26, 2010 2:01:41 PM org.apache.catalina.filters.ExpiresFilter init FINE: Filter initialized with configuration ExpiresFilter[ excludedResponseStatusCode=[304], default=null, byType={ image=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]], text/css=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]], application/javascript=ExpiresConfiguration[startingPoint=ACCESS_TIME, duration=[10 MINUTE]]}]Sample of per-request log message where ExpiresFilteradds an expiration dateMar 26, 2010 2:09:47 PM org.apache.catalina.filters.ExpiresFilter onBeforeWriteResponseBody FINE: Request "/tomcat.gif" with response status "200" content-type "image/gif", set expiration date 3/26/10 2:19 PMSample of per-request log message where ExpiresFilterdoes not add an expiration dateMar 26, 2010 2:10:27 PM org.apache.catalina.filters.ExpiresFilter onBeforeWriteResponseBody FINE: Request "/docs/config/manager.html" with response status "200" content-type "text/html", no expiration configured
- 
- 
Nested Class SummaryNested Classes Modifier and Type Class Description protected static classExpiresFilter.DurationDuration composed of anExpiresFilter.Duration.amountand aExpiresFilter.Duration.unitprotected static classExpiresFilter.DurationUnitDuration unitprotected static classExpiresFilter.ExpiresConfigurationMain piece of configuration of the filter.protected static classExpiresFilter.StartingPointExpiration configuration starting point.classExpiresFilter.XHttpServletResponseWrapping extension of theHttpServletResponseto yrap the "Start Write Response Body" event.classExpiresFilter.XPrintWriterWrapping extension ofPrintWriterto trap the "Start Write Response Body" event.classExpiresFilter.XServletOutputStreamWrapping extension ofServletOutputStreamto trap the "Start Write Response Body" event.
 - 
Field Summary- 
Fields inherited from class org.apache.catalina.filters.FilterBasesm
 
- 
 - 
Constructor SummaryConstructors Constructor Description ExpiresFilter()
 - 
Method SummaryAll Methods Static Methods Instance Methods Concrete Methods Deprecated Methods Modifier and Type Method Description protected static int[]commaDelimitedListToIntArray(java.lang.String commaDelimitedInts)Convert a comma delimited list of numbers into anint[].protected static java.lang.String[]commaDelimitedListToStringArray(java.lang.String commaDelimitedStrings)Convert a given comma delimited list of strings into an array of Stringprotected static booleancontains(java.lang.String str, java.lang.String searchStr)voiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain)ThedoFiltermethod of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain.ExpiresFilter.ExpiresConfigurationgetDefaultExpiresConfiguration()java.lang.StringgetExcludedResponseStatusCodes()int[]getExcludedResponseStatusCodesAsInts()protected java.util.DategetExpirationDate(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response)Returns the expiration date of the givenExpiresFilter.XHttpServletResponseornullif no expiration date has been configured for the declared content type.protected java.util.DategetExpirationDate(ExpiresFilter.ExpiresConfiguration configuration, ExpiresFilter.XHttpServletResponse response)Returns the expiration date of the givenExpiresFilter.ExpiresConfiguration,HttpServletRequestandExpiresFilter.XHttpServletResponse.protected java.util.DategetExpirationDate(ExpiresFilter.XHttpServletResponse response)Deprecated.Will be removed in Tomcat 10.java.util.Map<java.lang.String,ExpiresFilter.ExpiresConfiguration>getExpiresConfigurationByContentType()protected LoggetLogger()voidinit(FilterConfig filterConfig)Iterates over the configuration parameters and either logs a warning, or throws an exception for any parameter that does not have a matching setter in this filter.protected static java.lang.StringintsToCommaDelimitedString(int[] ints)Convert an array of ints into a comma delimited stringprotected booleanisEligibleToExpirationHeaderGeneration(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response)protectedfor extension.protected static booleanisEmpty(java.lang.String str)protected static booleanisNotEmpty(java.lang.String str)voidonBeforeWriteResponseBody(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response)If no expiration header has been set by the servlet and an expiration has been defined in theExpiresFilterconfiguration, sets the 'Expires' header and the attribute 'max-age' of the 'Cache-Control' header.protected ExpiresFilter.ExpiresConfigurationparseExpiresConfiguration(java.lang.String inputLine)Parse configuration lines like 'access plus 1 month 15 days 2 hours' or 'modification 1 day 2 hours 5 seconds'voidsetDefaultExpiresConfiguration(ExpiresFilter.ExpiresConfiguration defaultExpiresConfiguration)voidsetExcludedResponseStatusCodes(int[] excludedResponseStatusCodes)voidsetExpiresConfigurationByContentType(java.util.Map<java.lang.String,ExpiresFilter.ExpiresConfiguration> expiresConfigurationByContentType)protected static booleanstartsWithIgnoreCase(java.lang.String string, java.lang.String prefix)protected static java.lang.StringsubstringBefore(java.lang.String str, java.lang.String separator)java.lang.StringtoString()- 
Methods inherited from class org.apache.catalina.filters.FilterBasedestroy, isConfigProblemFatal
 
- 
 
- 
- 
- 
Method Detail- 
commaDelimitedListToIntArrayprotected static int[] commaDelimitedListToIntArray(java.lang.String commaDelimitedInts) Convert a comma delimited list of numbers into anint[].- Parameters:
- commaDelimitedInts- can be- null
- Returns:
- never nullarray
 
 - 
commaDelimitedListToStringArrayprotected static java.lang.String[] commaDelimitedListToStringArray(java.lang.String commaDelimitedStrings) Convert a given comma delimited list of strings into an array of String- Parameters:
- commaDelimitedStrings- the string to be split
- Returns:
- array of patterns (non null)
 
 - 
containsprotected static boolean contains(java.lang.String str, java.lang.String searchStr)- Parameters:
- str- String that will be searched
- searchStr- The substring to search
- Returns:
- trueif the given- strcontains the given- searchStr.
 
 - 
intsToCommaDelimitedStringprotected static java.lang.String intsToCommaDelimitedString(int[] ints) Convert an array of ints into a comma delimited string- Parameters:
- ints- The int array
- Returns:
- a comma separated string
 
 - 
isEmptyprotected static boolean isEmpty(java.lang.String str) - Parameters:
- str- The String to check
- Returns:
- trueif the given- stris- nullor has a zero characters length.
 
 - 
isNotEmptyprotected static boolean isNotEmpty(java.lang.String str) - Parameters:
- str- The String to check
- Returns:
- trueif the given- strhas at least one character (can be a whitespace).
 
 - 
startsWithIgnoreCaseprotected static boolean startsWithIgnoreCase(java.lang.String string, java.lang.String prefix)- Parameters:
- string- can be- null
- prefix- can be- null
- Returns:
- trueif the given- stringstarts with the given- prefixignoring case.
 
 - 
substringBeforeprotected static java.lang.String substringBefore(java.lang.String str, java.lang.String separator)- Parameters:
- str- can be- null
- separator- can be- null
- Returns:
- the subset of the given strthat is before the first occurrence of the givenseparator. Returnnullif the givenstror the givenseparatoris null. Return and empty string if theseparatoris empty.
 
 - 
doFilterpublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException Description copied from interface:javax.servlet.FilterThedoFiltermethod of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed in to this method allows the Filter to pass on the request and response to the next entity in the chain.A typical implementation of this method would follow the following pattern:- 
 1. Examine the request
 2. Optionally wrap the request object with a custom implementation to filter content or headers for input filtering
 3. Optionally wrap the response object with a custom implementation to filter content or headers for output filtering
 4. a) Either invoke the next entity in the chain using the FilterChain object (chain.doFilter()),
 4. b) or not pass on the request/response pair to the next entity in the filter chain to block the request processing
 5. Directly set headers on the response after invocation of the next entity in the filter chain.- Parameters:
- request- The request to process
- response- The response associated with the request
- chain- Provides access to the next filter in the chain for this filter to pass the request and response to for further processing
- Throws:
- java.io.IOException- if an I/O error occurs during this filter's processing of the request
- ServletException- if the processing fails for any other reason
 
 - 
getDefaultExpiresConfigurationpublic ExpiresFilter.ExpiresConfiguration getDefaultExpiresConfiguration() 
 - 
getExcludedResponseStatusCodespublic java.lang.String getExcludedResponseStatusCodes() 
 - 
getExcludedResponseStatusCodesAsIntspublic int[] getExcludedResponseStatusCodesAsInts() 
 - 
getExpirationDate@Deprecated protected java.util.Date getExpirationDate(ExpiresFilter.XHttpServletResponse response) Deprecated.Will be removed in Tomcat 10. UsegetExpirationDate(HttpServletRequest, XHttpServletResponse)Returns the expiration date of the givenExpiresFilter.XHttpServletResponseornullif no expiration date has been configured for the declared content type.protectedfor extension.- Parameters:
- response- The wrapped HTTP response
- Returns:
- the expiration date
- See Also:
- ServletResponse.getContentType()
 
 - 
getExpirationDateprotected java.util.Date getExpirationDate(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response) Returns the expiration date of the givenExpiresFilter.XHttpServletResponseornullif no expiration date has been configured for the declared content type.protectedfor extension.- Parameters:
- request- The HTTP request
- response- The wrapped HTTP response
- Returns:
- the expiration date
- See Also:
- ServletResponse.getContentType()
 
 - 
getExpirationDateprotected java.util.Date getExpirationDate(ExpiresFilter.ExpiresConfiguration configuration, ExpiresFilter.XHttpServletResponse response) Returns the expiration date of the given ExpiresFilter.ExpiresConfiguration,HttpServletRequestandExpiresFilter.XHttpServletResponse.protectedfor extension.- Parameters:
- configuration- The parsed expires
- response- The Servlet response
- Returns:
- the expiration date
 
 - 
getExpiresConfigurationByContentTypepublic java.util.Map<java.lang.String,ExpiresFilter.ExpiresConfiguration> getExpiresConfigurationByContentType() 
 - 
getLoggerprotected Log getLogger() - Specified by:
- getLoggerin class- FilterBase
 
 - 
initpublic void init(FilterConfig filterConfig) throws ServletException Description copied from class:FilterBaseIterates over the configuration parameters and either logs a warning, or throws an exception for any parameter that does not have a matching setter in this filter.- Specified by:
- initin interface- Filter
- Overrides:
- initin class- FilterBase
- Parameters:
- filterConfig- The configuration information associated with the filter instance being initialised
- Throws:
- ServletException- if- FilterBase.isConfigProblemFatal()returns- trueand a configured parameter does not have a matching setter
 
 - 
isEligibleToExpirationHeaderGenerationprotected boolean isEligibleToExpirationHeaderGeneration(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response) protectedfor extension.- Parameters:
- request- The Servlet request
- response- The Servlet response
- Returns:
- trueif an expire header may be added
 
 - 
onBeforeWriteResponseBodypublic void onBeforeWriteResponseBody(HttpServletRequest request, ExpiresFilter.XHttpServletResponse response) If no expiration header has been set by the servlet and an expiration has been defined in the ExpiresFilterconfiguration, sets the 'Expires' header and the attribute 'max-age' of the 'Cache-Control' header.Must be called on the "Start Write Response Body" event. Invocations to Logger.debug(...)are guarded byLog.isDebugEnabled()becauseHttpServletRequest.getRequestURI()andServletResponse.getContentType()costsStringobjects instantiations (as of Tomcat 7).- Parameters:
- request- The Servlet request
- response- The Servlet response
 
 - 
parseExpiresConfigurationprotected ExpiresFilter.ExpiresConfiguration parseExpiresConfiguration(java.lang.String inputLine) Parse configuration lines like 'access plus 1 month 15 days 2 hours' or 'modification 1 day 2 hours 5 seconds'- Parameters:
- inputLine- the input
- Returns:
- the parsed expires
 
 - 
setDefaultExpiresConfigurationpublic void setDefaultExpiresConfiguration(ExpiresFilter.ExpiresConfiguration defaultExpiresConfiguration) 
 - 
setExcludedResponseStatusCodespublic void setExcludedResponseStatusCodes(int[] excludedResponseStatusCodes) 
 - 
setExpiresConfigurationByContentTypepublic void setExpiresConfigurationByContentType(java.util.Map<java.lang.String,ExpiresFilter.ExpiresConfiguration> expiresConfigurationByContentType) 
 - 
toStringpublic java.lang.String toString() - Overrides:
- toStringin class- java.lang.Object
 
 
- 
 
-