Re: [Opensymphony-oscache] RE: CVS update: /oscache/src/core/java/com/opensymphony/oscache/web/filter/
Lars Torunski <[email protected]>
| Newsgroups | gmane.comp.java.open-symphony.os-cache |
|---|---|
| Message-ID | <[email protected]> |
- this is only the first step to support full gzip compression - this fix allows OSCache to support underlying gzip compression filters in the filter chain, so other gzip filters are plugable but - maybe a filter parameter is necessary to disable the gzip support - and browsers claim to handle gzip but can't, hence the browser check is missing http://httpd.apache.org/docs-2.0/mod/mod_deflate.html March, Andres wrote: >I didn't think that we came to agreement to how this should work. Are >we comfortable with how this is implemented? > > > >>-----Original Message----- >>From: [email protected] [mailto:[email protected]] >>Sent: Monday, March 21, 2005 2:30 PM >>To: [email protected] >>Subject: CVS update: >>/oscache/src/core/java/com/opensymphony/oscache/web/filter/ >> >>User: ltorunski >>Date: 2005/03/21 14:29:58 >> >>Log: >> Support of GZip filters in the filter chain >> Issue number: CACHE-155 >> Obtained from: Fernando Martins >> Submitted by: Lars Torunski >> >>File Changes: >> >>Directory: /oscache/src/core/java/com/opensymphony/oscache/web/filter/ >>====================================================================== >> >>File [changed]: CacheFilter.java >>Url: >> >> >> >https://oscache.dev.java.net/source/browse/oscache/src/core/java/com/ope >ns > > >>ymphony/oscache/web/filter/CacheFilter.java?r1=1.5&r2=1.6 >>Delta lines: +46 -36 >>--------------------- >>--- CacheFilter.java 22 Feb 2005 17:17:02 -0000 1.5 >>+++ CacheFilter.java 21 Mar 2005 22:29:55 -0000 1.6 >>@@ -26,15 +26,13 @@ >> * @author <a href="mailto:[email protected]">Serge Knystautas</a> >> * @author <a href="mailto:[email protected]">Mike >> >> >Cannon-Brookes</a> > > >> * @author <a href="mailto:[email protected]">Lars Torunski</a> >>- * @version $Revision: 1.5 $ >>+ * @version $Revision: 1.6 $ >> */ >> public class CacheFilter implements Filter { >>- >>- private final Log log = LogFactory.getLog(this.getClass()); >>- >> // Header >> public static final String HEADER_LAST_MODIFIED = >> >> >"Last-Modified"; > > >> public static final String HEADER_CONTENT_TYPE = "Content-Type"; >>+ public static final String HEADER_CONTENT_ENCODING = "Content- >>Encoding"; >> public static final String HEADER_EXPIRES = "Expires"; >> public static final String HEADER_IF_MODIFIED_SINCE = >> >> >"If-Modified- > > >>Since"; >> >>@@ -43,17 +41,19 @@ >> public static final int FRAGMENT_NO = 0; >> public static final int FRAGMENT_YES = 1; >> >>+ // request attribute to avoid reentrance >>+ private final static String REQUEST_FILTERED = >> >> >"__oscache_filtered"; > > >>+ >>+ // the policy for the expires header >>+ private static final ExpiresRefreshPolicy EXPIRES_REFRESH_POLICY >> >> >= > > >>new ExpiresRefreshPolicy(); >>+ private final Log log = LogFactory.getLog(this.getClass()); >>+ >> // filter variables >> private FilterConfig config; >> private ServletCacheAdministrator admin = null; >> private int cacheScope = PageContext.APPLICATION_SCOPE; // filter >>scope - default is APPLICATION >>- private int time = 60 * 60; // time before cache should be >> >> >refreshed > > >>- default one hour (in seconds) >> private int fragment = FRAGMENT_AUTODETECT; // defines if this >> >> >filter > > >>handles fragments of a page - default is auto detect >>- >>- // request attribute to avoid reentrance >>- private final static String REQUEST_FILTERED = >> >> >"__oscache_filtered"; > > >>- // the policy for the expires header >>- private static final ExpiresRefreshPolicy EXPIRES_REFRESH_POLICY >> >> >= > > >>new ExpiresRefreshPolicy(); >>+ private int time = 60 * 60; // time before cache should be >> >> >refreshed > > >>- default one hour (in seconds) >> >> /** >> * Filter clean-up >>@@ -84,6 +84,7 @@ >> chain.doFilter(request, response); >> return; >> } >>+ >> request.setAttribute(REQUEST_FILTERED, Boolean.TRUE); >> >> HttpServletRequest httpRequest = (HttpServletRequest) >> >> >request; > > >>@@ -96,6 +97,7 @@ >> >> // avoid useless session creation for application scope pages >>(CACHE-129) >> Cache cache; >>+ >> if (cacheScope == PageContext.SESSION_SCOPE) { >> cache = >>admin.getSessionScopeCache(httpRequest.getSession(true)); >> } else { >>@@ -109,19 +111,18 @@ >> log.info("<cache>: Using cached entry for " + key); >> } >> >>- // only reply with SC_NOT_MODIFIED >>- // if the client has already the newest page and the >> >> >reponse > > >>isn't a fragment in a page >> if (!fragmentRequest) { >> long clientLastModified = >>httpRequest.getDateHeader(HEADER_IF_MODIFIED_SINCE); // will return -1 >> >> >if > > >>no header... >> >>+ // only reply with SC_NOT_MODIFIED >>+ // if the client has already the newest page and the >>reponse isn't a fragment in a page >> if ((clientLastModified != -1) && (clientLastModified >>= >>respContent.getLastModified())) { >> ((HttpServletResponse) >>response).setStatus(HttpServletResponse.SC_NOT_MODIFIED); >> return; >> } >> } >> >>- respContent.writeTo(response, fragmentRequest); >>- >>+ respContent.writeTo(response, fragmentRequest, >>acceptsGZipEncoding(httpRequest)); >> } catch (NeedsRefreshException nre) { >> boolean updateSucceeded = false; >> >>@@ -194,6 +195,7 @@ >> >> try { >> fragment = >>Integer.parseInt(config.getInitParameter("fragment")); >>+ >> if ((fragment < FRAGMENT_AUTODETECT) || (fragment > >>FRAGMENT_YES)) { >> log.info("Wrong init parameter 'fragment', setting to >>'auto detect':" + fragment); >> fragment = FRAGMENT_AUTODETECT; >>@@ -201,7 +203,6 @@ >> } catch (Exception e) { >> log.info("Could not get init parameter 'fragment', >> >> >defaulting > > >>to 'auto detect'."); >> } >>- >> } >> >> /** >>@@ -226,7 +227,7 @@ >> * @param request the to be handled request >> * @return true if the request is a fragment in a page >> */ >>- public boolean isFragment(HttpServletRequest request) { >>+ protected boolean isFragment(HttpServletRequest request) { >> if (fragment == FRAGMENT_AUTODETECT) { >> return >>request.getAttribute("javax.servlet.include.request_uri") != null; >> } else { >>@@ -243,8 +244,17 @@ >> * @param request checks if the request was filtered before. >> * @return true if it is the first execution >> */ >>- public boolean isFilteredBefore(ServletRequest request) { >>+ protected boolean isFilteredBefore(ServletRequest request) { >> return request.getAttribute(REQUEST_FILTERED) != null; >> } >> >>+ /** >>+ * Check if the client browser support gzip compression. >>+ * @param request the http request >>+ * @return true if client browser supports GZIP >>+ */ >>+ protected boolean acceptsGZipEncoding(HttpServletRequest request) >> >> >{ > > >>+ String acceptEncoding = request.getHeader("Accept-Encoding"); >>+ return (acceptEncoding != null) && >>(acceptEncoding.indexOf("gzip") != -1); >>+ } >> } >> >>File [changed]: ResponseContent.java >>Url: >> >> >> >https://oscache.dev.java.net/source/browse/oscache/src/core/java/com/ope >ns > > >>ymphony/oscache/web/filter/ResponseContent.java?r1=1.3&r2=1.4 >>Delta lines: +59 -8 >>-------------------- >>--- ResponseContent.java 22 Feb 2005 17:17:02 -0000 1.3 >>+++ ResponseContent.java 21 Mar 2005 22:29:55 -0000 1.4 >>@@ -6,9 +6,14 @@ >> >> import java.io.*; >> >>+import java.util.Enumeration; >> import java.util.Locale; >>+import java.util.zip.GZIPInputStream; >>+import java.util.zip.ZipException; >> >>+import javax.servlet.ServletRequest; >> import javax.servlet.ServletResponse; >>+import javax.servlet.http.HttpServletRequest; >> import javax.servlet.http.HttpServletResponse; >> >> /** >>@@ -16,16 +21,17 @@ >> * in the cache (and, since this class is serializable, optionally >> * persisted to disk). >> * >>- * @version $Revision: 1.3 $ >>+ * @version $Revision: 1.4 $ >> * @author <a href="mailto:[email protected]">Serge Knystautas</a> >> */ >> public class ResponseContent implements Serializable { >> private transient ByteArrayOutputStream bout = new >>ByteArrayOutputStream(1000); >> private Locale locale = null; >>+ private String contentEncoding = null; >> private String contentType = null; >> private byte[] content = null; >>- private long lastModified = -1; >> private long expires = Long.MAX_VALUE; >>+ private long lastModified = -1; >> >> /** >> * Set the content type. We capture this so that when we serve >> >> >this > > >>@@ -43,6 +49,10 @@ >> lastModified = value; >> } >> >>+ public void setContentEncoding(String contentEncoding) { >>+ this.contentEncoding = contentEncoding; >>+ } >>+ >> /** >> * Set the Locale. We capture this so that when we serve this >> >> >data > > >>from >> * cache, we can set the correct locale on the response. >>@@ -100,7 +110,7 @@ >> * @throws IOException >> */ >> public void writeTo(ServletResponse response) throws IOException >> >> >{ > > >>- writeTo(response, false); >>+ writeTo(response, false, false); >> } >> >> /** >>@@ -108,27 +118,68 @@ >> * >> * @param response The servlet response to output the cached >> >> >content > > >>to. >> * @param fragment is true if this content a fragment or part of >> >> >a > > >>page >>+ * @param acceptsGZip is true if client browser supports gzip >>compression >> * @throws IOException >> */ >>- public void writeTo(ServletResponse response, boolean fragment) >>throws IOException { >>+ public void writeTo(ServletResponse response, boolean fragment, >>boolean acceptsGZip) throws IOException { >> //Send the content type and data to this response >> if (contentType != null) { >> response.setContentType(contentType); >> } >> >>+ // Don't support gzip compression if the content is a >> >> >fragment of > > >>a page >>+ if (fragment) { >>+ acceptsGZip = false; >>+ } >>+ >> // Don't add in the Last-Modified header in a fragment of a >> >> >page > > >> if ((!fragment) && (response instanceof HttpServletResponse)) >> >> >{ > > >> ((HttpServletResponse) >>response).setDateHeader(CacheFilter.HEADER_LAST_MODIFIED, >> >> >lastModified); > > >> } >> >>- response.setContentLength(content.length); >>- >> if (locale != null) { >> response.setLocale(locale); >> } >> >> OutputStream out = new >>BufferedOutputStream(response.getOutputStream()); >>+ >>+ if (isContentGZiped()) { >>+ if (acceptsGZip) { >>+ ((HttpServletResponse) response).addHeader("Content- >>Encoding", "gzip"); >>+ response.setContentLength(content.length); >>+ out.write(content); >>+ } else { >>+ // client doesn't support, so we have to uncompress >> >> >it > > >>+ ByteArrayInputStream bais = new >>ByteArrayInputStream(content); >>+ GZIPInputStream zis = new GZIPInputStream(bais); >>+ >>+ ByteArrayOutputStream baos = new >> >> >ByteArrayOutputStream(); > > >>+ int numBytesRead = 0; >>+ byte[] tempBytes = new byte[4196]; >>+ >>+ while ((numBytesRead = zis.read(tempBytes, 0, >>tempBytes.length)) != -1) { >>+ baos.write(tempBytes, 0, numBytesRead); >>+ } >>+ >>+ byte[] result = baos.toByteArray(); >>+ >>+ response.setContentLength(result.length); >>+ out.write(result); >>+ } >>+ } else { >>+ // the content isn't compressed >>+ // regardless if the client browser supports gzip we will >>just return the content >>+ response.setContentLength(content.length); >> out.write(content); >>+ } >> out.flush(); >>+ } >>+ >>+ >>+ /** >>+ * @return true if the content is GZIP compressed >>+ */ >>+ public boolean isContentGZiped() { >>+ return "gzip".equals(contentEncoding); >> } >> } >> >>File [changed]: CacheHttpServletResponseWrapper.java >>Url: >> >> >> >https://oscache.dev.java.net/source/browse/oscache/src/core/java/com/ope >ns > > >ymphony/oscache/web/filter/CacheHttpServletResponseWrapper.java?r1=1.6&r >2= > > >>1.7 >>Delta lines: +18 -9 >>-------------------- >>--- CacheHttpServletResponseWrapper.java 23 Feb 2005 17:55:29 >> >> >-0000 > > >> 1.6 >>+++ CacheHttpServletResponseWrapper.java 21 Mar 2005 22:29:55 >> >> >-0000 > > >> 1.7 >>@@ -20,7 +20,7 @@ >> * CacheServletResponse is a serialized representation of a response >> * >> * @author <a href="mailto:[email protected]">Serge Knystautas</a> >>- * @version $Revision: 1.6 $ >>+ * @version $Revision: 1.7 $ >> */ >> public class CacheHttpServletResponseWrapper extends >>HttpServletResponseWrapper { >> private final Log log = LogFactory.getLog(this.getClass()); >>@@ -32,8 +32,8 @@ >> private PrintWriter cachedWriter; >> private ResponseContent result = null; >> private SplitServletOutputStream cacheOut = null; >>- private int status = SC_OK; >> private boolean fragment = false; >>+ private int status = SC_OK; >> >> /** >> * Constructor >>@@ -77,6 +77,7 @@ >> if (log.isDebugEnabled()) { >> log.debug("ContentType: " + value); >> } >>+ >> super.setContentType(value); >> result.setContentType(value); >> } >>@@ -144,6 +145,10 @@ >> result.setContentType(value); >> } >> >>+ if >> >> >(CacheFilter.HEADER_CONTENT_ENCODING.equalsIgnoreCase(name)) { > > >>+ result.setContentEncoding(value); >>+ } >>+ >> super.setHeader(name, value); >> } >> >>@@ -162,6 +167,10 @@ >> result.setContentType(value); >> } >> >>+ if >> >> >(CacheFilter.HEADER_CONTENT_ENCODING.equalsIgnoreCase(name)) { > > >>+ result.setContentEncoding(value); >>+ } >>+ >> super.addHeader(name, value); >> } >> >> >> >> >> >>--------------------------------------------------------------------- >>To unsubscribe, e-mail: [email protected] >>For additional commands, e-mail: [email protected] >> >> > > >--------------------------------------------------------------------- >To unsubscribe, e-mail: [email protected] >For additional commands, e-mail: [email protected] > > > > >