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