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