001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2006
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * Felix Gnass [fgnass at neteye dot de]
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.common.web.filter;
025:
026: import java.io.IOException;
027: import java.util.regex.Pattern;
028:
029: import javax.servlet.FilterChain;
030: import javax.servlet.ServletException;
031: import javax.servlet.http.HttpServletRequest;
032: import javax.servlet.http.HttpServletResponse;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.commons.logging.LogFactory;
036: import org.riotfamily.common.util.FormatUtils;
037: import org.riotfamily.common.web.util.ServletUtils;
038:
039: /**
040: * Servlet filter that sets a far future Expires header for request URLs that
041: * contain a timestamp. URLs are considered as 'stamped' if they match the
042: * configured pattern.
043: * <p>
044: * The default pattern is <code>(.*\\/\\d{14}/.+)|(.+\\?[0-9]+$)</code>, this
045: * matches URLs created by the DefaultFileStore and URLs printed via the
046: * <code>common.resource()</code> FreeMarker function.
047: * </p>
048: * @author Felix Gnass [fgnass at neteye dot de]
049: * @since 6.4
050: */
051: public class CacheStampedResourcesFilter extends HttpFilterBean {
052:
053: private static Log log = LogFactory
054: .getLog(CacheStampedResourcesFilter.class);
055:
056: public static final String DEFAULT_EXPIRATION = "10Y";
057:
058: public static final Pattern DEFAULT_PATTERN = Pattern
059: .compile("(^.*/\\d{14}/.+$)|(^.+[?&][0-9]+$)");
060:
061: private static final String EXPIRES_HEADER = "Expires";
062:
063: private Pattern stampPattern = DEFAULT_PATTERN;
064:
065: private String expiresAfter = DEFAULT_EXPIRATION;
066:
067: private long expires;
068:
069: public void setExpiresAfter(String expiresAfter) {
070: this .expiresAfter = expiresAfter;
071: }
072:
073: public void setStampPattern(Pattern stampPattern) {
074: this .stampPattern = stampPattern;
075: }
076:
077: protected void initFilterBean() throws ServletException {
078: expires = System.currentTimeMillis()
079: + FormatUtils.parseMillis(expiresAfter);
080: }
081:
082: protected void filter(HttpServletRequest request,
083: HttpServletResponse response, FilterChain filterChain)
084: throws ServletException, IOException {
085:
086: if (isStamped(request)) {
087: if (log.isDebugEnabled()) {
088: log.debug("Setting Expires header for "
089: + request.getRequestURI());
090: }
091: response.setDateHeader(EXPIRES_HEADER, expires);
092: }
093: filterChain.doFilter(request, response);
094: }
095:
096: protected boolean isStamped(HttpServletRequest request) {
097: String url = ServletUtils.getRequestUrlWithQueryString(request);
098: return stampPattern.matcher(url).matches();
099: }
100: }
|