Last active
November 8, 2015 14:13
-
-
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+)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**/ | |
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() { | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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