##### Coverage Report - org.seasar.cubby.filter.EncodingFilter

Classes in this File | Line Coverage | Branch Coverage | Complexity
EncodingFilter |
80% | 32/40
87% | 14/16
| 3.625;3.625
EncodingFilter$EncodingHttpServletRequestWrapper |
72% | 8/11
50% | 2/4
| 3.625;3.625

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.io.UnsupportedEncodingException;
20 |  |
     import java.nio.charset.Charset;
21 |  |
22 |  |
     import javax.servlet.Filter;
23 |  |
     import javax.servlet.FilterChain;
24 |  |
     import javax.servlet.FilterConfig;
25 |  |
     import javax.servlet.ServletException;
26 |  |
     import javax.servlet.ServletRequest;
27 |  |
     import javax.servlet.ServletResponse;
28 |  |
     import javax.servlet.http.HttpServletRequest;
29 |  |
     import javax.servlet.http.HttpServletRequestWrapper;
30 |  |
31 |  |
     /**
32 |  |
      * 要求のエンコーディングを設定するためのフィルタです。
33 |  |
      * <p>
34 |  |
      * 初期化パラメータ {@value #ENCODING}、{@value #FORCE_ENCODING} で要求の文字エンコーディングを指定します。
35 |  |
      * </p>
36 |  |
      * <p>
37 |  |
      * 初期化パラメータ {@value #URI_ENCODING}、{@value #URI_BYTES_ENCODING} で
38 |  |
      * {@link HttpServletRequest#getServletPath()}、
39 |  |
      * {@link HttpServletRequest#getPathInfo()} で取得できるパスのエンコーディングを指定します。
40 |  |
      * </p>
41 |  |
      * <p>
42 |  |
      * <table>
43 |  |
      * <thead>
44 |  |
      * <tr>
45 |  |
      * <th>param-name</th>
46 |  |
      * <th>param-value</th>
47 |  |
      * </tr>
48 |  |
      * <tbody>
49 |  |
      * <tr>
50 |  |
      * <td>{@value #ENCODING}</td>
51 |  |
      * <td>要求のエンコーディングを指定します。要求のエンコーディングが <code>null</code> か、
52 |  |
      * {@value #FORCE_ENCODING} に <code>true</code> が指定された場合はこのエンコーディングが要求に設定されます。</td>
53 |  |
      * </tr>
54 |  |
      * <tr>
55 |  |
      * <td>{@value #FORCE_ENCODING}</td>
56 |  |
      * <td><code>true</code> を指定した場合は、要求にエンコーディングが設定されていても {@value #ENCODING}
57 |  |
      * で上書きします。
58 |  |
      * </tr>
59 |  |
      * <tr>
60 |  |
      * <td>{@value #URI_ENCODING}</td>
61 |  |
      * <td>URI のエンコーディングを指定します。</td>
62 |  |
      * </tr>
63 |  |
      * <tr>
64 |  |
      * <td>{@value #URI_BYTES_ENCODING}</td>
65 |  |
      * <td>URI をバイト配列として取得する際のエンコーディングを指定します。</td>
66 |  |
      * </tr>
67 |  |
      * </tbody>
68 |  |
      * </table>
69 |  |
      * <caption>初期化パラメータ</caption>
70 |  |
      * </p>
71 |  |
      *
72 |  |
      * @author baba
73 |  |
      */
