View Javadoc

    1   /*
    2    * Copyright 2004-2009 the Seasar Foundation and the Others.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    13   * either express or implied. See the License for the specific language
    14   * governing permissions and limitations under the License.
    15   */
    16  package org.seasar.cubby.filter;
    17
    18  import java.io.IOException;
    19  import java.util.ArrayList;
    20  import java.util.List;
    21  import java.util.StringTokenizer;
    22  import java.util.regex.Matcher;
    23  import java.util.regex.Pattern;
    24
    25  import javax.servlet.Filter;
    26  import javax.servlet.FilterChain;
    27  import javax.servlet.FilterConfig;
    28  import javax.servlet.ServletException;
    29  import javax.servlet.ServletRequest;
    30  import javax.servlet.ServletResponse;
    31  import javax.servlet.http.HttpServletRequest;
    32  import javax.servlet.http.HttpServletResponse;
    33
    34  import org.seasar.cubby.internal.util.StringUtils;
    35
    36  /**
    37   * 適用された要求に対して、異常系の HTTP ステータスコードを返す {@link Filter} です。
    38   *
    39   * @author baba
    40   */
    41  public class SendErrorFilter implements Filter {
    42
    43  	/** 応答の HTTP ステータスコードの初期パラメータ名。 */
    44  	public static final String STATUS_CODE = "statusCode";
    45
    46  	/** 対象外とするパスの初期パラメータ名。 */
    47  	public static final String IGNORE_PATH_PATTERN = "ignorePathPattern";
    48
    49  	/** 応答の HTTP ステータスコード (デフォルトは 403 Forbidden)。 */
    50  	private int statusCode = HttpServletResponse.SC_FORBIDDEN;
    51
    52  	/** 対象外とするパスの正規表現パターンのリスト。 */
    53  	private final List<Pattern> ignorePathPatterns = new ArrayList<Pattern>();
    54
    55  	/**
    56  	 * このフィルタを初期化します。
    57  	 * <p>
    58  	 * <table>
    59  	 * <caption>使用可能な初期化パラメータ</caption> <thead>
    60  	 * <th>初期化パラメータ名</th>
    61  	 * <th>初期化パラメータの値</th>
    62  	 * <th>例</th>
    63  	 * </thead> <thead>
    64  	 * <tr>
    65  	 * <td>{@link #STATUS_CODE}</td>
    66  	 * <td>応答の HTTP ステータスコードを指定します。指定しなかった場合は
    67  	 * {@link HttpServletResponse#SC_FORBIDDEN} を返します。</td>
    68  	 * <td></td>
    69  	 * <tr>
    70  	 * <td>{@link #IGNORE_PATH_PATTERN}</td>
    71  	 * <td>対象外とするパスの正規表現をカンマ区切りで指定します。 filter-mapping の url-pattern
    72  	 * で指定する、このフィルタを適用する URL のうち、適用を除外したいパスを指定してください。</td>
    73  	 * <td>
    74  	 *
    75  	 * <pre>
    76  	 * &lt;filter&gt;
    77  	 *   &lt;filter-name&gt;sendErrorFilter&lt;/filter-name&gt;
    78  	 *   &lt;filter-class&gt;org.seasar.cubby.filter.SendErrorFilter&lt;/filter-class&gt;
    79  	 *   &lt;init-param&gt;
    80  	 *     &lt;param-name&gt;statusCode;&lt;/param-name&gt;
    81  	 *     &lt;param-value&gt;404&lt;param-name&gt;
    82  	 *   &lt;/init-param&gt;
    83  	 *   &lt;init-param&gt;
    84  	 *     &lt;param-name&gt;ignorePathPattern&lt;/param-name&gt;
    85  	 *     &lt;param-value&gt;/index.jsp&lt;param-name&gt;
    86  	 *   &lt;/init-param&gt;
    87  	 * &lt;/filter&gt;
    88  	 *
    89  	 * &lt;filter-mapping&gt;
    90  	 *   &lt;filter-name&gt;sendErrorFilter&lt;filter-name&gt;
    91  	 *   &lt;url-pattern&gt;*.jsp&lt;url-pattern&gt;
    92  	 *   &lt;dispatcher&gt;REQUEST&lt;/dispatcher&gt;
    93  	 * &lt;/filter-mapping&gt;
    94  	 * </pre>
    95  	 *
    96  	 * この例では、 /index.jsp を除く *.jsp に要求があった場合に HTTP ステータスコード 404 (Not Found)
    97  	 * を返します。</td>
    98  	 * </tr>
    99  	 * </thead>
    100 	 * </p>
    101 	 *
    102 	 * @param config
    103 	 *            Filter 設定のためのオブジェクト
    104 	 * @exception ServletException
    105 	 *                初期化処理で例外が発生した場合
    106 	 */
    107 	public void init(final FilterConfig config) throws ServletException {
    108 		final String statusCodeString = config.getInitParameter(STATUS_CODE);
    109 		if (statusCodeString != null) {
    110 			statusCode = Integer.parseInt(statusCodeString);
    111 		}
    112 		final String ignorePathPatternString = config
    113 				.getInitParameter(IGNORE_PATH_PATTERN);
    114 		if (!StringUtils.isEmpty(ignorePathPatternString)) {
    115
    116 			for (final StringTokenizer tokenizer = new StringTokenizer(
    117 					ignorePathPatternString, ","); tokenizer.hasMoreTokens();) {
    118 				final String token = tokenizer.nextToken();
    119 				final Pattern pattern = Pattern.compile(token);
    120 				ignorePathPatterns.add(pattern);
    121 			}
    122 		}
    123 	}
    124
    125 	/**
    126 	 * {@inheritDoc}
    127 	 */
    128 	public void destroy() {
    129 	}
    130
    131 	/**
    132 	 * {@link HttpServletResponse#sendError(int)} によって、異常系の HTTP ステータスコードを返します。
    133 	 *
    134 	 * @param req
    135 	 *            要求
    136 	 * @param res
    137 	 *            応答
    138 	 * @param chain
    139 	 *            フィルターチェーン
    140 	 * @throws IOException
    141 	 *             要求の転送や要求のチェーンがこの例外をスローする場合
    142 	 * @throws ServletException
    143 	 *             要求の転送や要求のチェーンがこの例外をスローする場合
    144 	 */
    145 	public void doFilter(final ServletRequest req, final ServletResponse res,
    146 			final FilterChain chain) throws IOException, ServletException {
    147
    148 		final HttpServletRequest request = (HttpServletRequest) req;
    149 		final HttpServletResponse response = (HttpServletResponse) res;
    150
    151 		if (isIgnore(request)) {
    152 			chain.doFilter(request, response);
    153 		} else {
    154 			response.sendError(statusCode);
    155 		}
    156 	}
    157
    158 	/**
    159 	 * 指定された要求がこのフィルタの対象外であるかを示します。
    160 	 *
    161 	 * @param request
    162 	 *            要求
    163 	 * @return 指定された要求がこのフィルタの対象外である場合は <code>true</code>、そうでない場合は
    164 	 *         <code>false</code>
    165 	 */
    166 	private boolean isIgnore(final HttpServletRequest request) {
    167 		final String servletPath = request.getServletPath();
    168 		for (final Pattern ignorePattern : ignorePathPatterns) {
    169 			final Matcher matcher = ignorePattern.matcher(servletPath);
    170 			if (matcher.matches()) {
    171 				return true;
    172 			}
    173 		}
    174 		return false;
    175 	}
    176
    177 }