001
014
015 package com.liferay.portal.servlet.filters.dynamiccss;
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.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
022 import com.liferay.portal.kernel.servlet.HttpHeaders;
023 import com.liferay.portal.kernel.servlet.PortalWebResourcesUtil;
024 import com.liferay.portal.kernel.servlet.PortletResourcesUtil;
025 import com.liferay.portal.kernel.servlet.ServletResponseUtil;
026 import com.liferay.portal.kernel.util.ContentTypes;
027 import com.liferay.portal.kernel.util.FileUtil;
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.StringPool;
032 import com.liferay.portal.kernel.util.StringUtil;
033 import com.liferay.portal.kernel.util.URLUtil;
034 import com.liferay.portal.servlet.filters.IgnoreModuleRequestFilter;
035 import com.liferay.portal.util.PortalUtil;
036 import com.liferay.portal.util.PropsUtil;
037
038 import java.io.File;
039
040 import java.net.URL;
041
042 import javax.servlet.FilterChain;
043 import javax.servlet.FilterConfig;
044 import javax.servlet.ServletContext;
045 import javax.servlet.http.HttpServletRequest;
046 import javax.servlet.http.HttpServletResponse;
047
048
052 public class DynamicCSSFilter extends IgnoreModuleRequestFilter {
053
054 public static final boolean ENABLED = GetterUtil.getBoolean(
055 PropsUtil.get(DynamicCSSFilter.class.getName()));
056
057 @Override
058 public void init(FilterConfig filterConfig) {
059 super.init(filterConfig);
060
061 _servletContext = filterConfig.getServletContext();
062
063 File tempDir = (File)_servletContext.getAttribute(
064 JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR);
065
066 _tempDir = new File(tempDir, _TEMP_DIR);
067
068 _tempDir.mkdirs();
069 }
070
071 protected String getCacheFileName(HttpServletRequest request) {
072 CacheKeyGenerator cacheKeyGenerator =
073 CacheKeyGeneratorUtil.getCacheKeyGenerator(
074 DynamicCSSFilter.class.getName());
075
076 cacheKeyGenerator.append(HttpUtil.getProtocol(request.isSecure()));
077 cacheKeyGenerator.append(StringPool.UNDERLINE);
078 cacheKeyGenerator.append(request.getRequestURI());
079
080 String queryString = request.getQueryString();
081
082 if (queryString != null) {
083 cacheKeyGenerator.append(sterilizeQueryString(queryString));
084 }
085
086 if (PortalUtil.isRightToLeft(request)) {
087 cacheKeyGenerator.append("_rtl");
088 }
089
090 return String.valueOf(cacheKeyGenerator.finish());
091 }
092
093 protected Object getDynamicContent(
094 HttpServletRequest request, HttpServletResponse response,
095 FilterChain filterChain)
096 throws Exception {
097
098 ServletContext servletContext = _servletContext;
099
100 String requestPath = getRequestPath(request);
101
102 URL resourceURL = _servletContext.getResource(requestPath);
103
104 if (resourceURL == null) {
105 ServletContext resourceServletContext =
106 PortalWebResourcesUtil.getPathServletContext(requestPath);
107
108 if (resourceServletContext != null) {
109 resourceURL = PortalWebResourcesUtil.getResource(
110 resourceServletContext, requestPath);
111 }
112
113 if (resourceURL == null) {
114 resourceServletContext =
115 PortletResourcesUtil.getPathServletContext(requestPath);
116
117 if (resourceServletContext != null) {
118 resourceURL = PortletResourcesUtil.getResource(
119 resourceServletContext, requestPath);
120 }
121 }
122
123 if (resourceURL == null) {
124 return null;
125 }
126
127 servletContext = resourceServletContext;
128 }
129
130 String cacheCommonFileName = getCacheFileName(request);
131
132 File cacheContentTypeFile = new File(
133 _tempDir, cacheCommonFileName + "_E_CONTENT_TYPE");
134 File cacheDataFile = new File(
135 _tempDir, cacheCommonFileName + "_E_DATA");
136
137 if (cacheDataFile.exists() &&
138 (cacheDataFile.lastModified() >=
139 URLUtil.getLastModifiedTime(resourceURL))) {
140
141 if (cacheContentTypeFile.exists()) {
142 String contentType = FileUtil.read(cacheContentTypeFile);
143
144 response.setContentType(contentType);
145 }
146
147 return cacheDataFile;
148 }
149
150 String dynamicContent = null;
151
152 String content = null;
153
154 try {
155 if (requestPath.endsWith(_CSS_EXTENSION)) {
156 if (_log.isInfoEnabled()) {
157 _log.info("Replacing tokens on CSS " + requestPath);
158 }
159
160 content = StringUtil.read(resourceURL.openStream());
161
162 dynamicContent = DynamicCSSUtil.replaceToken(
163 servletContext, request, content);
164
165 response.setContentType(ContentTypes.TEXT_CSS);
166
167 FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
168 }
169 else if (requestPath.endsWith(_JSP_EXTENSION)) {
170 if (_log.isInfoEnabled()) {
171 _log.info(
172 "Replacing tokens on JSP or servlet " + requestPath);
173 }
174
175 BufferCacheServletResponse bufferCacheServletResponse =
176 new BufferCacheServletResponse(response);
177
178 processFilter(
179 DynamicCSSFilter.class, request, bufferCacheServletResponse,
180 filterChain);
181
182 bufferCacheServletResponse.finishResponse(false);
183
184 content = bufferCacheServletResponse.getString();
185
186 dynamicContent = DynamicCSSUtil.replaceToken(
187 servletContext, request, content);
188
189 FileUtil.write(
190 cacheContentTypeFile,
191 bufferCacheServletResponse.getContentType());
192 }
193 else {
194 return null;
195 }
196 }
197 catch (Exception e) {
198 _log.error("Unable to replace tokens in CSS " + requestPath, e);
199
200 if (_log.isDebugEnabled()) {
201 _log.debug(content);
202 }
203
204 response.setHeader(
205 HttpHeaders.CACHE_CONTROL,
206 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
207 }
208
209 if (dynamicContent != null) {
210 FileUtil.write(cacheDataFile, dynamicContent);
211 }
212 else {
213 dynamicContent = content;
214 }
215
216 return dynamicContent;
217 }
218
219 protected String getRequestPath(HttpServletRequest request) {
220 String requestPath = request.getRequestURI();
221
222 String contextPath = request.getContextPath();
223
224 if (!contextPath.equals(StringPool.SLASH)) {
225 requestPath = requestPath.substring(contextPath.length());
226 }
227
228 return requestPath;
229 }
230
231 @Override
232 protected boolean isModuleRequest(HttpServletRequest request) {
233 String requestURI = request.getRequestURI();
234
235 if (PortalWebResourcesUtil.hasContextPath(requestURI)) {
236 return false;
237 }
238
239 return super.isModuleRequest(request);
240 }
241
242 @Override
243 protected void processFilter(
244 HttpServletRequest request, HttpServletResponse response,
245 FilterChain filterChain)
246 throws Exception {
247
248 Object parsedContent = getDynamicContent(
249 request, response, filterChain);
250
251 if (parsedContent == null) {
252 processFilter(
253 DynamicCSSFilter.class, request, response, filterChain);
254 }
255 else {
256 if (parsedContent instanceof File) {
257 ServletResponseUtil.write(response, (File)parsedContent);
258 }
259 else if (parsedContent instanceof String) {
260 ServletResponseUtil.write(response, (String)parsedContent);
261 }
262 }
263 }
264
265 protected String sterilizeQueryString(String queryString) {
266 return StringUtil.replace(
267 queryString, new String[] {StringPool.SLASH, StringPool.BACK_SLASH},
268 new String[] {StringPool.UNDERLINE, StringPool.UNDERLINE});
269 }
270
271 private static final String _CSS_EXTENSION = ".css";
272
273 private static final String _JSP_EXTENSION = ".jsp";
274
275 private static final String _TEMP_DIR = "css";
276
277 private static final Log _log = LogFactoryUtil.getLog(
278 DynamicCSSFilter.class);
279
280 private ServletContext _servletContext;
281 private File _tempDir;
282
283 }