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