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 */ 016package org.opengion.hayabusa.filter; 017 018import org.opengion.fukurou.util.StringUtil; 019 020import java.io.IOException; 021import javax.servlet.ServletRequest; 022import javax.servlet.ServletResponse; 023import javax.servlet.Filter; 024import javax.servlet.FilterChain; 025import javax.servlet.FilterConfig; 026import javax.servlet.ServletException; 027import javax.servlet.http.HttpServletRequest; 028import 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 :フィルタするリモートIPアドレス。無指定時は、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 */ 069public 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}