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.ServletResponseUtil;
024 import com.liferay.portal.kernel.util.ContentTypes;
025 import com.liferay.portal.kernel.util.FileUtil;
026 import com.liferay.portal.kernel.util.GetterUtil;
027 import com.liferay.portal.kernel.util.JavaConstants;
028 import com.liferay.portal.kernel.util.StringPool;
029 import com.liferay.portal.kernel.util.StringUtil;
030 import com.liferay.portal.servlet.filters.IgnoreModuleRequestFilter;
031 import com.liferay.portal.util.PropsUtil;
032
033 import java.io.File;
034
035 import java.net.URL;
036 import java.net.URLConnection;
037
038 import javax.servlet.FilterChain;
039 import javax.servlet.FilterConfig;
040 import javax.servlet.ServletContext;
041 import javax.servlet.http.HttpServletRequest;
042 import javax.servlet.http.HttpServletResponse;
043
044
048 public class DynamicCSSFilter extends IgnoreModuleRequestFilter {
049
050 public static final boolean ENABLED = GetterUtil.getBoolean(
051 PropsUtil.get(DynamicCSSFilter.class.getName()));
052
053 @Override
054 public void init(FilterConfig filterConfig) {
055 super.init(filterConfig);
056
057 _servletContext = filterConfig.getServletContext();
058
059 File tempDir = (File)_servletContext.getAttribute(
060 JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR);
061
062 _tempDir = new File(tempDir, _TEMP_DIR);
063
064 _tempDir.mkdirs();
065
066 DynamicCSSUtil.init();
067 }
068
069 protected String getCacheFileName(HttpServletRequest request) {
070 CacheKeyGenerator cacheKeyGenerator =
071 CacheKeyGeneratorUtil.getCacheKeyGenerator(
072 DynamicCSSFilter.class.getName());
073
074 cacheKeyGenerator.append(request.getRequestURI());
075
076 String queryString = request.getQueryString();
077
078 if (queryString != null) {
079 cacheKeyGenerator.append(sterilizeQueryString(queryString));
080 }
081
082 return String.valueOf(cacheKeyGenerator.finish());
083 }
084
085 protected Object getDynamicContent(
086 HttpServletRequest request, HttpServletResponse response,
087 FilterChain filterChain)
088 throws Exception {
089
090 String requestURI = request.getRequestURI();
091
092 String requestPath = requestURI;
093
094 String contextPath = request.getContextPath();
095
096 if (!contextPath.equals(StringPool.SLASH)) {
097 requestPath = requestPath.substring(contextPath.length());
098 }
099
100 URL resourceURL = _servletContext.getResource(requestPath);
101
102 if (resourceURL == null) {
103 return null;
104 }
105
106 URLConnection urlConnection = resourceURL.openConnection();
107
108 String cacheCommonFileName = getCacheFileName(request);
109
110 File cacheContentTypeFile = new File(
111 _tempDir, cacheCommonFileName + "_E_CONTENT_TYPE");
112 File cacheDataFile = new File(
113 _tempDir, cacheCommonFileName + "_E_DATA");
114
115 if (cacheDataFile.exists() &&
116 (cacheDataFile.lastModified() >= urlConnection.getLastModified())) {
117
118 if (cacheContentTypeFile.exists()) {
119 String contentType = FileUtil.read(cacheContentTypeFile);
120
121 response.setContentType(contentType);
122 }
123
124 return cacheDataFile;
125 }
126
127 String dynamicContent = null;
128
129 String content = null;
130
131 try {
132 if (requestPath.endsWith(_CSS_EXTENSION)) {
133 if (_log.isInfoEnabled()) {
134 _log.info("Parsing SASS on CSS " + requestPath);
135 }
136
137 content = StringUtil.read(urlConnection.getInputStream());
138
139 dynamicContent = DynamicCSSUtil.parseSass(
140 _servletContext, request, requestPath, content);
141
142 response.setContentType(ContentTypes.TEXT_CSS);
143
144 FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
145 }
146 else if (requestPath.endsWith(_JSP_EXTENSION)) {
147 if (_log.isInfoEnabled()) {
148 _log.info("Parsing SASS on JSP or servlet " + requestPath);
149 }
150
151 BufferCacheServletResponse bufferCacheServletResponse =
152 new BufferCacheServletResponse(response);
153
154 processFilter(
155 DynamicCSSFilter.class, request, bufferCacheServletResponse,
156 filterChain);
157
158 bufferCacheServletResponse.finishResponse();
159
160 content = bufferCacheServletResponse.getString();
161
162 dynamicContent = DynamicCSSUtil.parseSass(
163 _servletContext, request, requestPath, content);
164
165 FileUtil.write(
166 cacheContentTypeFile,
167 bufferCacheServletResponse.getContentType());
168 }
169 else {
170 return null;
171 }
172 }
173 catch (Exception e) {
174 _log.error("Unable to parse SASS on CSS " + requestPath, e);
175
176 if (_log.isDebugEnabled()) {
177 _log.debug(content);
178 }
179
180 response.setHeader(
181 HttpHeaders.CACHE_CONTROL,
182 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
183 }
184
185 if (dynamicContent != null) {
186 FileUtil.write(cacheDataFile, dynamicContent);
187 }
188 else {
189 dynamicContent = content;
190 }
191
192 return dynamicContent;
193 }
194
195 @Override
196 protected void processFilter(
197 HttpServletRequest request, HttpServletResponse response,
198 FilterChain filterChain)
199 throws Exception {
200
201 Object parsedContent = getDynamicContent(
202 request, response, filterChain);
203
204 if (parsedContent == null) {
205 processFilter(
206 DynamicCSSFilter.class, request, response, filterChain);
207 }
208 else {
209 if (parsedContent instanceof File) {
210 ServletResponseUtil.write(response, (File)parsedContent);
211 }
212 else if (parsedContent instanceof String) {
213 ServletResponseUtil.write(response, (String)parsedContent);
214 }
215 }
216 }
217
218 protected String sterilizeQueryString(String queryString) {
219 return StringUtil.replace(
220 queryString, new String[] {StringPool.SLASH, StringPool.BACK_SLASH},
221 new String[] {StringPool.UNDERLINE, StringPool.UNDERLINE});
222 }
223
224 private static final String _CSS_EXTENSION = ".css";
225
226 private static final String _JSP_EXTENSION = ".jsp";
227
228 private static final String _TEMP_DIR = "css";
229
230 private static Log _log = LogFactoryUtil.getLog(DynamicCSSFilter.class);
231
232 private ServletContext _servletContext;
233 private File _tempDir;
234
235 }