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