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 if (requestPath.endsWith(_CSS_EXTENSION) &&
103 PortalUtil.isRightToLeft(request)) {
104
105 int pos = requestPath.lastIndexOf(StringPool.PERIOD);
106
107 requestPath =
108 requestPath.substring(0, pos) + "_rtl" +
109 requestPath.substring(pos);
110 }
111
112 URL resourceURL = _servletContext.getResource(requestPath);
113
114 if (resourceURL == null) {
115 ServletContext resourceServletContext =
116 PortalWebResourcesUtil.getPathServletContext(requestPath);
117
118 if (resourceServletContext != null) {
119 resourceURL = PortalWebResourcesUtil.getResource(
120 resourceServletContext, requestPath);
121 }
122
123 if (resourceURL == null) {
124 resourceServletContext =
125 PortletResourcesUtil.getPathServletContext(requestPath);
126
127 if (resourceServletContext != null) {
128 resourceURL = PortletResourcesUtil.getResource(
129 resourceServletContext, requestPath);
130 }
131 }
132
133 if (resourceURL == null) {
134 return null;
135 }
136
137 servletContext = resourceServletContext;
138 }
139
140 String cacheCommonFileName = getCacheFileName(request);
141
142 File cacheContentTypeFile = new File(
143 _tempDir, cacheCommonFileName + "_E_CONTENT_TYPE");
144 File cacheDataFile = new File(
145 _tempDir, cacheCommonFileName + "_E_DATA");
146
147 if (cacheDataFile.exists() &&
148 (cacheDataFile.lastModified() >=
149 URLUtil.getLastModifiedTime(resourceURL))) {
150
151 if (cacheContentTypeFile.exists()) {
152 String contentType = FileUtil.read(cacheContentTypeFile);
153
154 response.setContentType(contentType);
155 }
156
157 return cacheDataFile;
158 }
159
160 String dynamicContent = null;
161
162 String content = null;
163
164 try {
165 if (requestPath.endsWith(_CSS_EXTENSION)) {
166 if (_log.isInfoEnabled()) {
167 _log.info("Replacing tokens on CSS " + requestPath);
168 }
169
170 content = StringUtil.read(resourceURL.openStream());
171
172 dynamicContent = DynamicCSSUtil.replaceToken(
173 servletContext, request, content);
174
175 response.setContentType(ContentTypes.TEXT_CSS);
176
177 FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
178 }
179 else if (requestPath.endsWith(_JSP_EXTENSION)) {
180 if (_log.isInfoEnabled()) {
181 _log.info(
182 "Replacing tokens on JSP or servlet " + requestPath);
183 }
184
185 BufferCacheServletResponse bufferCacheServletResponse =
186 new BufferCacheServletResponse(response);
187
188 processFilter(
189 DynamicCSSFilter.class.getName(), request,
190 bufferCacheServletResponse, filterChain);
191
192 bufferCacheServletResponse.finishResponse(false);
193
194 content = bufferCacheServletResponse.getString();
195
196 dynamicContent = DynamicCSSUtil.replaceToken(
197 servletContext, request, content);
198
199 FileUtil.write(
200 cacheContentTypeFile,
201 bufferCacheServletResponse.getContentType());
202 }
203 else {
204 return null;
205 }
206 }
207 catch (Exception e) {
208 _log.error("Unable to replace tokens in CSS " + requestPath, e);
209
210 if (_log.isDebugEnabled()) {
211 _log.debug(content);
212 }
213
214 response.setHeader(
215 HttpHeaders.CACHE_CONTROL,
216 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
217 }
218
219 if (dynamicContent != null) {
220 FileUtil.write(cacheDataFile, dynamicContent);
221 }
222 else {
223 dynamicContent = content;
224 }
225
226 return dynamicContent;
227 }
228
229 protected String getRequestPath(HttpServletRequest request) {
230 String requestPath = request.getRequestURI();
231
232 String contextPath = request.getContextPath();
233
234 if (!contextPath.equals(StringPool.SLASH)) {
235 requestPath = requestPath.substring(contextPath.length());
236 }
237
238 return requestPath;
239 }
240
241 @Override
242 protected boolean isModuleRequest(HttpServletRequest request) {
243 String requestURI = request.getRequestURI();
244
245 if (PortalWebResourcesUtil.hasContextPath(requestURI)) {
246 return false;
247 }
248
249 return super.isModuleRequest(request);
250 }
251
252 @Override
253 protected void processFilter(
254 HttpServletRequest request, HttpServletResponse response,
255 FilterChain filterChain)
256 throws Exception {
257
258 Object parsedContent = getDynamicContent(
259 request, response, filterChain);
260
261 if (parsedContent == null) {
262 processFilter(
263 DynamicCSSFilter.class.getName(), request, response,
264 filterChain);
265 }
266 else {
267 if (parsedContent instanceof File) {
268 ServletResponseUtil.write(response, (File)parsedContent);
269 }
270 else if (parsedContent instanceof String) {
271 ServletResponseUtil.write(response, (String)parsedContent);
272 }
273 }
274 }
275
276 protected String sterilizeQueryString(String queryString) {
277 return StringUtil.replace(
278 queryString, new String[] {StringPool.SLASH, StringPool.BACK_SLASH},
279 new String[] {StringPool.UNDERLINE, StringPool.UNDERLINE});
280 }
281
282 private static final String _CSS_EXTENSION = ".css";
283
284 private static final String _JSP_EXTENSION = ".jsp";
285
286 private static final String _TEMP_DIR = "css";
287
288 private static final Log _log = LogFactoryUtil.getLog(
289 DynamicCSSFilter.class);
290
291 private ServletContext _servletContext;
292 private File _tempDir;
293
294 }