1 package com.atlassian.gzipfilter;
2
3 import com.atlassian.gzipfilter.integration.GzipFilterIntegration;
4 import com.atlassian.gzipfilter.selector.DefaultGzipCompatibilitySelectorFactory;
5 import com.atlassian.gzipfilter.selector.GzipCompatibilitySelector;
6 import com.atlassian.gzipfilter.selector.GzipCompatibilitySelectorFactory;
7
8 import org.apache.log4j.Logger;
9
10 import javax.servlet.*;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13 import java.io.IOException;
14
15
16
17
18
19
20
21
22
23
24
25 public class GzipFilter extends AbstractFilter
26 {
27 private static final Logger log = Logger.getLogger(GzipFilter.class);
28 private static final String ALREADY_FILTERED = GzipFilter.class.getName() + "_already_filtered";
29
30 private static final GzipCompatibilitySelector NO_GZIP_SELECTOR = new NoGzipCompatibilitySelector();
31
32 private final DefaultGzipCompatibilitySelectorFactory factory = new DefaultGzipCompatibilitySelectorFactory();
33 private final GzipFilterIntegration integration;
34 private FilterConfig filterConfig;
35
36 public GzipFilter(GzipFilterIntegration integration)
37 {
38 this.integration = integration;
39 }
40
41 public void init(FilterConfig filterConfig) throws ServletException
42 {
43 this.filterConfig = filterConfig;
44 super.init(filterConfig);
45 }
46
47 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
48 {
49 if (req.getAttribute(ALREADY_FILTERED) == null)
50 {
51 doFilterInternal(req, res, chain);
52 }
53 else
54 {
55 chain.doFilter(req, res);
56 }
57 }
58
59 private void doFilterInternal(ServletRequest req, ServletResponse res, FilterChain chain)
60 throws IOException, ServletException
61 {
62 req.setAttribute(ALREADY_FILTERED, Boolean.TRUE);
63
64 if (req instanceof HttpServletRequest && integration.useGzip() && isTopLevelRequest(req))
65 {
66 HttpServletRequest request = (HttpServletRequest) req;
67 HttpServletResponse response = (HttpServletResponse) res;
68 GzipCompatibilitySelector selector = getCompatibilitySelector(request);
69 if (selector.shouldGzip())
70 {
71 if (log.isDebugEnabled())
72 log.debug("GZIP supported, compressing.");
73
74 SelectingResponseWrapper wrappedResponse = new SelectingResponseWrapper(response, selector, integration.getResponseEncoding(request));
75 chain.doFilter(req, wrappedResponse);
76 wrappedResponse.finishResponse();
77 return;
78 }
79 }
80
81 chain.doFilter(req, res);
82 }
83
84 private GzipCompatibilitySelector getCompatibilitySelector(HttpServletRequest request)
85 {
86 String acceptEncodingHeader = request.getHeader("accept-encoding");
87 if (acceptEncodingHeader == null || acceptEncodingHeader.indexOf("gzip") == -1)
88 return NO_GZIP_SELECTOR;
89
90 return getFactory().getSelector(filterConfig, request);
91 }
92
93 protected GzipCompatibilitySelectorFactory getFactory()
94 {
95 return factory;
96 }
97
98 private boolean isTopLevelRequest(ServletRequest request)
99 {
100 return request.getAttribute("javax.servlet.include.servlet_path") == null;
101 }
102
103
104
105
106 private static final class NoGzipCompatibilitySelector implements GzipCompatibilitySelector
107 {
108 public boolean shouldGzip(String contentType)
109 {
110 return false;
111 }
112
113 public boolean shouldGzip()
114 {
115 return false;
116 }
117 }
118 }