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