You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@click.apache.org by sa...@apache.org on 2009/06/05 19:48:28 UTC

svn commit: r782077 - in /incubator/click/trunk/click/extras/src/org/apache/click/extras/filter: CompressionFilter.java CompressionResponseStream.java CompressionServletResponseWrapper.java PerformanceFilter.java

Author: sabob
Date: Fri Jun  5 17:48:27 2009
New Revision: 782077

URL: http://svn.apache.org/viewvc?rev=782077&view=rev
Log:
improved compression to handle included requests. CLK-557

Modified:
    incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionFilter.java
    incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionResponseStream.java
    incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionServletResponseWrapper.java
    incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/PerformanceFilter.java

Modified: incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionFilter.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionFilter.java?rev=782077&r1=782076&r2=782077&view=diff
==============================================================================
--- incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionFilter.java (original)
+++ incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionFilter.java Fri Jun  5 17:48:27 2009
@@ -1,18 +1,18 @@
 /*
-* Copyright 2004 The Apache Software Foundation
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.click.extras.filter;
 
 import java.io.IOException;
@@ -120,13 +120,13 @@
      * It then invokes the next entity in the chain using the FilterChain object
      * (<code>chain.doFilter()</code>)
      *
-     * @param request the servlet request
-     * @param response the servlet response
+     * @param servletRequest the servlet request
+     * @param servletResponse the servlet response
      * @param chain the filter chain
      * @throws IOException if an I/O error occurs
      * @throws ServletException if a servlet error occurs
      */
