View Javadoc
1   /*
2    * Copyright 2012-2017 CodeLibs Project 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.codelibs.fess.filter;
17  
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.HashMap;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.ConcurrentHashMap;
25  
26  import javax.servlet.Filter;
27  import javax.servlet.FilterChain;
28  import javax.servlet.FilterConfig;
29  import javax.servlet.ServletContext;
30  import javax.servlet.ServletException;
31  import javax.servlet.ServletRequest;
32  import javax.servlet.ServletResponse;
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpServletResponse;
35  
36  import org.apache.commons.codec.DecoderException;
37  import org.apache.commons.codec.net.URLCodec;
38  import org.codelibs.core.lang.StringUtil;
39  import org.lastaflute.web.servlet.filter.LastaPrepareFilter;
40  
41  public class EncodingFilter implements Filter {
42      public static final String ENCODING_MAP = "encodingRules";
43  
44      protected Map<String, String> encodingMap = new ConcurrentHashMap<>();
45  
46      protected String encoding;
47  
48      protected ServletContext servletContext;
49  
50      protected URLCodec urlCodec = new URLCodec();
51  
52      @Override
53      public void init(final FilterConfig config) throws ServletException {
54          servletContext = config.getServletContext();
55  
56          encoding = config.getInitParameter(LastaPrepareFilter.ENCODING_KEY);
57          if (encoding == null) {
58              encoding = LastaPrepareFilter.DEFAULT_ENCODING;
59          }
60  
61          // ex. sjis:Shift_JIS,eucjp:EUC-JP
62          final String value = config.getInitParameter(ENCODING_MAP);
63          if (StringUtil.isNotBlank(value)) {
64              final String[] encodingPairs = value.split(",");
65              for (final String pair : encodingPairs) {
66                  final String[] encInfos = pair.trim().split(":");
67                  if (encInfos.length == 2) {
68                      encodingMap.put("/" + encInfos[0] + "/", encInfos[1]);
69                  }
70              }
71          }
72      }
73  
74      @Override
75      public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException,
76              ServletException {
77          final HttpServletRequest req = (HttpServletRequest) request;
78          final String servletPath = req.getServletPath();
79          for (final Map.Entry<String, String> entry : encodingMap.entrySet()) {
80              final String path = entry.getKey();
81              if (servletPath.startsWith(path)) {
82                  req.setCharacterEncoding(entry.getValue());
83                  final StringBuilder locationBuf = new StringBuilder(1000);
84                  final String contextPath = servletContext.getContextPath();
85                  if (StringUtil.isNotBlank(contextPath) && !"/".equals(contextPath)) {
86                      locationBuf.append(contextPath);
87                  }
88                  locationBuf.append('/');
89                  locationBuf.append(servletPath.substring(path.length()));
90                  boolean append = false;
91                  final Map<String, String[]> parameterMap = new HashMap<>();
92                  parameterMap.putAll(req.getParameterMap());
93                  parameterMap.putAll(getParameterMapFromQueryString(req, entry.getValue()));
94                  for (final Map.Entry<String, String[]> paramEntry : parameterMap.entrySet()) {
95                      final String[] values = paramEntry.getValue();
96                      if (values == null) {
97                          continue;
98                      }
99                      final String key = paramEntry.getKey();
100                     for (final String value : values) {
101                         if (append) {
102                             locationBuf.append('&');
103                         } else {
104                             locationBuf.append('?');
105                             append = true;
106                         }
107                         locationBuf.append(urlCodec.encode(key, encoding));
108                         locationBuf.append('=');
109                         locationBuf.append(urlCodec.encode(value, encoding));
110                     }
111 
112                 }
113                 final HttpServletResponse res = (HttpServletResponse) response;
114                 res.sendRedirect(locationBuf.toString());
115                 return;
116             }
117         }
118 
119         chain.doFilter(request, response);
120     }
121 
122     protected Map<String, String[]> getParameterMapFromQueryString(final HttpServletRequest request, final String enc) throws IOException {
123         final String queryString = request.getQueryString();
124         if (StringUtil.isNotBlank(queryString)) {
125             return parseQueryString(queryString, enc);
126         } else {
127             return Collections.emptyMap();
128         }
129     }
130 
131     protected Map<String, String[]> parseQueryString(final String queryString, final String enc) throws IOException {
132         final Map<String, List<String>> paramListMap = new HashMap<>();
133         final String[] pairs = queryString.split("&");
134         try {
135             for (final String pair : pairs) {
136                 final int pos = pair.indexOf('=');
137                 if (pos >= 0) {
138                     final String key = urlCodec.decode(pair.substring(0, pos), enc);
139                     List<String> list = paramListMap.get(key);
140                     if (list == null) {
141                         list = new ArrayList<>();
142                         paramListMap.put(key, list);
143                     }
144                     if (pos + 1 < pair.length()) {
145                         list.add(urlCodec.decode(pair.substring(pos + 1), enc));
146                     } else {
147                         list.add(StringUtil.EMPTY);
148                     }
149                 } else {
150                     final String key = urlCodec.decode(pair, enc);
151                     List<String> list = paramListMap.get(key);
152                     if (list == null) {
153                         list = new ArrayList<>();
154                         paramListMap.put(key, list);
155                     }
156                     list.add(StringUtil.EMPTY);
157                 }
158             }
159         } catch (final DecoderException e) {
160             throw new IOException(e);
161         }
162 
163         final Map<String, String[]> paramMap = new HashMap<>(paramListMap.size());
164         for (final Map.Entry<String, List<String>> entry : paramListMap.entrySet()) {
165             final List<String> list = entry.getValue();
166             paramMap.put(entry.getKey(), list.toArray(new String[list.size()]));
167         }
168         return paramMap;
169     }
170 
171     @Override
172     public void destroy() {
173         // nothing
174     }
175 }