74 | 7 |
     public class EncodingFilter implements Filter {
75 |  |
76 | 1 |
             private static final String ALREADY_FILTERED_ATTRIBUTE_NAME = EncodingFilter.class
77 |  |
                             .getName()
78 |  |
                             + ".FILTERED";
79 |  |
80 |  |
             /** エンコーディングのキー。 */
81 |  |
             public static final String ENCODING = "encoding";
82 |  |
83 |  |
             /** 強制エンコーディング設定のキー。 */
84 |  |
             public static final String FORCE_ENCODING = "forceEncoding";
85 |  |
86 |  |
             /** URI エンコーディングのキー。 */
87 |  |
             public static final String URI_ENCODING = "URIEncoding";
88 |  |
89 |  |
             /** URI バイト列のエンコーディングのキー。 */
90 |  |
             public static final String URI_BYTES_ENCODING = "URIBytesEncoding";
91 |  |
92 |  |
             /** URI バイト列のエンコーディングのデフォルト値。 */
93 |  |
             public static final String DEFAULT_URI_BYTE_ENCODING = "ISO-8859-1";
94 |  |
95 |  |
             /** エンコーディング。 */
96 |  |
             private String encoding;
97 |  |
98 |  |
             /** 強制エンコーディング設定。 */
99 | 7 |
             private boolean forceEncoding = false;
100 |  |
101 |  |
             /** URI エンコーディング。 */
102 |  |
             private String uriEncoding;
103 |  |
104 |  |
             /** URI バイト列のエンコーディング。 */
105 |  |
             private String uriBytesEncoding;
106 |  |
107 |  |
             /**
108 |  |
              * {@inheritDoc}
109 |  |
              */
110 |  |
             public void init(final FilterConfig config) throws ServletException {
111 | 7 |
                     encoding = config.getInitParameter(ENCODING);
112 |  |
                     try {
113 | 7 |
                             validateEncoding(encoding);
114 | 0 |
                     } catch (final UnsupportedEncodingException e) {
115 | 0 |
                             throw new ServletException(e);
116 | 7 |
                     }
117 |  |
118 | 7 |
                     final String forceEncodingString = config
119 |  |
                                     .getInitParameter(FORCE_ENCODING);
120 | 7 |
                     if (forceEncodingString != null) {
121 | 5 |
                             forceEncoding = Boolean.parseBoolean(forceEncodingString);
122 |  |
                     }
123 |  |
124 | 7 |
                     uriEncoding = config.getInitParameter(URI_ENCODING);
125 |  |
                     try {
126 | 7 |
                             validateEncoding(uriEncoding);
127 | 0 |
                     } catch (final UnsupportedEncodingException e) {
128 | 0 |
                             throw new ServletException(e);
129 | 7 |
                     }
130 |  |
131 | 7 |
                     uriBytesEncoding = config.getInitParameter(URI_BYTES_ENCODING);
132 | 7 |
                     if (uriBytesEncoding == null) {
133 | 6 |
                             uriBytesEncoding = DEFAULT_URI_BYTE_ENCODING;
134 |  |
                     }
135 |  |
                     try {
136 | 7 |
                             validateEncoding(uriBytesEncoding);
137 | 0 |
                     } catch (final UnsupportedEncodingException e) {
138 | 0 |
                             throw new ServletException(e);
139 | 7 |
                     }
140 | 7 |
             }
141 |  |
142 |  |
             /**
143 |  |
              * 指定されたエンコーディングがサポートされているか検査します。
144 |  |
              *
145 |  |
              * @param encoding
146 |  |
              *            エンコーディング
147 |  |
              * @throws UnsupportedEncodingException
148 |  |
              *             指定されたエンコーディングがサポートされていない場合
149 |  |
              */
150 |  |
             private void validateEncoding(final String encoding)
151 |  |
                             throws UnsupportedEncodingException {
152 | 21 |
                     if (encoding != null && !Charset.isSupported(encoding)) {
153 | 0 |
                             throw new UnsupportedEncodingException(encoding);
154 |  |
                     }
155 | 21 |
             }
156 |  |
157 |  |
             /**
158 |  |
              * {@inheritDoc}
159 |  |
              */
160 |  |
             public void destroy() {
161 | 7 |
             }
162 |  |
163 |  |
             /**
164 |  |
              * {@inheritDoc}
165 |  |
              */
166 |  |
             public void doFilter(final ServletRequest request,
167 |  |
                             final ServletResponse response, final FilterChain chain)
168 |  |
                             throws IOException, ServletException {
169 | 7 |
                     if (request.getAttribute(ALREADY_FILTERED_ATTRIBUTE_NAME) == null) {
170 | 7 |
                             request.setAttribute(ALREADY_FILTERED_ATTRIBUTE_NAME, Boolean.TRUE);
171 | 7 |
                             if (request.getCharacterEncoding() == null || forceEncoding) {
172 | 5 |
                                     request.setCharacterEncoding(encoding);
173 |  |
                             }
174 | 7 |
                             if (uriEncoding == null) {
175 | 5 |
                                     chain.doFilter(request, response);
176 |  |
                             } else {
177 | 2 |
                                     final ServletRequest wrapper = new EncodingHttpServletRequestWrapper(
178 |  |
                                                     (HttpServletRequest) request, uriEncoding,
179 |  |
                                                     uriBytesEncoding);
180 | 2 |
                                     chain.doFilter(wrapper, response);
181 |  |
                             }
182 | 7 |
                             request.removeAttribute(ALREADY_FILTERED_ATTRIBUTE_NAME);
183 |  |
                     } else {
184 | 0 |
                             chain.doFilter(request, response);
185 |  |
                     }
186 | 7 |
             }
187 |  |
188 |  |
             /**
189 |  |
              * 適切なエンコーディングで処理するための {@link HttpServletRequestWrapper} です。
190 |  |
              *
191 |  |
              * @author baba
192 |  |
              */
193 | 7 |
             private static class EncodingHttpServletRequestWrapper extends
194 |  |
                             HttpServletRequestWrapper {
195 |  |
196 |  |
                     /** URI エンコーディング。 */
197 |  |
                     private final String uriEncoding;
198 |  |
199 |  |
                     /** URI バイト列のエンコーディング。 */
200 |  |
                     private final String uriBytesEncoding;
201 |  |
202 |  |
                     /**
203 |  |
                      * 指定された要求をラップします。
204 |  |
                      *
205 |  |
                      * @param request
206 |  |
                      *            要求
207 |  |
                      * @param uriEncoding
208 |  |
                      *            URI エンコーディング
209 |  |
                      * @param uriBytesEncoding
210 |  |
                      *            URI バイト列のエンコーディング。
211 |  |
                      * @throws IOException
212 |  |
                      *             スーパクラスのコンストラクタで例外が発生した場合
213 |  |
                      */
214 |  |
                     public EncodingHttpServletRequestWrapper(
215 |  |
                                     final HttpServletRequest request, final String uriEncoding,
216 |  |
                                     final String uriBytesEncoding) throws IOException {
217 | 2 |
                             super(request);
218 | 2 |
                             this.uriEncoding = uriEncoding;
219 | 2 |
                             this.uriBytesEncoding = uriBytesEncoding;
220 | 2 |
                     }
221 |  |
222 |  |
                     @Override
223 |  |
                     public String getServletPath() {
224 | 2 |
                             return rebuild(super.getServletPath(), uriEncoding,
225 |  |
                                             uriBytesEncoding);
226 |  |
                     }
227 |  |
228 |  |
                     @Override
229 |  |
                     public String getPathInfo() {
230 | 2 |
                             return rebuild(super.getPathInfo(), uriEncoding, uriBytesEncoding);
231 |  |
                     }
232 |  |
233 |  |
                     /**
234 |  |
                      * 指定された文字列を一度 <code>bytesEncoding</code> でバイト配列に戻し、
235 |  |
                      * <code>encoding</code> で文字列を再構築します。
236 |  |
                      *
237 |  |
                      * @param str
238 |  |
                      *            文字列
239 |  |
                      * @param encoding
240 |  |
                      *            エンコーディング
241 |  |
                      * @param bytesEncoding
242 |  |
                      *            バイト配列に戻す時のエンコーディング
243 |  |
                      * @return 再構築された文字列
244 |  |
                      */
245 |  |
                     private String rebuild(final String str, final String encoding,
246 |  |
                                     final String bytesEncoding) {
247 | 4 |
                             if (str == null || encoding == null) {
248 | 0 |
                                     return str;
249 |  |
                             }
250 |  |
                             try {
251 | 4 |
                                     return new String(str.getBytes(bytesEncoding), encoding);
252 | 0 |
                             } catch (final UnsupportedEncodingException e) {
253 | 0 |
                                     throw new IllegalStateException(e);
254 |  |
                             }
255 |  |
                     }
256 |  |
257 |  |
             }
258 |  |
259 |  |
     }