-    public void doFilter(ServletRequest request, ServletResponse response,
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
             FilterChain chain) throws IOException, ServletException {
 
         if (!configured) {
@@ -134,7 +134,7 @@
         }
 
         if (compressionThreshold == 0) {
-            chain.doFilter(request, response);
+            chain.doFilter(servletRequest, servletResponse);
             return;
         }
 
@@ -143,7 +143,7 @@
         String charset = getConfigService().getCharset();
         if (charset != null) {
             try {
-                request.setCharacterEncoding(charset);
+                servletRequest.setCharacterEncoding(charset);
 
             } catch (UnsupportedEncodingException ex) {
                 String msg =
@@ -152,43 +152,26 @@
             }
         }
 
-        if (request instanceof HttpServletRequest) {
+        final HttpServletRequest request = (HttpServletRequest) servletRequest;
+        final HttpServletResponse response = (HttpServletResponse) servletResponse;
 
-            // Are we allowed to compress ?
-            String s = ((HttpServletRequest) request).getParameter("gzip");
-            if ("false".equals(s)) {
-                chain.doFilter(request, response);
-                return;
-            }
-
-            Enumeration e =
-                ((HttpServletRequest) request).getHeaders("Accept-Encoding");
-
-            while (e.hasMoreElements()) {
-                String name = (String) e.nextElement();
-                if (name.indexOf("gzip") != -1) {
-                    supportCompression = true;
-                }
-            }
-        }
+        final String path = ClickUtils.getResourcePath((HttpServletRequest) request);
+        supportCompression = useGzipCompression(request, response, path);
 
         if (!supportCompression) {
             chain.doFilter(request, response);
 
         } else {
-            if (response instanceof HttpServletResponse) {
 
-                HttpServletResponse hsr = (HttpServletResponse) response;
-                CompressionServletResponseWrapper wrappedResponse =
-                    new CompressionServletResponseWrapper(hsr);
-
-                wrappedResponse.setCompressionThreshold(compressionThreshold);
-
-                try {
-                    chain.doFilter(request, wrappedResponse);
-                } finally {
-                    wrappedResponse.finishResponse();
-                }
+            CompressionServletResponseWrapper wrappedResponse =
+                new CompressionServletResponseWrapper(response, request);
+
+            wrappedResponse.setCompressionThreshold(compressionThreshold);
+
+            try {
+                chain.doFilter(request, wrappedResponse);
+            } finally {
+                wrappedResponse.finishResponse();
             }
         }
     }
@@ -215,6 +198,46 @@
     // ------------------------------------------------------ Protected Methods
 
     /**
+     * Return true if the response should be GZIP compressed.
+     *
+     * @param request the request to test
+     * @param response the response to test
+     * @param path the request path to test
+     * @return true if the response should be GZIP compressed
+     */
+    protected boolean useGzipCompression(HttpServletRequest request,
+        HttpServletResponse response, String path) {
+
+        // If Content-Encoding header is already set on response, skip compression
+        if (response.containsHeader("Content-Encoding")) {
+            return false;
+        }
+
+        // Are we allowed to compress ?
+        String s = ((HttpServletRequest) request).getParameter("gzip");
+        if ("false".equals(s)) {
+            return false;
+        }
+
+        if (compressionThreshold > 0) {
+            if (path.endsWith(".gif") || path.endsWith(".png") || path.endsWith(".jpg")) {
+                return false;
+            }
+
+            Enumeration e = request.getHeaders("Accept-Encoding");
+
+            while (e.hasMoreElements()) {
+                String name = (String) e.nextElement();
+                if (name.indexOf("gzip") != -1) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
      * Return the application configuration service.
      *
      * @return the application configuration service

Modified: incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionResponseStream.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionResponseStream.java?rev=782077&r1=782076&r2=782077&view=diff
==============================================================================
--- incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionResponseStream.java (original)
+++ incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionResponseStream.java Fri Jun  5 17:48:27 2009
@@ -1,25 +1,26 @@
 /*
-* Copyright 2004 The Apache Software Foundation
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.click.extras.filter;
 
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.zip.GZIPOutputStream;
 
 import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
@@ -35,23 +36,6 @@
  */
 public class CompressionResponseStream extends ServletOutputStream {
 
-    // ----------------------------------------------------------- Constructors
-
-    /**
-     * Construct a servlet output stream associated with the specified Response.
-     *
-     * @param response The associated response
-     * @throws IOException if an IO error occurs reading the response stream
-     */
-    public CompressionResponseStream(HttpServletResponse response)
-        throws IOException {
-
-        super();
-        closed = false;
-        this.response = response;
-        this.output = response.getOutputStream();
-    }
-
     // ----------------------------------------------------- Instance Variables
 
     /**
@@ -74,7 +58,7 @@
     /**
      * The underlying gzip output stream to which we should write data.
      */
-    protected GZIPOutputStream gzipstream = null;
+    protected OutputStream gzipstream = null;
 
     /** Has this stream been closed? */
     protected boolean closed = false;
@@ -85,15 +69,36 @@
      */
     protected int length = -1;
 
+    /** The response with which this servlet output stream is associated. */
+    protected HttpServletResponse response = null;
+
+    /** The request with which this servlet is associated. */
+    protected HttpServletRequest request;
+
     /**
-     * The response with which this servlet output stream is associated.
+     * The underlying output stream, either gzipped or servlet, to which we
+     * should write data.
      */
-    protected HttpServletResponse response = null;
+    protected OutputStream output = null;
+
+    // ----------------------------------------------------------- Constructors
 
     /**
-     * The underlying servket output stream to which we should write data.
+     * Construct a servlet output stream associated with the specified Response.
+     *
+     * @param response The associated response
+     * @param request The associated request
+     * @throws IOException if an IO error occurs reading the response stream
      */
-    protected ServletOutputStream output = null;
+    public CompressionResponseStream(HttpServletResponse response,
+        HttpServletRequest request) throws IOException {
+
+        super();
+        this.closed = false;
+        this.response = response;
+        this.request = request;
+        this.output = response.getOutputStream();
+    }
 
     // --------------------------------------------------------- Public Methods
 
@@ -108,35 +113,41 @@
     }
 
     /**
-     * Close this output stream, causing any buffered data to be flushed and
-     * any further output data to throw an IOException.
+     * Close this output stream, causing any buffered data to be flushed.
+     * Consecutive calls to this method will be ignored.
      *
      * @throws IOException if an error occurs closing the response
      */
     public void close() throws IOException {
 
-        if (closed) {
-            throw new IOException("This output stream has already been closed");
-        }
+        if (!closed) {
 
-        if (gzipstream != null) {
-            flushToGZip();
-            gzipstream.close();
-            gzipstream = null;
-        } else {
-            if (bufferCount > 0) {
-                if (debug > 2) {
-                    System.out.print("output.write(");
-                    System.out.write(buffer, 0, bufferCount);
-                    System.out.println(")");
+            // Don't close if this is a server side include
+            if (request.getAttribute("javax.servlet.include.request_uri") != null) {
+                flush();
+
+            } else {
+                if (gzipstream != null) {
+                    flushToGZip();
+                    gzipstream.close();
+                    gzipstream = null;
+                } else {
+                    if (bufferCount > 0) {
+                        if (debug > 2) {
+                            System.out.print("output.write(");
+                            System.out.write(buffer, 0, bufferCount);
+                            System.out.println(")");
+                        }
+                        output.write(buffer, 0, bufferCount);
+                        bufferCount = 0;
+                    }
                 }
-                output.write(buffer, 0, bufferCount);
-                bufferCount = 0;
+
+                output.close();
+                output = null;
+                closed = true;
             }
         }
-
-        output.close();
-        closed = true;
     }
 
     /**
@@ -147,12 +158,11 @@
      */
     public void flush() throws IOException {
 
-        if (closed) {
-            throw new IOException("Cannot flush a closed output stream");
-        }
+        if (!closed) {
 
-        if (gzipstream != null) {
-            gzipstream.flush();
+            if (gzipstream != null) {
+                gzipstream.flush();
+            }
         }
     }
 
@@ -240,7 +250,6 @@
         writeToGZip(b, off, len);
     }
 
-
     /**
      * Writes array of bytes to the compressed output stream. This method
      * will block until all the bytes are written.
@@ -248,20 +257,13 @@
      * @param b the data to be written
      * @param off the start offset of the data
      * @param len the length of the data
-     * @exception IOException If an I/O error has occurred.
+     * @throws IOException If an I/O error has occurred.
      */
     public void writeToGZip(byte b[], int off, int len) throws IOException {
-
-        if (gzipstream == null) {
-            response.addHeader("Content-Encoding", "gzip");
-            gzipstream = new GZIPOutputStream(output);
-        }
-
+        initializeGzip();
         gzipstream.write(b, off, len);
     }
 
-    // -------------------------------------------------------- Package Methods
-
     /**
      * Has this response stream been closed?
      *
@@ -271,4 +273,55 @@
         return (this.closed);
     }
 
+    // ------------------------------------------------------ Protected Methods
+
+    /**
+     * Initialize the GZip output stream.
+     * <p/>
+     * This method delgates to {@link #setContentEncodingGZip()} to set the
+     * GZip response Content-Encoding header.
+     *
+     * @throws IOException If an I/O error has occurred
+     */
+    protected void initializeGzip() throws IOException {
+
+        if (gzipstream == null) {
+
+            if (debug > 1) {
+                System.out.println("new GZIPOutputStream");
+            }
+
+            if (response.isCommitted()) {
+                if (debug > 1) {
+                    System.out.print("Response already committed. Using original"
+                        + " output stream");
+                }
+                gzipstream = output;
+            }
+            else if (setContentEncodingGZip()) {
+                // If we can set the Content-Encoding header to gzip, create a
+                // new gzip stream
+                gzipstream = new GZIPOutputStream(response.getOutputStream());
+            } else {
+                // If we cannot set the Content-Encoding header, use original
+                // output stream
+                gzipstream = output;
+            }
+        }
+    }
+
+    /**
+     * Set the "<tt>Content-Encoding</tt>" header of the response to
+     * "<tt>gzip</tt>", returning true if the header was set, false otherwise.
+     * <p/>
+     * This method will return false when it is invoked from a server side
+     * include (&lt;jsp:include&gt;), since its not possible to alter the headers
+     * of an included response.
+     *
+     * @return true if the content encoding was set, false otherwise
+     */
+    protected boolean setContentEncodingGZip() {
+        response.addHeader("Content-Encoding", "gzip");
+        return response.containsHeader("Content-Encoding");
+    }
 }

Modified: incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionServletResponseWrapper.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionServletResponseWrapper.java?rev=782077&r1=782076&r2=782077&view=diff
==============================================================================
--- incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionServletResponseWrapper.java (original)
+++ incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/CompressionServletResponseWrapper.java Fri Jun  5 17:48:27 2009
@@ -1,19 +1,18 @@
 /*
-* Copyright 2004 The Apache Software Foundation
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.click.extras.filter;
 
 import java.io.IOException;
@@ -21,6 +20,7 @@
 import java.io.PrintWriter;
 
 import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponseWrapper;
 
@@ -44,10 +44,12 @@
      * wrapping the given response object.
      *
      * @param response the servlet response to wrap
+     * @param request The associated request
      */
-    public CompressionServletResponseWrapper(HttpServletResponse response) {
+    public CompressionServletResponseWrapper(HttpServletResponse response, HttpServletRequest request) {
         super(response);
         origResponse = response;
+        origRequest = request;
     }
 
     // ----------------------------------------------------- Instance Variables
@@ -55,6 +57,9 @@
     /** Original response. */
     protected HttpServletResponse origResponse = null;
 
+    /** The request with which this servlet is associated. */
+    protected HttpServletRequest origRequest;
+
     /** Descriptive information about this Response implementation. */
     protected static final String INFO = "CompressionServletResponseWrapper";
 
@@ -110,7 +115,7 @@
     public ServletOutputStream createOutputStream() throws IOException {
 
         CompressionResponseStream stream =
-            new CompressionResponseStream(origResponse);
+            new CompressionResponseStream(origResponse, origRequest);
         stream.setBuffer(threshold);
 
         return stream;

Modified: incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/PerformanceFilter.java
URL: http://svn.apache.org/viewvc/incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/PerformanceFilter.java?rev=782077&r1=782076&r2=782077&view=diff
==============================================================================
--- incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/PerformanceFilter.java (original)
+++ incubator/click/trunk/click/extras/src/org/apache/click/extras/filter/PerformanceFilter.java Fri Jun  5 17:48:27 2009
@@ -378,10 +378,10 @@
         final boolean isVersionedResourcePath = (realPath.length() != path.length());
 
         // Apply response compression
-        if (useGzipCompression(request, path)) {
+        if (useGzipCompression(request, response, path)) {
 
             CompressionServletResponseWrapper wrappedResponse =
-                new CompressionServletResponseWrapper(response);
+                new CompressionServletResponseWrapper(response, request);
 
             wrappedResponse.setCompressionThreshold(compressionThreshold);
 
@@ -679,10 +679,17 @@
      * Return true if the response should be GZIP compressed.
      *
      * @param request the request to test
+     * @param response the response to test
      * @param path the request path to test
      * @return true if the response should be GZIP compressed
      */
-    protected boolean useGzipCompression(HttpServletRequest request, String path) {
+    protected boolean useGzipCompression(HttpServletRequest request,
+        HttpServletResponse response, String path) {
+
+        // If Content-Encoding header is already set on response, skip compression
+        if (response.containsHeader("Content-Encoding")) {
+            return false;
+        }
 
         if (compressionThreshold > 0) {
             if (path.endsWith(".gif") || path.endsWith(".png") || path.endsWith(".jpg")) {