001    /*
002    * Licensed to the Apache Software Foundation (ASF) under one or more
003    * contributor license agreements.  See the NOTICE file distributed with
004    * this work for additional information regarding copyright ownership.
005    * The ASF licenses this file to You under the Apache License, Version 2.0
006    * (the "License"); you may not use this file except in compliance with
007    * the License.  You may obtain a copy of the License at
008    *
009    *     http://www.apache.org/licenses/LICENSE-2.0
010    *
011    * Unless required by applicable law or agreed to in writing, software
012    * distributed under the License is distributed on an "AS IS" BASIS,
013    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014    * See the License for the specific language governing permissions and
015    * limitations under the License.
016    */
017    
018    
019    package compressionFilters;
020    
021    import java.io.IOException;
022    import java.util.Enumeration;
023    
024    import javax.servlet.Filter;
025    import javax.servlet.FilterChain;
026    import javax.servlet.FilterConfig;
027    import javax.servlet.ServletException;
028    import javax.servlet.ServletRequest;
029    import javax.servlet.ServletResponse;
030    import javax.servlet.http.HttpServletRequest;
031    import javax.servlet.http.HttpServletResponse;
032    
033    
034    /**
035     * Implementation of <code>javax.servlet.Filter</code> used to compress
036     * the ServletResponse if it is bigger than a threshold.
037     *
038     * @author Amy Roh
039     * @author Dmitri Valdin
040     * @version $Revision: 664175 $, $Date: 2008-06-06 18:43:44 -0400 (Fri, 06 Jun 2008) $
041     */
042    
043    public class CompressionFilter implements Filter {
044    
045        /**
046         * The filter configuration object we are associated with.  If this value
047         * is null, this filter instance is not currently configured.
048         */
049        private FilterConfig config = null;
050    
051        /**
052         * Minimal reasonable threshold
053         */
054        private int minThreshold = 128;
055    
056    
057        /**
058         * The threshold number to compress
059         */
060        protected int compressionThreshold;
061    
062        /**
063         * Debug level for this filter
064         */
065        private int debug = 0;
066    
067        /**
068         * Place this filter into service.
069         *
070         * @param filterConfig The filter configuration object
071         */
072    
073        public void init(FilterConfig filterConfig) {
074    
075            config = filterConfig;
076            if (filterConfig != null) {
077                String value = filterConfig.getInitParameter("debug");
078                if (value != null) {
079                    debug = Integer.parseInt(value);
080                } else {
081                    debug = 0;
082                }
083                String str = filterConfig.getInitParameter("compressionThreshold");
084                if (str != null) {
085                    compressionThreshold = Integer.parseInt(str);
086                    if (compressionThreshold != 0 && compressionThreshold < minThreshold) {
087                        if (debug > 0) {
088                            System.out.println("compressionThreshold should be either 0 - no compression or >= " + minThreshold);
089                            System.out.println("compressionThreshold set to " + minThreshold);
090                        }
091                        compressionThreshold = minThreshold;
092                    }
093                } else {
094                    compressionThreshold = 0;
095                }
096    
097            } else {
098                compressionThreshold = 0;
099            }
100    
101        }
102    
103        /**
104         * Take this filter out of service.
105         */
106        public void destroy() {
107    
108            this.config = null;
109    
110        }
111    
112        /**
113         * The <code>doFilter</code> method of the Filter is called by the container
114         * each time a request/response pair is passed through the chain due
115         * to a client request for a resource at the end of the chain.
116         * The FilterChain passed into this method allows the Filter to pass on the
117         * request and response to the next entity in the chain.<p>
118         * This method first examines the request to check whether the client support
119         * compression. <br>
120         * It simply just pass the request and response if there is no support for
121         * compression.<br>
122         * If the compression support is available, it creates a
123         * CompressionServletResponseWrapper object which compresses the content and
124         * modifies the header if the content length is big enough.
125         * It then invokes the next entity in the chain using the FilterChain object
126         * (<code>chain.doFilter()</code>), <br>
127         */
128    
129        public void doFilter(ServletRequest request, ServletResponse response,
130                             FilterChain chain) throws IOException, ServletException {
131    
132            if (debug > 0) {
133                System.out.println("@doFilter");
134            }
135    
136            if (compressionThreshold == 0) {
137                if (debug > 0) {
138                    System.out.println("doFilter gets called, but compressionTreshold is set to 0 - no compression");
139                }
140                chain.doFilter(request, response);
141                return;
142            }
143    
144            boolean supportCompression = false;
145            if (request instanceof HttpServletRequest) {
146                if (debug > 1) {
147                    System.out.println("requestURI = " + ((HttpServletRequest) request).getRequestURI());
148                }
149    
150                // Are we allowed to compress ?
151                String s = (String) ((HttpServletRequest) request).getParameter("gzip");
152                if ("false".equals(s)) {
153                    if (debug > 0) {
154                        System.out.println("got parameter gzip=false --> don't compress, just chain filter");
155                    }
156                    chain.doFilter(request, response);
157                    return;
158                }
159    
160                Enumeration e =
161                        ((HttpServletRequest) request).getHeaders("Accept-Encoding");
162                while (e.hasMoreElements()) {
163                    String name = (String) e.nextElement();
164                    if (name.indexOf("gzip") != -1) {
165                        if (debug > 0) {
166                            System.out.println("supports compression");
167                        }
168                        supportCompression = true;
169                    } else {
170                        if (debug > 0) {
171                            System.out.println("no support for compresion");
172                        }
173                    }
174                }
175            }
176    
177            if (!supportCompression) {
178                if (debug > 0) {
179                    System.out.println("doFilter gets called wo compression");
180                }
181                chain.doFilter(request, response);
182                return;
183            } else {
184                if (response instanceof HttpServletResponse) {
185                    CompressionServletResponseWrapper wrappedResponse =
186                            new CompressionServletResponseWrapper((HttpServletResponse) response);
187                    wrappedResponse.setDebugLevel(debug);
188                    wrappedResponse.setCompressionThreshold(compressionThreshold);
189                    if (debug > 0) {
190                        System.out.println("doFilter gets called with compression");
191                    }
192                    try {
193                        chain.doFilter(request, wrappedResponse);
194                    } finally {
195                        wrappedResponse.finishResponse();
196                    }
197                    return;
198                }
199            }
200        }
201    
202        /**
203         * Set filter config
204         * This function is equivalent to init. Required by Weblogic 6.1
205         *
206         * @param filterConfig The filter configuration object
207         */
208        public void setFilterConfig(FilterConfig filterConfig) {
209            init(filterConfig);
210        }
211    
212        /**
213         * Return filter config
214         * Required by Weblogic 6.1
215         */
216        public FilterConfig getFilterConfig() {
217            return config;
218        }
219    
220    }
221