Skip to content

Instantly share code, notes, and snippets.

@leodutra
Last active November 8, 2015 14:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leodutra/a8a03ca76a9a96be018d to your computer and use it in GitHub Desktop.
Save leodutra/a8a03ca76a9a96be018d to your computer and use it in GitHub Desktop.
Filtro para controle de cache de resources para Servlets 2.3+ (Websphere 5+)
/**/
package com.github.leodutra.filters;
import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Cache control filter for common Java web applications.<br>
* When web.xml init parameters are not defined, uses the internal default definitions.
*
* @author leonardodutra (https://github.com/LeoDutra)
*/
public final class CacheControlFilter implements Filter {
private static final long DEFAULT_MAX_AGE_SECONDS = 60 * 60 * 3; // 3 horas
private static final String[] DEFAULT_CACHED_EXTENSIONS = new String[] { ".js", ".css", ".png", ".jpg", ".svg",
".ico", ".webp", ".eot", ".woff", ".woff2", ".ttf", ".gif" };
private static final String[] DEFAULT_IGNORED_EXTENSIONS = new String[] { ".do", ".jsp", ".action", ".ext",
".html", ".xhtml", ".ajax" };
private static final String EXTENSIONS_SPLIT_PATTERN = ",\\s?";
private static final String CACHE_CONTROL_NO_CACHE = "private, no-cache, must-revalidate, max-age=15, proxy-revalidate, s-maxage=15"; // 15 sec against multicast
private static final String PRAGMA_NO_CACHE = "no-cache";
private static final String BLANK_STR = "";
private static final String HEADER_EXPIRES = "Expires";
private static final String HEADER_PRAGMA = "Pragma";
private static final String HEADER_CACHE_CONTROL = "Cache-Control";
private static final String HTTP_1_1_PROTOCOL = "HTTP/1.1";
private long maxAgeSeconds;
private long maxAgeMillis;
private String timedCacheControl;
private String[] cachedExtensions;
private String[] ignoredExtensions;
/*
Useful Cache-Control response headers include: (source: https://www.mnot.net/cache_docs/)
- max-age=[seconds] — specifies the maximum amount of time that a representation will be considered fresh. Similar to Expires, this directive is relative to the time of the request, rather than absolute. [seconds] is the number of seconds from the time of the request you wish the representation to be fresh for.
- s-maxage=[seconds] — similar to max-age, except that it only applies to shared (e.g., proxy) caches.
- public — marks authenticated responses as cacheable; normally, if HTTP authentication is required, responses are automatically private.
- private — allows caches that are specific to one user (e.g., in a browser) to store the response; shared caches (e.g., in a proxy) may not.
- no-cache — forces caches to submit the request to the origin server for validation before releasing a cached copy, every time. This is useful to assure that authentication is respected (in combination with public), or to maintain rigid freshness, without sacrificing all of the benefits of caching.
- no-store — instructs caches not to keep a copy of the representation under any conditions.
- must-revalidate — tells caches that they must obey any freshness information you give them about a representation. HTTP allows caches to serve stale representations under special conditions; by specifying this header, you’re telling the cache that you want it to strictly follow your rules.
- proxy-revalidate — similar to must-revalidate, except that it only applies to proxy caches.
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) request;
final HttpServletResponse httpResponse = (HttpServletResponse) response;
final String uri = httpRequest.getRequestURI();
boolean hasIgnoredExtension = false;
for (final String ignored : ignoredExtensions) {
if (uri.endsWith(ignored)) {
hasIgnoredExtension = true;
break;
}
}
if (!hasIgnoredExtension) {
boolean hasCacheableExtension = false;
for (final String extension : cachedExtensions) {
if (uri.endsWith(extension)) {
hasCacheableExtension = true;
break;
}
}
if (hasCacheableExtension) {
httpResponse.setDateHeader(HEADER_EXPIRES, new Date().getTime() + maxAgeMillis);
if (request.getProtocol().equals(HTTP_1_1_PROTOCOL)) {
httpResponse.setHeader(HEADER_CACHE_CONTROL, timedCacheControl);
}
// DO NOT USE PRAGMA=CACHE
} else {
httpResponse.setDateHeader(HEADER_EXPIRES, -1);
if (request.getProtocol().equals(HTTP_1_1_PROTOCOL)) {
httpResponse.setHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
} else {
httpResponse.setHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
}
}
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
final String initMaxAgeSeconds = filterConfig.getInitParameter("max-age-seconds");
final String initCachedExtensions = filterConfig.getInitParameter("cached-extensions");
final String initIgnoredExtensions = filterConfig.getInitParameter("ignored-extensions");
if (isNotBlank(initMaxAgeSeconds)) {
maxAgeSeconds = Long.parseLong(initMaxAgeSeconds.trim(), 10);
} else {
maxAgeSeconds = DEFAULT_MAX_AGE_SECONDS;
}
if (isNotBlank(initCachedExtensions)) {
cachedExtensions = initCachedExtensions.trim().split(EXTENSIONS_SPLIT_PATTERN);
} else {
cachedExtensions = DEFAULT_CACHED_EXTENSIONS;
}
if (isNotBlank(initIgnoredExtensions)) {
ignoredExtensions = initIgnoredExtensions.trim().split(EXTENSIONS_SPLIT_PATTERN);
} else {
ignoredExtensions = DEFAULT_IGNORED_EXTENSIONS;
}
maxAgeMillis = maxAgeSeconds * 1000;
timedCacheControl = new StringBuilder().append("private, must-revalidate, max-age=").append(maxAgeSeconds)
.append(", proxy-revalidate, s-maxage=").append(maxAgeSeconds).toString(); // https://gist.github.com/LeoDutra/f417cdfd9aaf361e3c6b
}
private static final boolean isNotBlank(String str) {
return str != null && !BLANK_STR.equals(str);
}
@Override
public void destroy() {
}
}
<filter>
<description>Cache control filter for common Java web applications. When init parameters are not defined, defaults to internal definitions.</description>
<display-name>CacheControlFilter</display-name>
<filter-name>CacheControlFilter</filter-name>
<filter-class>com.github.leodutra.filters.CacheControlFilter</filter-class>
<init-param>
<param-name>max-age-seconds</param-name>
<param-value>10800</param-value>
</init-param>
<init-param>
<param-name>cached-extensions</param-name>
<param-value>.js, .css, .png, .jpg, .svg, .ico, .webp, .eot, .woff, .woff2, .ttf, .gif</param-value>
</init-param>
<init-param>
<param-name>ignored-extensions</param-name>
<param-value>.do, .jsp, .action, .ext, .html, .xhtml, .ajax</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CacheControlFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment