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.PortalWebResourceConstants;
024 import com.liferay.portal.kernel.servlet.PortalWebResourcesUtil;
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 DynamicCSSUtil.init(_servletContext);
071 }
072
073 protected String getCacheFileName(HttpServletRequest request) {
074 CacheKeyGenerator cacheKeyGenerator =
075 CacheKeyGeneratorUtil.getCacheKeyGenerator(
076 DynamicCSSFilter.class.getName());
077
078 cacheKeyGenerator.append(HttpUtil.getProtocol(request.isSecure()));
079 cacheKeyGenerator.append(StringPool.UNDERLINE);
080 cacheKeyGenerator.append(request.getRequestURI());
081
082 String queryString = request.getQueryString();
083
084 if (queryString != null) {
085 cacheKeyGenerator.append(sterilizeQueryString(queryString));
086 }
087
088 if (PortalUtil.isRightToLeft(request)) {
089 cacheKeyGenerator.append("_rtl");
090 }
091
092 return String.valueOf(cacheKeyGenerator.finish());
093 }
094
095 protected Object getDynamicContent(
096 HttpServletRequest request, HttpServletResponse response,
097 FilterChain filterChain)
098 throws Exception {
099
100 boolean bundleResource = false;
101 ServletContext servletContext = _servletContext;
102
103 String requestPath = getRequestPath(request);
104
105 URL resourceURL = _servletContext.getResource(requestPath);
106
107 if (resourceURL == null) {
108 resourceURL = PortalWebResourcesUtil.getServletContextResource(
109 requestPath);
110
111 if (resourceURL == null) {
112 return null;
113 }
114
115 bundleResource = true;
116 servletContext = PortalWebResourcesUtil.getServletContext(
117 PortalWebResourceConstants.RESOURCE_TYPE_CSS);
118 }
119
120 String cacheCommonFileName = getCacheFileName(request);
121
122 File cacheContentTypeFile = new File(
123 _tempDir, cacheCommonFileName + "_E_CONTENT_TYPE");
124 File cacheDataFile = new File(
125 _tempDir, cacheCommonFileName + "_E_DATA");
126
127 if (cacheDataFile.exists() &&
128 (cacheDataFile.lastModified() >=
129 URLUtil.getLastModifiedTime(resourceURL))) {
130
131 if (cacheContentTypeFile.exists()) {
132 String contentType = FileUtil.read(cacheContentTypeFile);
133
134 response.setContentType(contentType);
135 }
136
137 return cacheDataFile;
138 }
139
140 String dynamicContent = null;
141
142 String content = null;
143
144 try {
145 if (requestPath.endsWith(_CSS_EXTENSION)) {
146 if (_log.isInfoEnabled()) {
147 _log.info("Parsing SASS on CSS " + requestPath);
148 }
149
150 content = StringUtil.read(resourceURL.openStream());
151
152 if (bundleResource) {
153 dynamicContent = DynamicCSSUtil.replaceToken(
154 servletContext, request, content);
155 }
156 else {
157 dynamicContent = DynamicCSSUtil.parseSass(
158 servletContext, request, requestPath, content);
159 }
160
161 response.setContentType(ContentTypes.TEXT_CSS);
162
163 FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
164 }
165 else if (requestPath.endsWith(_JSP_EXTENSION)) {
166 if (_log.isInfoEnabled()) {
167 _log.info("Parsing SASS on JSP or servlet " + requestPath);
168 }
169
170 BufferCacheServletResponse bufferCacheServletResponse =
171 new BufferCacheServletResponse(response);
172
173 processFilter(
174 DynamicCSSFilter.class, request, bufferCacheServletResponse,
175 filterChain);
176
177 bufferCacheServletResponse.finishResponse(false);
178
179 content = bufferCacheServletResponse.getString();
180
181 dynamicContent = DynamicCSSUtil.parseSass(
182 servletContext, request, requestPath, content);
183
184 FileUtil.write(
185 cacheContentTypeFile,
186 bufferCacheServletResponse.getContentType());
187 }
188 else {
189 return null;
190 }
191 }
192 catch (Exception e) {
193 _log.error("Unable to parse SASS on CSS " + requestPath, e);
194
195 if (_log.isDebugEnabled()) {
196 _log.debug(content);
197 }
198
199 response.setHeader(
200 HttpHeaders.CACHE_CONTROL,
201 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
202 }
203
204 if (dynamicContent != null) {
205 FileUtil.write(cacheDataFile, dynamicContent);
206 }
207 else {
208 dynamicContent = content;
209 }
210
211 return dynamicContent;
212 }
213
214 protected String getRequestPath(HttpServletRequest request) {
215 String requestPath = request.getRequestURI();
216
217 String contextPath = request.getContextPath();
218
219 if (!contextPath.equals(StringPool.SLASH)) {
220 requestPath = requestPath.substring(contextPath.length());
221 }
222
223 return requestPath;
224 }
225
226 @Override
227 protected boolean isModuleRequest(HttpServletRequest request) {
228 String requestURI = request.getRequestURI();
229
230 if (PortalWebResourcesUtil.isResourceContextPath(requestURI)) {
231 return false;
232 }
233
234 return super.isModuleRequest(request);
235 }
236
237 @Override
238 protected void processFilter(
239 HttpServletRequest request, HttpServletResponse response,
240 FilterChain filterChain)
241 throws Exception {
242
243 Object parsedContent = getDynamicContent(
244 request, response, filterChain);
245
246 if (parsedContent == null) {
247 processFilter(
248 DynamicCSSFilter.class, request, response, filterChain);
249 }
250 else {
251 if (parsedContent instanceof File) {
252 ServletResponseUtil.write(response, (File)parsedContent);
253 }
254 else if (parsedContent instanceof String) {
255 ServletResponseUtil.write(response, (String)parsedContent);
256 }
257 }
258 }
259
260 protected String sterilizeQueryString(String queryString) {
261 return StringUtil.replace(
262 queryString, new String[] {StringPool.SLASH, StringPool.BACK_SLASH},
263 new String[] {StringPool.UNDERLINE, StringPool.UNDERLINE});
264 }
265
266 private static final String _CSS_EXTENSION = ".css";
267
268 private static final String _JSP_EXTENSION = ".jsp";
269
270 private static final String _TEMP_DIR = "css";
271
272 private static final Log _log = LogFactoryUtil.getLog(
273 DynamicCSSFilter.class);
274
275 private ServletContext _servletContext;
276 private File _tempDir;
277
278 }