001
014
015 package com.liferay.portal.kernel.servlet.filters.invoker;
016
017 import com.liferay.portal.kernel.cache.key.CacheKeyGenerator;
018 import com.liferay.portal.kernel.cache.key.CacheKeyGeneratorUtil;
019 import com.liferay.portal.kernel.concurrent.ConcurrentLFUCache;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.servlet.HttpOnlyCookieServletResponse;
023 import com.liferay.portal.kernel.servlet.NonSerializableObjectRequestWrapper;
024 import com.liferay.portal.kernel.servlet.SanitizedServletResponse;
025 import com.liferay.portal.kernel.util.BasePortalLifecycle;
026 import com.liferay.portal.kernel.util.GetterUtil;
027 import com.liferay.portal.kernel.util.HttpUtil;
028 import com.liferay.portal.kernel.util.JavaConstants;
029 import com.liferay.portal.kernel.util.PropsKeys;
030 import com.liferay.portal.kernel.util.PropsUtil;
031 import com.liferay.portal.kernel.util.ServerDetector;
032 import com.liferay.portal.kernel.util.StringBundler;
033 import com.liferay.portal.kernel.util.StringPool;
034 import com.liferay.portal.kernel.util.StringUtil;
035 import com.liferay.portal.kernel.util.Validator;
036 import com.liferay.portal.kernel.util.WebKeys;
037
038 import java.io.IOException;
039
040 import javax.servlet.Filter;
041 import javax.servlet.FilterChain;
042 import javax.servlet.FilterConfig;
043 import javax.servlet.ServletContext;
044 import javax.servlet.ServletException;
045 import javax.servlet.ServletRequest;
046 import javax.servlet.ServletResponse;
047 import javax.servlet.http.HttpServletRequest;
048 import javax.servlet.http.HttpServletResponse;
049
050
055 public class InvokerFilter extends BasePortalLifecycle implements Filter {
056
057 @Override
058 public void destroy() {
059 portalDestroy();
060 }
061
062 @Override
063 public void doFilter(
064 ServletRequest servletRequest, ServletResponse servletResponse,
065 FilterChain filterChain)
066 throws IOException, ServletException {
067
068 HttpServletRequest request = (HttpServletRequest)servletRequest;
069
070 String uri = getURI(request);
071
072 HttpServletResponse response = (HttpServletResponse)servletResponse;
073
074 String requestURL = getURL(request);
075
076 if (requestURL.length() > _invokerFilterURIMaxLength) {
077 response.sendError(HttpServletResponse.SC_REQUEST_URI_TOO_LONG);
078
079 if (_log.isWarnEnabled()) {
080 StringBundler sb = new StringBundler(5);
081
082 sb.append("Rejected ");
083 sb.append(StringUtil.shorten(uri, _invokerFilterURIMaxLength));
084 sb.append(" because it has more than ");
085 sb.append(_invokerFilterURIMaxLength);
086 sb.append(" characters");
087
088 _log.warn(sb.toString());
089 }
090
091 return;
092 }
093
094 request = handleNonSerializableRequest(request);
095
096 response =
097 HttpOnlyCookieServletResponse.getHttpOnlyCookieServletResponse(
098 response);
099
100 response = secureResponseHeaders(request, response);
101
102 request.setAttribute(WebKeys.INVOKER_FILTER_URI, uri);
103
104 try {
105 InvokerFilterChain invokerFilterChain = getInvokerFilterChain(
106 request, uri, filterChain);
107
108 Thread currentThread = Thread.currentThread();
109
110 ClassLoader contextClassLoader =
111 currentThread.getContextClassLoader();
112
113 invokerFilterChain.setContextClassLoader(contextClassLoader);
114
115 invokerFilterChain.doFilter(request, response);
116 }
117 finally {
118 request.removeAttribute(WebKeys.INVOKER_FILTER_URI);
119 }
120 }
121
122 @Override
123 public void init(FilterConfig filterConfig) throws ServletException {
124 _filterConfig = filterConfig;
125
126 ServletContext servletContext = _filterConfig.getServletContext();
127
128 _contextPath = servletContext.getContextPath();
129
130 boolean registerPortalLifecycle = GetterUtil.getBoolean(
131 _filterConfig.getInitParameter("register-portal-lifecycle"), true);
132
133 if (registerPortalLifecycle) {
134 registerPortalLifecycle();
135 }
136 else {
137 try {
138 doPortalInit();
139 }
140 catch (Exception e) {
141 _log.error(e, e);
142
143 throw new ServletException(e);
144 }
145 }
146 }
147
148 protected void clearFilterChainsCache() {
149 if (_filterChains != null) {
150 _filterChains.clear();
151 }
152 }
153
154 @Override
155 protected void doPortalDestroy() {
156 ServletContext servletContext = _filterConfig.getServletContext();
157
158 InvokerFilterHelper invokerFilterHelper =
159 (InvokerFilterHelper)servletContext.getAttribute(
160 InvokerFilterHelper.class.getName());
161
162 if (invokerFilterHelper != null) {
163 servletContext.removeAttribute(InvokerFilterHelper.class.getName());
164
165 invokerFilterHelper.destroy();
166 }
167 }
168
169 @Override
170 protected void doPortalInit() throws Exception {
171 _invokerFilterChainSize = GetterUtil.getInteger(
172 PropsUtil.get(PropsKeys.INVOKER_FILTER_CHAIN_SIZE));
173
174 if (_invokerFilterChainSize > 0) {
175 _filterChains = new ConcurrentLFUCache<>(_invokerFilterChainSize);
176 }
177
178 _invokerFilterURIMaxLength = GetterUtil.getInteger(
179 PropsUtil.get(PropsKeys.INVOKER_FILTER_URI_MAX_LENGTH));
180
181 ServletContext servletContext = _filterConfig.getServletContext();
182
183 InvokerFilterHelper invokerFilterHelper =
184 (InvokerFilterHelper)servletContext.getAttribute(
185 InvokerFilterHelper.class.getName());
186
187 if (invokerFilterHelper == null) {
188 invokerFilterHelper = new InvokerFilterHelper();
189
190 servletContext.setAttribute(
191 InvokerFilterHelper.class.getName(), invokerFilterHelper);
192
193 invokerFilterHelper.init(_filterConfig);
194 }
195
196 _invokerFilterHelper = invokerFilterHelper;
197
198 _invokerFilterHelper.addInvokerFilter(this);
199
200 String dispatcher = GetterUtil.getString(
201 _filterConfig.getInitParameter("dispatcher"));
202
203 if (dispatcher.equals("ERROR")) {
204 _dispatcher = Dispatcher.ERROR;
205 }
206 else if (dispatcher.equals("FORWARD")) {
207 _dispatcher = Dispatcher.FORWARD;
208 }
209 else if (dispatcher.equals("INCLUDE")) {
210 _dispatcher = Dispatcher.INCLUDE;
211 }
212 else if (dispatcher.equals("REQUEST")) {
213 _dispatcher = Dispatcher.REQUEST;
214 }
215 else {
216 throw new IllegalArgumentException(
217 "Invalid dispatcher " + dispatcher);
218 }
219 }
220
221 protected InvokerFilterChain getInvokerFilterChain(
222 HttpServletRequest request, String uri, FilterChain filterChain) {
223
224 if (_filterChains == null) {
225 return _invokerFilterHelper.createInvokerFilterChain(
226 request, _dispatcher, uri, filterChain);
227 }
228
229 CacheKeyGenerator cacheKeyGenerator =
230 CacheKeyGeneratorUtil.getCacheKeyGenerator(
231 InvokerFilter.class.getName());
232
233 String key = String.valueOf(cacheKeyGenerator.getCacheKey(uri));
234
235 InvokerFilterChain invokerFilterChain = _filterChains.get(key);
236
237 if (invokerFilterChain == null) {
238 invokerFilterChain = _invokerFilterHelper.createInvokerFilterChain(
239 request, _dispatcher, uri, filterChain);
240
241 _filterChains.put(key, invokerFilterChain);
242 }
243
244 return invokerFilterChain.clone(filterChain);
245 }
246
247 protected String getURI(HttpServletRequest request) {
248 String uri = null;
249
250 if (_dispatcher == Dispatcher.ERROR) {
251 uri = (String)request.getAttribute(
252 JavaConstants.JAVAX_SERVLET_ERROR_REQUEST_URI);
253 }
254 else if (_dispatcher == Dispatcher.INCLUDE) {
255 uri = (String)request.getAttribute(
256 JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
257 }
258 else {
259 uri = request.getRequestURI();
260 }
261
262 if (Validator.isNotNull(_contextPath) &&
263 !_contextPath.equals(StringPool.SLASH) &&
264 uri.startsWith(_contextPath)) {
265
266 uri = uri.substring(_contextPath.length());
267 }
268
269 return HttpUtil.normalizePath(uri);
270 }
271
272 protected String getURL(HttpServletRequest request) {
273 StringBuffer requestURL = request.getRequestURL();
274
275 if (requestURL == null) {
276 return StringPool.BLANK;
277 }
278
279 String queryString = request.getQueryString();
280
281 if (!Validator.isBlank(queryString)) {
282 requestURL.append(StringPool.QUESTION);
283 requestURL.append(request.getQueryString());
284 }
285
286 return requestURL.toString();
287 }
288
289 protected HttpServletRequest handleNonSerializableRequest(
290 HttpServletRequest request) {
291
292 if (ServerDetector.isWebLogic()) {
293 if (!NonSerializableObjectRequestWrapper.isWrapped(request)) {
294 request = new NonSerializableObjectRequestWrapper(request);
295 }
296 }
297
298 return request;
299 }
300
301 protected HttpServletResponse secureResponseHeaders(
302 HttpServletRequest request, HttpServletResponse response) {
303
304 if (!GetterUtil.getBoolean(
305 request.getAttribute(_SECURE_RESPONSE), true)) {
306
307 return response;
308 }
309
310 request.setAttribute(_SECURE_RESPONSE, Boolean.FALSE);
311
312 return SanitizedServletResponse.getSanitizedServletResponse(
313 request, response);
314 }
315
316 private static final String _SECURE_RESPONSE =
317 InvokerFilter.class.getName() + "SECURE_RESPONSE";
318
319 private static final Log _log = LogFactoryUtil.getLog(InvokerFilter.class);
320
321 private String _contextPath;
322 private Dispatcher _dispatcher;
323 private ConcurrentLFUCache<String, InvokerFilterChain> _filterChains;
324 private FilterConfig _filterConfig;
325 private int _invokerFilterChainSize;
326 private InvokerFilterHelper _invokerFilterHelper;
327 private int _invokerFilterURIMaxLength;
328
329 }