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 * <filter>
047 * <filter-name>GZIPFilter</filter-name>
048 * <filter-class>org.opengion.hayabusa.filter.GZIPFilter</filter-class>
049 * <init-param>
050 * <param-name>ipAddress</param-name>
051 * <param-value>200.1</param-value>
052 * </init-param>
053 * <init-param>
054 * <param-name>debug</param-name>
055 * <param-value>true</param-value>
056 * </init-param>
057 * </filter>
058 *
059 * <filter-mapping>
060 * <filter-name>GZIPFilter</filter-name>
061 * <url-pattern>/jsp/*</url-pattern>
062 * </filter-mapping>
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 }