001
014
015 package com.liferay.portal.kernel.servlet.filters.invoker;
016
017 import com.liferay.portal.kernel.concurrent.ConcurrentLFUCache;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.servlet.HttpOnlyCookieServletResponse;
021 import com.liferay.portal.kernel.servlet.NonSerializableObjectRequestWrapper;
022 import com.liferay.portal.kernel.servlet.SanitizedServletResponse;
023 import com.liferay.portal.kernel.servlet.ServletVersionDetector;
024 import com.liferay.portal.kernel.util.BasePortalLifecycle;
025 import com.liferay.portal.kernel.util.ContextPathUtil;
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(7);
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 if (ServletVersionDetector.is3_0()) {
097 response =
098 HttpOnlyCookieServletResponse.getHttpOnlyCookieServletResponse(
099 response);
100 }
101
102 response = secureResponseHeaders(request, response);
103
104 request.setAttribute(WebKeys.INVOKER_FILTER_URI, uri);
105
106 try {
107 InvokerFilterChain invokerFilterChain = getInvokerFilterChain(
108 request, uri, filterChain);
109
110 Thread currentThread = Thread.currentThread();
111
112 ClassLoader contextClassLoader =
113 currentThread.getContextClassLoader();
114
115 invokerFilterChain.setContextClassLoader(contextClassLoader);
116
117 invokerFilterChain.doFilter(request, response);
118 }
119 finally {
120 request.removeAttribute(WebKeys.INVOKER_FILTER_URI);
121 }
122 }
123
124 @Override
125 public void init(FilterConfig filterConfig) throws ServletException {
126 _filterConfig = filterConfig;
127
128 ServletContext servletContext = _filterConfig.getServletContext();
129
130 _contextPath = ContextPathUtil.getContextPath(servletContext);
131
132 boolean registerPortalLifecycle = GetterUtil.getBoolean(
133 _filterConfig.getInitParameter("register-portal-lifecycle"), true);
134
135 if (registerPortalLifecycle) {
136 registerPortalLifecycle();
137 }
138 else {
139 try {
140 doPortalInit();
141 }
142 catch (Exception e) {
143 _log.error(e, e);
144
145 throw new ServletException(e);
146 }
147 }
148 }
149
150 protected void clearFilterChainsCache() {
151 if (_filterChains != null) {
152 _filterChains.clear();
153 }
154 }
155
156 @Override
157 protected void doPortalDestroy() {
158 ServletContext servletContext = _filterConfig.getServletContext();
159
160 InvokerFilterHelper invokerFilterHelper =
161 (InvokerFilterHelper)servletContext.getAttribute(
162 InvokerFilterHelper.class.getName());
163
164 if (invokerFilterHelper != null) {
165 servletContext.removeAttribute(InvokerFilterHelper.class.getName());
166
167 invokerFilterHelper.destroy();
168 }
169 }
170
171 @Override
172 protected void doPortalInit() throws Exception {
173 _invokerFilterChainSize = GetterUtil.getInteger(
174 PropsUtil.get(PropsKeys.INVOKER_FILTER_CHAIN_SIZE));
175
176 if (_invokerFilterChainSize > 0) {
177 _filterChains = new ConcurrentLFUCache<String, InvokerFilterChain>(
178 _invokerFilterChainSize);
179 }
180
181 _invokerFilterURIMaxLength = GetterUtil.getInteger(
182 PropsUtil.get(PropsKeys.INVOKER_FILTER_URI_MAX_LENGTH));
183
184 ServletContext servletContext = _filterConfig.getServletContext();
185
186 InvokerFilterHelper invokerFilterHelper =
187 (InvokerFilterHelper)servletContext.getAttribute(
188 InvokerFilterHelper.class.getName());
189
190 if (invokerFilterHelper == null) {
191 invokerFilterHelper = new InvokerFilterHelper();
192
193 servletContext.setAttribute(
194 InvokerFilterHelper.class.getName(), invokerFilterHelper);
195
196 invokerFilterHelper.readLiferayFilterWebXML(
197 servletContext, "/WEB-INF/liferay-web.xml");
198 }
199
200 _invokerFilterHelper = invokerFilterHelper;
201
202 _invokerFilterHelper.addInvokerFilter(this);
203
204 String dispatcher = GetterUtil.getString(
205 _filterConfig.getInitParameter("dispatcher"));
206
207 if (dispatcher.equals("ERROR")) {
208 _dispatcher = Dispatcher.ERROR;
209 }
210 else if (dispatcher.equals("FORWARD")) {
211 _dispatcher = Dispatcher.FORWARD;
212 }
213 else if (dispatcher.equals("INCLUDE")) {
214 _dispatcher = Dispatcher.INCLUDE;
215 }
216 else if (dispatcher.equals("REQUEST")) {
217 _dispatcher = Dispatcher.REQUEST;
218 }
219 else {
220 throw new IllegalArgumentException(
221 "Invalid dispatcher " + dispatcher);
222 }
223 }
224
225 protected InvokerFilterChain getInvokerFilterChain(
226 HttpServletRequest request, String uri, FilterChain filterChain) {
227
228 if (_filterChains == null) {
229 return _invokerFilterHelper.createInvokerFilterChain(
230 request, _dispatcher, uri, filterChain);
231 }
232
233 InvokerFilterChain invokerFilterChain = _filterChains.get(uri);
234
235 if (invokerFilterChain == null) {
236 invokerFilterChain = _invokerFilterHelper.createInvokerFilterChain(
237 request, _dispatcher, uri, filterChain);
238
239 _filterChains.put(uri, invokerFilterChain);
240 }
241
242 return invokerFilterChain.clone(filterChain);
243 }
244
245 protected String getURI(HttpServletRequest request) {
246 String uri = null;
247
248 if (_dispatcher == Dispatcher.ERROR) {
249 uri = (String)request.getAttribute(
250 JavaConstants.JAVAX_SERVLET_ERROR_REQUEST_URI);
251 }
252 else if (_dispatcher == Dispatcher.INCLUDE) {
253 uri = (String)request.getAttribute(
254 JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
255 }
256 else {
257 uri = request.getRequestURI();
258 }
259
260 if (Validator.isNotNull(_contextPath) &&
261 !_contextPath.equals(StringPool.SLASH) &&
262 uri.startsWith(_contextPath)) {
263
264 uri = uri.substring(_contextPath.length());
265 }
266
267 return HttpUtil.normalizePath(uri);
268 }
269
270 protected String getURL(HttpServletRequest request) {
271 StringBuffer requestURL = request.getRequestURL();
272
273 if (requestURL == null) {
274 return StringPool.BLANK;
275 }
276
277 String queryString = request.getQueryString();
278
279 if (!Validator.isBlank(queryString)) {
280 requestURL.append(StringPool.QUESTION);
281 requestURL.append(request.getQueryString());
282 }
283
284 return requestURL.toString();
285 }
286
287 protected HttpServletRequest handleNonSerializableRequest(
288 HttpServletRequest request) {
289
290 if (ServerDetector.isWebLogic()) {
291 if (!NonSerializableObjectRequestWrapper.isWrapped(request)) {
292 request = new NonSerializableObjectRequestWrapper(request);
293 }
294 }
295
296 return request;
297 }
298
299 protected HttpServletResponse secureResponseHeaders(
300 HttpServletRequest request, HttpServletResponse response) {
301
302 if (Boolean.FALSE.equals(request.getAttribute(_SECURE_RESPONSE))) {
303 return response;
304 }
305
306 request.setAttribute(_SECURE_RESPONSE, Boolean.FALSE);
307
308 return SanitizedServletResponse.getSanitizedServletResponse(
309 request, response);
310 }
311
312 private static final String _SECURE_RESPONSE =
313 InvokerFilter.class.getName() + "SECURE_RESPONSE";
314
315 private static Log _log = LogFactoryUtil.getLog(InvokerFilter.class);
316
317 private String _contextPath;
318 private Dispatcher _dispatcher;
319 private ConcurrentLFUCache<String, InvokerFilterChain> _filterChains;
320 private FilterConfig _filterConfig;
321 private int _invokerFilterChainSize;
322 private InvokerFilterHelper _invokerFilterHelper;
323 private int _invokerFilterURIMaxLength;
324
325 }