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