1 /*
2 * Copyright 2004-2008 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.framework.util.StringUtil;
35
36 /**
37 * 適用されたリクエストに対して、異常系の HTTP ステータスコードを返す {@link Filter} です。
38 *
39 * @author baba
40 * @since 1.1.0
41 */
42 public class SendErrorFilter implements Filter {
43
44 /** レスポンスの HTTP ステータスコードの初期パラメータ名。 */
45 private static final String STATUS_CODE = "statusCode";
46
47 /** 対象外とするパスの初期パラメータ名。 */
48 private static final String IGNORE_PATH_PATTERN = "ignorePathPattern";
49
50 /** レスポンスの HTTP ステータスコード (デフォルトは 403 Forbidden)。 */
51 private int statusCode = HttpServletResponse.SC_FORBIDDEN;
52
53 /** 対象外とするパスの正規表現パターンのリスト。 */
54 private final List<Pattern> ignorePathPatterns = new ArrayList<Pattern>();
55
56 /**
57 * このフィルタを初期化します。
58 * <p>
59 * <table> <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 * <filter>
77 * <filter-name>sendErrorFilter</filter-name>
78 * <filter-class>org.seasar.cubby.filter.SendErrorFilter</filter-class>
79 * <init-param>
80 * <param-name>statusCode;</param-name>
81 * <param-value>404<param-name>
82 * </init-param>
83 * <init-param>
84 * <param-name>ignorePathPattern</param-name>
85 * <param-value>/index.jsp<param-name>
86 * </init-param>
87 * </filter>
88 *
89 * <filter-mapping>
90 * <filter-name>sendErrorFilter<filter-name>
91 * <url-pattern>*.jsp<url-pattern>
92 * <dispatcher>REQUEST</dispatcher>
93 * </filter-mapping>
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 (!StringUtil.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 public void doFilter(final ServletRequest req, final ServletResponse res,
135 final FilterChain chain) throws IOException, ServletException {
136
137 final HttpServletRequest request = (HttpServletRequest) req;
138 final HttpServletResponse response = (HttpServletResponse) res;
139
140 if (isIgnore(request)) {
141 chain.doFilter(request, response);
142 } else {
143 response.sendError(statusCode);
144 }
145 }
146
147 /**
148 * 指定されたリクエストがこのフィルタの対象外であるかを示します。
149 *
150 * @param request
151 * リクエスト
152 * @return 指定されたリクエストがこのフィルタの対象外である場合は <code>true</code>、そうでない場合は
153 * <code>false</code>
154 */
155 private boolean isIgnore(final HttpServletRequest request) {
156 for (final Pattern ignorePattern : ignorePathPatterns) {
157 final String servletPath = request.getServletPath();
158 final Matcher matcher = ignorePattern.matcher(servletPath);
159 if (matcher.matches()) {
160 return true;
161 }
162 }
163 return false;
164 }
165
166 }