1 package de.halbekunst.juplo.cachecontrol;
3 import de.halbekunst.juplo.cachecontrol.CacheControl.CacheMethodHandle;
4 import java.io.IOException;
5 import java.io.OutputStream;
6 import java.io.PrintWriter;
7 import java.util.Enumeration;
9 import java.util.zip.GZIPOutputStream;
10 import javax.servlet.Filter;
11 import javax.servlet.FilterChain;
12 import javax.servlet.FilterConfig;
13 import javax.servlet.ServletException;
14 import javax.servlet.ServletOutputStream;
15 import javax.servlet.ServletRequest;
16 import javax.servlet.ServletResponse;
17 import javax.servlet.http.HttpServletRequest;
18 import javax.servlet.http.HttpServletResponse;
19 import javax.servlet.http.HttpServletResponseWrapper;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22 import org.springframework.beans.factory.annotation.Autowired;
23 import org.springframework.beans.factory.annotation.Configurable;
32 public class AcceleratorFilter implements Filter {
33 private final static Logger log = LoggerFactory.getLogger(AcceleratorFilter.class);
35 public final static String REQUEST_URI_ATTRIBUTE = "javax.servlet.include.request_uri";
38 @Autowired CacheControl cacheControl;
39 @Autowired(required=true) Integer buffer;
40 @Autowired(required=true) String eTag;
41 @Autowired(required=true) Boolean weak;
42 @Autowired(required=true) Long lastModified;
43 @Autowired(required=true) Integer cacheSeconds;
47 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
48 if (!(request instanceof HttpServletRequest)) {
49 log.error("AcceleratorFilter can only handle HTTP-requests");
50 chain.doFilter(request, response);
54 /** Prüfen, ob es sich um eine Anfrage für einen JSP-Include handelt */
55 if (request.getAttribute(REQUEST_URI_ATTRIBUTE) != null) {
56 log.debug("Includes cannot be accelerated");
57 chain.doFilter(request, response);
61 AccelerationWrapper wrapper = new AccelerationWrapper((HttpServletRequest)request, (HttpServletResponse)response);
62 cacheControl.init(wrapper);
63 chain.doFilter(request, wrapper);
68 public void init(FilterConfig filterConfig) throws ServletException {
72 public void destroy() {
76 class AccelerationWrapper extends HttpServletResponseWrapper implements CacheMethodHandle {
78 private final HttpServletRequest request;
79 private final HttpServletResponse response;
81 private boolean zipped;
82 private GZIPServletOutputStream out;
90 AccelerationWrapper(HttpServletRequest request, HttpServletResponse response) throws IOException {
93 this.request = request;
94 this.response = response;
96 now = System.currentTimeMillis();
97 buffer = AcceleratorFilter.this.buffer;
98 status = HttpServletResponse.SC_OK;
101 Enumeration values = request.getHeaders(HeaderNames.HEADER_ACCEPT_ENCODING);
102 while (values.hasMoreElements()) {
103 String value = (String) values.nextElement();
104 if (value.indexOf("gzip") != -1) {
106 response.addHeader(HeaderNames.HEADER_CONTENT_ENCODING, "gzip");
113 public void finish() throws IOException {
114 if (zipped && out != null)
120 public void setStatus(int sc) {
121 response.setStatus(sc);
124 cacheControl.decorate(request, response, this);
126 catch (Exception e) {
127 log.error("Error while decorating response", e);
132 public void setStatus(int sc, String sm) {
133 response.setStatus(sc,sm);
136 cacheControl.decorate(request, response, this);
138 catch (Exception e) {
139 log.error("Error while decorating response", e);
144 public ServletOutputStream getOutputStream() throws IOException {
146 out = new GZIPServletOutputStream(response.getOutputStream(), zipped);
151 public PrintWriter getWriter() throws IOException {
152 return new PrintWriter(getOutputStream());
156 public void setContentType(String type) {
158 response.setContentType(type);
162 public void setBufferSize(int size) {
164 response.setBufferSize(size);
168 public int getBufferSize() {
173 public void flushBuffer() throws IOException {
174 cacheControl.decorate(request, response, this);
175 if (zipped && out != null) {
178 response.flushBuffer();
182 public void resetBuffer() {
183 response.resetBuffer();
187 public boolean isCommitted() {
188 return response.isCommitted();
192 public void reset() {
199 public long getTimestamp() {
204 public int accepts(HttpServletRequest request) {
209 public int getCacheSeconds(HttpServletRequest request) {
214 public long getLastModified(HttpServletRequest request) {
219 public String getETag(HttpServletRequest request) {
224 public boolean isETagWeak() {
229 public void cacheControl(HttpServletRequest request, Map<String, String> cacheControlMap) {
233 class GZIPServletOutputStream extends ServletOutputStream {
235 private final OutputStream out;
236 private final GZIPOutputStream zout;
237 private boolean untouched = true;
239 public GZIPServletOutputStream(ServletOutputStream out, boolean zipped) throws IOException {
241 this.zout = new GZIPOutputStream(out, buffer);
242 this.out = this.zout;
252 public void write(int i) throws IOException {
256 AcceleratorFilter.this.cacheControl.decorate(AccelerationWrapper.this.request, response, buffer);
258 catch (Exception e) {
259 log.error("Error while guessing Cache-Header's", e);
260 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);