1
22
23 package com.liferay.portal.servlet.filters.cache;
24
25 import com.liferay.portal.NoSuchLayoutException;
26 import com.liferay.portal.kernel.language.LanguageUtil;
27 import com.liferay.portal.kernel.log.Log;
28 import com.liferay.portal.kernel.log.LogFactoryUtil;
29 import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
30 import com.liferay.portal.kernel.util.GetterUtil;
31 import com.liferay.portal.kernel.util.Http;
32 import com.liferay.portal.kernel.util.HttpUtil;
33 import com.liferay.portal.kernel.util.JavaConstants;
34 import com.liferay.portal.kernel.util.ParamUtil;
35 import com.liferay.portal.kernel.util.StringPool;
36 import com.liferay.portal.kernel.util.StringUtil;
37 import com.liferay.portal.kernel.util.UnicodeProperties;
38 import com.liferay.portal.kernel.util.Validator;
39 import com.liferay.portal.model.Group;
40 import com.liferay.portal.model.Layout;
41 import com.liferay.portal.model.LayoutConstants;
42 import com.liferay.portal.model.Portlet;
43 import com.liferay.portal.model.PortletConstants;
44 import com.liferay.portal.service.GroupLocalServiceUtil;
45 import com.liferay.portal.service.LayoutLocalServiceUtil;
46 import com.liferay.portal.service.PortletLocalServiceUtil;
47 import com.liferay.portal.servlet.filters.BasePortalFilter;
48 import com.liferay.portal.struts.LastPath;
49 import com.liferay.portal.util.PortalInstances;
50 import com.liferay.portal.util.PortalUtil;
51 import com.liferay.portal.util.PropsValues;
52 import com.liferay.portal.util.WebKeys;
53 import com.liferay.util.servlet.filters.CacheResponse;
54 import com.liferay.util.servlet.filters.CacheResponseData;
55 import com.liferay.util.servlet.filters.CacheResponseUtil;
56
57 import javax.servlet.FilterChain;
58 import javax.servlet.FilterConfig;
59 import javax.servlet.http.HttpServletRequest;
60 import javax.servlet.http.HttpServletResponse;
61 import javax.servlet.http.HttpSession;
62
63
70 public class CacheFilter extends BasePortalFilter {
71
72 public static final String SKIP_FILTER = CacheFilter.class + "SKIP_FILTER";
73
74 public void init(FilterConfig filterConfig) {
75 super.init(filterConfig);
76
77 _pattern = GetterUtil.getInteger(
78 filterConfig.getInitParameter("pattern"));
79
80 if ((_pattern != _PATTERN_FRIENDLY) &&
81 (_pattern != _PATTERN_LAYOUT) &&
82 (_pattern != _PATTERN_RESOURCE)) {
83
84 _log.error("Cache pattern is invalid");
85 }
86 }
87
88 protected String getBrowserType(HttpServletRequest request) {
89 if (BrowserSnifferUtil.isIe(request) &&
90 BrowserSnifferUtil.getMajorVersion(request) == 7.0) {
91
92 return _BROWSER_TYPE_IE_7;
93 }
94 else if (BrowserSnifferUtil.isIe(request)) {
95 return _BROWSER_TYPE_IE;
96 }
97 else {
98 return _BROWSER_TYPE_OTHER;
99 }
100 }
101
102 protected String getCacheKey(HttpServletRequest request) {
103 StringBuilder sb = new StringBuilder();
104
105
107 sb.append(HttpUtil.getProtocol(request));
108 sb.append(Http.PROTOCOL_DELIMITER);
109 sb.append(request.getContextPath());
110 sb.append(request.getServletPath());
111 sb.append(request.getPathInfo());
112 sb.append(StringPool.QUESTION);
113 sb.append(request.getQueryString());
114
115
117 sb.append(StringPool.POUND);
118
119 String languageId = (String)request.getAttribute(
120 WebKeys.I18N_LANGUAGE_ID);
121
122 if (Validator.isNull(languageId)) {
123 languageId = LanguageUtil.getLanguageId(request);
124 }
125
126 sb.append(languageId);
127
128
130 sb.append(StringPool.POUND);
131 sb.append(getBrowserType(request));
132
133
135 sb.append(StringPool.POUND);
136 sb.append(BrowserSnifferUtil.acceptsGzip(request));
137
138 return sb.toString().trim().toUpperCase();
139 }
140
141 protected long getPlid(
142 long companyId, String pathInfo, String servletPath, long defaultPlid) {
143
144 if (_pattern == _PATTERN_LAYOUT) {
145 return defaultPlid;
146 }
147
148 if (Validator.isNull(pathInfo) ||
149 !pathInfo.startsWith(StringPool.SLASH)) {
150
151 return 0;
152 }
153
154
156 String friendlyURL = null;
157
158 int pos = pathInfo.indexOf(StringPool.SLASH, 1);
159
160 if (pos != -1) {
161 friendlyURL = pathInfo.substring(0, pos);
162 }
163 else {
164 if (pathInfo.length() > 1) {
165 friendlyURL = pathInfo.substring(0, pathInfo.length());
166 }
167 }
168
169 if (Validator.isNull(friendlyURL)) {
170 return 0;
171 }
172
173 long groupId = 0;
174 boolean privateLayout = false;
175
176 try {
177 Group group = GroupLocalServiceUtil.getFriendlyURLGroup(
178 companyId, friendlyURL);
179
180 groupId = group.getGroupId();
181
182 if (servletPath.startsWith(
183 PropsValues.
184 LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING) ||
185 servletPath.startsWith(
186 PropsValues.
187 LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING)) {
188
189 privateLayout = true;
190 }
191 else if (servletPath.startsWith(
192 PropsValues.
193 LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING)) {
194
195 privateLayout = false;
196 }
197 }
198 catch (NoSuchLayoutException nsle) {
199 if (_log.isWarnEnabled()) {
200 _log.warn(nsle);
201 }
202 }
203 catch (Exception e) {
204 if (_log.isWarnEnabled()) {
205 _log.error(e);
206 }
207
208 return 0;
209 }
210
211
213 friendlyURL = null;
214
215 if ((pos != -1) && ((pos + 1) != pathInfo.length())) {
216 friendlyURL = pathInfo.substring(pos, pathInfo.length());
217 }
218
219 if (Validator.isNull(friendlyURL)) {
220 return 0;
221 }
222
223
225 try {
226 Layout layout = LayoutLocalServiceUtil.getFriendlyURLLayout(
227 groupId, privateLayout, friendlyURL);
228
229 return layout.getPlid();
230 }
231 catch (NoSuchLayoutException nsle) {
232 _log.warn(nsle);
233
234 return 0;
235 }
236 catch (Exception e) {
237 _log.error(e);
238
239 return 0;
240 }
241 }
242
243 protected boolean isAlreadyFiltered(HttpServletRequest request) {
244 if (request.getAttribute(SKIP_FILTER) != null) {
245 return true;
246 }
247 else {
248 return false;
249 }
250 }
251
252 protected boolean isCacheableData(
253 long companyId, HttpServletRequest request) {
254
255 try {
256 if (_pattern == _PATTERN_RESOURCE) {
257 return true;
258 }
259
260 long plid = getPlid(
261 companyId, request.getPathInfo(), request.getServletPath(),
262 ParamUtil.getLong(request, "p_l_id"));
263
264 if (plid <= 0) {
265 return false;
266 }
267
268 Layout layout = LayoutLocalServiceUtil.getLayout(plid);
269
270 if (!layout.getType().equals(LayoutConstants.TYPE_PORTLET)) {
271 return false;
272 }
273
274 UnicodeProperties props = layout.getTypeSettingsProperties();
275
276 for (int i = 0; i < 10; i++) {
277 String columnId = "column-" + i;
278
279 String settings = props.getProperty(columnId, StringPool.BLANK);
280
281 String[] portlets = StringUtil.split(settings);
282
283 for (int j = 0; j < portlets.length; j++) {
284 String portletId = StringUtil.extractFirst(
285 portlets[j], PortletConstants.INSTANCE_SEPARATOR);
286
287 Portlet portlet = PortletLocalServiceUtil.getPortletById(
288 companyId, portletId);
289
290 if (!portlet.isLayoutCacheable()) {
291 return false;
292 }
293 }
294 }
295
296 return true;
297 }
298 catch (Exception e) {
299 return false;
300 }
301 }
302
303 protected boolean isCacheableRequest(HttpServletRequest request) {
304 String portletId = ParamUtil.getString(request, "p_p_id");
305
306 if (Validator.isNotNull(portletId)) {
307 return false;
308 }
309
310 if ((_pattern == _PATTERN_FRIENDLY) || (_pattern == _PATTERN_LAYOUT)) {
311 long userId = PortalUtil.getUserId(request);
312 String remoteUser = request.getRemoteUser();
313
314 if ((userId > 0) || Validator.isNotNull(remoteUser)) {
315 return false;
316 }
317 }
318
319 if (_pattern == _PATTERN_LAYOUT) {
320 String plid = ParamUtil.getString(request, "p_l_id");
321
322 if (Validator.isNull(plid)) {
323 return false;
324 }
325 }
326
327 return true;
328 }
329
330 protected boolean isInclude(HttpServletRequest request) {
331 String uri = (String)request.getAttribute(
332 JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
333
334 if (uri == null) {
335 return false;
336 }
337 else {
338 return true;
339 }
340 }
341
342 protected void processFilter(
343 HttpServletRequest request, HttpServletResponse response,
344 FilterChain filterChain)
345 throws Exception {
346
347 if (isCacheableRequest(request) && !isInclude(request) &&
348 !isAlreadyFiltered(request)) {
349
350 request.setAttribute(SKIP_FILTER, Boolean.TRUE);
351
352 String key = getCacheKey(request);
353
354 long companyId = PortalInstances.getCompanyId(request);
355
356 CacheResponseData cacheResponseData =
357 CacheUtil.getCacheResponseData(companyId, key);
358
359 if (cacheResponseData == null) {
360 if (!isCacheableData(companyId, request)) {
361 if (_log.isDebugEnabled()) {
362 _log.debug("Request is not cacheable " + key);
363 }
364
365 processFilter(
366 CacheFilter.class, request, response, filterChain);
367
368 return;
369 }
370
371 if (_log.isInfoEnabled()) {
372 _log.info("Caching request " + key);
373 }
374
375 CacheResponse cacheResponse = new CacheResponse(
376 response, StringPool.UTF8);
377
378 processFilter(
379 CacheFilter.class, request, cacheResponse, filterChain);
380
381 cacheResponseData = new CacheResponseData(
382 cacheResponse.getData(), cacheResponse.getContentType(),
383 cacheResponse.getHeaders());
384
385 LastPath lastPath = (LastPath)request.getAttribute(
386 WebKeys.LAST_PATH);
387
388 if (lastPath != null) {
389 cacheResponseData.setAttribute(WebKeys.LAST_PATH, lastPath);
390 }
391
392
397 if ((cacheResponseData.getData().length > 0) &&
398 (isCacheableRequest(request))) {
399
400 CacheUtil.putCacheResponseData(
401 companyId, key, cacheResponseData);
402 }
403 }
404 else {
405 LastPath lastPath = (LastPath)cacheResponseData.getAttribute(
406 WebKeys.LAST_PATH);
407
408 if (lastPath != null) {
409 HttpSession session = request.getSession();
410
411 session.setAttribute(WebKeys.LAST_PATH, lastPath);
412 }
413 }
414
415 CacheResponseUtil.write(response, cacheResponseData);
416 }
417 else {
418 if (_log.isDebugEnabled()) {
419 _log.debug("Request is not cacheable");
420 }
421
422 processFilter(CacheFilter.class, request, response, filterChain);
423 }
424 }
425
426 private static final int _PATTERN_FRIENDLY = 0;
427
428 private static final int _PATTERN_LAYOUT = 1;
429
430 private static final int _PATTERN_RESOURCE = 2;
431
432 private static final String _BROWSER_TYPE_IE_7 = "ie_7";
433
434 private static final String _BROWSER_TYPE_IE = "ie";
435
436 private static final String _BROWSER_TYPE_OTHER = "other";
437
438 private static Log _log = LogFactoryUtil.getLog(CacheFilter.class);
439
440 private int _pattern;
441
442 }