001    /*
002     * Copyright (c) 2009 The openGion Project.
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,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.hayabusa.filter;
017    
018    import org.opengion.fukurou.util.StringUtil;
019    
020    import java.io.IOException;
021    import javax.servlet.ServletRequest;
022    import javax.servlet.ServletResponse;
023    import javax.servlet.Filter;
024    import javax.servlet.FilterChain;
025    import javax.servlet.FilterConfig;
026    import javax.servlet.ServletException;
027    import javax.servlet.http.HttpServletRequest;
028    import javax.servlet.http.HttpServletResponse;
029    
030    /**
031     * GZIPFilter は、Filter インターフェースを継承した ZIP圧縮クラスですã?
032     * web.xml で filter 設定することにより、Webアプリケーションへのアクセスを制御できますã?
033     * フィルタへのパラメータは、IPAddress と Debug を指定できますã?
034     * IPAddress は、リモートユーザーのIPアドレスをカンマ区åˆ?‚Šでè¤?•°æŒ?®šできますã?
035     * これは、カンマ区åˆ?‚Šでåˆ?§£した後ã?アクセスå…??アドレスの先é?æ–?­—å?のä¸??ã‚?
036     * 判定してã�?�¾すã?
037     *
038     * フィルターに対してweb.xml でパラメータを設定しますã?
039     * <ul>
040     *   <li>IPAddress :フィルタするリモーãƒ?Pアドレス。無æŒ?®š時は、ZIP圧縮しませんã€?/li>
041     *   <li>Debug     :フィルタ処ç�??詳細æƒ??をå?力しますã?(ãƒ?ƒ�ãƒ?‚°モーãƒ?</li>
042     * </ul>
043     *
044     *<pre>
045     * 【WEB-INF/web.xmlã€?
046     *     &lt;filter&gt;
047     *         &lt;filter-name&gt;GZIPFilter&lt;/filter-name&gt;
048     *         &lt;filter-class&gt;org.opengion.hayabusa.filter.GZIPFilter&lt;/filter-class&gt;
049     *         &lt;init-param&gt;
050     *             &lt;param-name&gt;ipAddress&lt;/param-name&gt;
051     *             &lt;param-value&gt;200.1&lt;/param-value&gt;
052     *         &lt;/init-param&gt;
053     *         &lt;init-param&gt;
054     *             &lt;param-name&gt;debug&lt;/param-name&gt;
055     *             &lt;param-value&gt;true&lt;/param-value&gt;
056     *         &lt;/init-param&gt;
057     *     &lt;/filter&gt;
058     *
059     *     &lt;filter-mapping&gt;
060     *         &lt;filter-name&gt;GZIPFilter&lt;/filter-name&gt;
061     *         &lt;url-pattern&gt;/jsp/*&lt;/url-pattern&gt;
062     *     &lt;/filter-mapping&gt;
063     *</pre>
064     *
065     * @version  4.0
066     * @author   Kazuhiko Hasegawa
067     * @since    JDK5.0,
068     */
069    public class GZIPFilter implements Filter {
070            private String[] ipaddrArray = null;
071            private boolean  isDebug         = false;
072    
073            /**
074             * Filter インターフェースの doFilter メソãƒ?ƒ‰
075             *
076             * Filter クラスの doFilter メソãƒ?ƒ‰はコンãƒ?ƒŠにより呼び出されã€?æœ?¾Œã?チェーンにおけã‚?
077             * リソースへのクライアントリクエストã?ためにã€?毎回リクエストã?レスポンスのペアがã?
078             * チェーンをé?して渡されますã? こã?メソãƒ?ƒ‰に渡されã‚?FilterChain を利用して、Filter ã�?
079             * リクエストやレスポンスをチェーンå†??次のエンãƒ?‚£ãƒ?‚£(Filter)にリクエストとレスポンスã‚?
080             * 渡す事ができますã?
081             * こã?メソãƒ?ƒ‰の典型的な実è£??以下ã?ようなパターンとなるでしょã�??
082             * 1. リクエストã?検査
083             * 2. オプションとして、å?力フィルタリング用にコンãƒ?ƒ³ãƒ?‚‚しくはヘッãƒ?‚’フィルタリング
084             *    するためにカスタãƒ?®Ÿè£?�«よるリクエストオブジェクトã?ラãƒ??
085             * 3. オプションとして、å?力フィルタリング用にコンãƒ?ƒ³ãƒ?‚‚しくはヘッãƒ?‚’フィルタリング
086             *    するためにカスタãƒ?®Ÿè£?�«よるレスポンスオブジェクトラãƒ??
087             * 4. 以下ã? a)、b) のどちらか
088             *    a) FileterChain オブジェクãƒ?chain.doFilter()) を利用してチェーンの次のエンãƒ?‚£ãƒ?‚£を呼び出ã�?
089             *    b) リクエストå?ç�?‚’止めるために、リクエストã?レスポンスのペアをフィルタチェーンの次の
090             *       エンãƒ?‚£ãƒ?‚£に渡さなã�?
091             * 5. フィルタチェーンの次のエンãƒ?‚£ãƒ?‚£の呼び出した後ã?直接レスポンスのヘッãƒ?‚’セãƒ?ƒˆ
092             *
093             * @param       req             ServletRequestオブジェクãƒ?
094             * @param       res             ServletResponseオブジェクãƒ?
095             * @param       chain   FilterChainオブジェクãƒ?
096             * @throws IOException 入出力エラーが発生したとã�?
097             * @throws ServletException サーブレãƒ?ƒˆ関係ã?エラーが発生したå?合ã?throw されますã?
098             */
099            public void doFilter( final ServletRequest req,
100                                                            final ServletResponse res,
101                                                            final FilterChain chain )
102                                                                    throws IOException, ServletException {
103                    if( req instanceof HttpServletRequest && res instanceof HttpServletResponse ) {
104                            HttpServletRequest request = (HttpServletRequest) req;
105                            HttpServletResponse response = (HttpServletResponse) res;
106                            if( isFiltering( request ) ) {
107                                    GZIPResponseWrapper wrappedResponse = new GZIPResponseWrapper(response);
108                                    chain.doFilter(req, wrappedResponse);
109                                    wrappedResponse.finishResponse();
110                                    return;
111                            }
112                    }
113                    chain.doFilter(req, res);
114            }
115    
116            /**
117             * フィルター処ç�??判å®?
118             *
119             * フィルター処ç�?‚’行うかどã�?�‹を判定しますã?
120             * ipAddress と前方ä¸??するリモートクライアントからã?アクセス時にã€?
121             * GZIPフィルタリング処ç�?‚’行いますã?
122             *
123             * @param       request HttpServletRequestオブジェクãƒ?
124             *
125             * @return      フィルター処ç�?‚’行うかどã�?�‹[true:フィルタ対象/false:非対象]
126             */
127            private boolean isFiltering( final HttpServletRequest request ) {
128    
129                    boolean isFilter = false;
130    
131                    String ae   = request.getHeader("accept-encoding");
132                    String uri  = request.getRequestURI();
133                    String adrs = request.getRemoteAddr();
134    
135                    // ブラウザã�?GZIP 対応かどã�?�‹
136                    if( ae != null && ae.indexOf("gzip") >= 0 ) {
137                            // リクエストが、jsp,js,css かどã�?�‹
138                            if( uri.endsWith(".jsp") || uri.endsWith(".js") || uri.endsWith(".css") ) {
139                                    // アドレスがã?æŒ?®šã?アドレス配å?で先é?ä¸??してã�?‚‹かどã�?�‹
140                                    for( int i=0; i<ipaddrArray.length; i++ ) {
141                                            if( adrs.startsWith( ipaddrArray[i] ) ) {
142                                                    isFilter = true;        // �?
143                                                    break;
144                                            }
145                                    }
146                            }
147                    }
148    
149                    if( isDebug ) {
150                            System.out.println("[Filtering " + isFilter + "]");
151                            System.out.println("  IP Address :"     + adrs );
152                            System.out.println("  Request URI:"     + uri );
153                    }
154    
155                    return isFilter;
156            }
157    
158            /**
159             * Filter インターフェースの init メソãƒ?ƒ‰ (何もしません)ã€?
160             *
161             * Web コンãƒ?ƒŠは、Filter をサービス状態にするために init メソãƒ?ƒ‰を呼び出しますã?
162             * Servlet コンãƒ?ƒŠは、Filter をインスタンス化したあとã€?ä¸?º¦ã�?�‘ init メソãƒ?ƒ‰を呼び出しますã?
163             * Filter がフィルタリングの仕事を依é?される前に、init メソãƒ?ƒ‰は正常に完äº?�—てなければã�?�‘ませんã€?
164             *
165             * init メソãƒ?ƒ‰が以下ã?ような状況になると、Web コンãƒ?ƒŠは Filter をサービス状態にできませんã€?
166             * 1. ServletException をスローした
167             * 2. Web コネクタで定義した時間å†?�«戻らなã�?
168             *
169             * @param       filterConfig    FilterConfigオブジェクãƒ?
170             */
171            public void init(final FilterConfig filterConfig) {
172                    ipaddrArray = StringUtil.csv2Array( filterConfig.getInitParameter("ipAddress") );
173                    isDebug = Boolean.valueOf( filterConfig.getInitParameter("debug") ).booleanValue();
174            }
175    
176            /**
177             * Filter インターフェースの destroy メソãƒ?ƒ‰ (何もしません)ã€?
178             *
179             * サービス状態を終えた事を Filter に伝えるために Web コンãƒ?ƒŠが呼び出しますã?
180             * Filter の doFilter メソãƒ?ƒ‰が終äº?�—たか、タイãƒ?‚¢ウトに達したå?てのスレãƒ?ƒ‰においてã€?
181             * こã?メソãƒ?ƒ‰をä¸?º¦ã�?�‘呼び出されますã? Web コンãƒ?ƒŠがこのメソãƒ?ƒ‰を呼び出した後ã?ã€?
182             * Filter のこã?インスタンスにおいて二度と doFilter メソãƒ?ƒ‰を呼び出す事ã?ありませんã€?
183             *
184             * こã?メソãƒ?ƒ‰は、フィルタに保持されてã�?‚‹(例えば、メモリ、ファイルハンドル、スレãƒ?ƒ‰)
185             * 様ã?なリソースを開放する機会を与えã€?あらã‚?‚‹永続æ?の状態が、メモリ上におけã‚?Filter
186             * の現在の状態と同期してã�?‚‹ように注意してくださいã€?
187             */
188            public void destroy() {
189                    // noop
190            }
191    }