Author: markt
Date: Tue Jun 12 18:57:00 2012
New Revision: 1349473

URL: http://svn.apache.org/viewvc?rev=1349473&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50182
Various improvements to the compression filter example.
Patch by David Becker

Modified:
    
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
    
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
    
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
    
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
    tomcat/trunk/webapps/examples/WEB-INF/web.xml

Modified: 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java?rev=1349473&r1=1349472&r2=1349473&view=diff
==============================================================================
--- 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
 (original)
+++ 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilter.java
 Tue Jun 12 18:57:00 2012
@@ -14,11 +14,11 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-
 package compressionFilters;
 
 import java.io.IOException;
 import java.util.Enumeration;
+import java.util.StringTokenizer;
 
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
@@ -29,17 +29,14 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-
 /**
  * Implementation of <code>javax.servlet.Filter</code> used to compress
  * the ServletResponse if it is bigger than a threshold.
  *
  * @author Amy Roh
  * @author Dmitri Valdin
- * @version $Id$
  */
-
-public class CompressionFilter implements Filter{
+public class CompressionFilter implements Filter {
 
     /**
      * The filter configuration object we are associated with.  If this value
@@ -48,18 +45,32 @@ public class CompressionFilter implement
     private FilterConfig config = null;
 
     /**
-     * Minimal reasonable threshold
+     * Minimal reasonable threshold.
      */
     private int minThreshold = 128;
 
+    /**
+     * The threshold number to compress.
+     */
+    protected int compressionThreshold = 0;
+
+    /**
+     * Minimal reasonable buffer.
+     */
+    private int minBuffer = 8192;  // 8KB is what tomcat would use by default 
anyway
+
+    /**
+     * The compression buffer size to avoid chunking.
+     */
+    protected int compressionBuffer = 0;
 
     /**
-     * The threshold number to compress
+     * The mime types to compress.
      */
-    protected int compressionThreshold;
+    protected String[] compressionMimeTypes = {"text/html", "text/xml", 
"text/plain"};
 
     /**
-     * Debug level for this filter
+     * Debug level for this filter.
      */
     private int debug = 0;
 
@@ -68,7 +79,6 @@ public class CompressionFilter implement
      *
      * @param filterConfig The filter configuration object
      */
-
     @Override
     public void init(FilterConfig filterConfig) {
 
@@ -77,9 +87,8 @@ public class CompressionFilter implement
             String value = filterConfig.getInitParameter("debug");
             if (value!=null) {
                 debug = Integer.parseInt(value);
-            } else {
-                debug = 0;
             }
+
             String str = filterConfig.getInitParameter("compressionThreshold");
             if (str!=null) {
                 compressionThreshold = Integer.parseInt(str);
@@ -90,12 +99,33 @@ public class CompressionFilter implement
                     }
                     compressionThreshold = minThreshold;
                 }
-            } else {
-                compressionThreshold = 0;
             }
 
-        } else {
-            compressionThreshold = 0;
+            str = filterConfig.getInitParameter("compressionBuffer");
+            if (str!=null) {
+                compressionBuffer = Integer.parseInt(str);
+                if (compressionBuffer < minBuffer) {
+                    if (debug > 0) {
+                        System.out.println("compressionBuffer should be >= " + 
minBuffer);
+                        System.out.println("compressionBuffer set to " + 
minBuffer);
+                    }
+                    compressionBuffer = minBuffer;
+                }
+            }
+
+            str = filterConfig.getInitParameter("compressionMimeTypes");
+            if (str!=null) {
+                compressionMimeTypes = null;
+                StringTokenizer st = new StringTokenizer(str, ",");
+
+                while (st.hasMoreTokens()) {
+                    compressionMimeTypes = 
addStringArray(compressionMimeTypes, st.nextToken().trim());
+                }
+
+                if (debug > 0) {
+                    System.out.println("compressionMimeTypes set to " + 
compressionMimeTypes);
+                }
+            }
         }
 
     }
@@ -126,7 +156,6 @@ public class CompressionFilter implement
      * It then invokes the next entity in the chain using the FilterChain 
object
      * (<code>chain.doFilter()</code>), <br>
      **/
-
     @Override
     public void doFilter ( ServletRequest request, ServletResponse response,
                         FilterChain chain ) throws IOException, 
ServletException {
@@ -137,7 +166,7 @@ public class CompressionFilter implement
 
         if (compressionThreshold == 0) {
             if (debug > 0) {
-                System.out.println("doFilter gets called, but 
compressionTreshold is set to 0 - no compression");
+                System.out.println("doFilter got called, but 
compressionTreshold is set to 0 - no compression");
             }
             chain.doFilter(request, response);
             return;
@@ -170,33 +199,35 @@ public class CompressionFilter implement
                     supportCompression = true;
                 } else {
                     if (debug > 0) {
-                        System.out.println("no support for compresion");
+                        System.out.println("no support for compression");
                     }
                 }
             }
         }
 
-        if (!supportCompression) {
-            if (debug > 0) {
-                System.out.println("doFilter gets called wo compression");
+        if (supportCompression) {
+            if (response instanceof HttpServletResponse) {
+                CompressionServletResponseWrapper wrappedResponse =
+                    new 
CompressionServletResponseWrapper((HttpServletResponse)response);
+                wrappedResponse.setDebugLevel(debug);
+                wrappedResponse.setCompressionThreshold(compressionThreshold);
+                wrappedResponse.setCompressionBuffer(compressionBuffer);
+                wrappedResponse.setCompressionMimeTypes(compressionMimeTypes);
+                if (debug > 0) {
+                    System.out.println("doFilter gets called with 
compression");
+                }
+                try {
+                    chain.doFilter(request, wrappedResponse);
+                } finally {
+                    wrappedResponse.finishResponse();
+                }
+                return;
             }
-            chain.doFilter(request, response);
-            return;
-        }
-
-        if (response instanceof HttpServletResponse) {
-            CompressionServletResponseWrapper wrappedResponse =
-                new 
CompressionServletResponseWrapper((HttpServletResponse)response);
-            wrappedResponse.setDebugLevel(debug);
-            wrappedResponse.setCompressionThreshold(compressionThreshold);
+        } else {
             if (debug > 0) {
-                System.out.println("doFilter gets called with compression");
-            }
-            try {
-                chain.doFilter(request, wrappedResponse);
-            } finally {
-                wrappedResponse.finishResponse();
+                System.out.println("doFilter gets called w/o compression");
             }
+            chain.doFilter(request, response);
             return;
         }
     }
@@ -219,5 +250,26 @@ public class CompressionFilter implement
         return config;
     }
 
+    /**
+     * General use method
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private String[] addStringArray(String sArray[], String value) {
+        String[] result = null;
+        if (sArray == null) {
+            result = new String[1];
+            result[0] = value;
+        }
+        else {
+            result = new String[sArray.length + 1];
+            for (int i = 0; i < sArray.length; i++)
+                result[i] = sArray[i];
+            result[sArray.length] = value;
+        }
+        return result;
+    }
+
 }
 

Modified: 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java?rev=1349473&r1=1349472&r2=1349473&view=diff
==============================================================================
--- 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
 (original)
+++ 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionFilterTestServlet.java
 Tue Jun 12 18:57:00 2012
@@ -14,7 +14,6 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
-
 package compressionFilters;
 
 import java.io.IOException;
@@ -29,9 +28,7 @@ import javax.servlet.http.HttpServletRes
 /**
  * Very Simple test servlet to test compression filter
  * @author Amy Roh
- * @version $Id$
  */
-
 public class CompressionFilterTestServlet extends HttpServlet {
 
     private static final long serialVersionUID = 1L;
@@ -57,6 +54,11 @@ public class CompressionFilterTestServle
 
 
         out.println("Compression Filter Test Servlet");
+        out.println("Minimum content length for compression is 128 bytes");
+        out.println("**********  32 bytes  **********");
+        out.println("**********  32 bytes  **********");
+        out.println("**********  32 bytes  **********");
+        out.println("**********  32 bytes  **********");
         out.close();
     }
 

Modified: 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java?rev=1349473&r1=1349472&r2=1349473&view=diff
==============================================================================
--- 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
 (original)
+++ 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionResponseStream.java
 Tue Jun 12 18:57:00 2012
@@ -21,8 +21,6 @@ import java.io.OutputStream;
 import java.util.zip.GZIPOutputStream;
 
 import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServletResponse;
-
 
 /**
  * Implementation of <b>ServletOutputStream</b> that works with
@@ -30,28 +28,26 @@ import javax.servlet.http.HttpServletRes
  *
  * @author Amy Roh
  * @author Dmitri Valdin
- * @version $Id$
  */
-
-public class CompressionResponseStream
-    extends ServletOutputStream {
-
+public class CompressionResponseStream extends ServletOutputStream {
 
     // ----------------------------------------------------------- Constructors
 
-
     /**
      * Construct a servlet output stream associated with the specified 
Response.
      *
      * @param response The associated response
+     * @param response
+     * @param originalOutput
      */
-    public CompressionResponseStream(HttpServletResponse response) throws 
IOException{
+    public CompressionResponseStream(
+            CompressionServletResponseWrapper responseWrapper,
+            ServletOutputStream originalOutput) {
 
         super();
         closed = false;
-        this.response = response;
-        this.output = response.getOutputStream();
-
+        this.response = responseWrapper;
+        this.output = originalOutput;
     }
 
 
@@ -65,6 +61,16 @@ public class CompressionResponseStream
     protected int compressionThreshold = 0;
 
     /**
+     * The compression buffer size to avoid chunking
+     */
+    protected int compressionBuffer = 0;
+
+    /**
+     * The mime types to compress
+     */
+    protected String[] compressionMimeTypes = {"text/html", "text/xml", 
"text/plain"};
+
+    /**
      * Debug level
      */
     private int debug = 0;
@@ -98,10 +104,10 @@ public class CompressionResponseStream
     /**
      * The response with which this servlet output stream is associated.
      */
-    protected HttpServletResponse response = null;
+    protected CompressionServletResponseWrapper response = null;
 
     /**
-     * The underlying servket output stream to which we should write data.
+     * The underlying servlet output stream to which we should write data.
      */
     protected ServletOutputStream output = null;
 
@@ -119,11 +125,31 @@ public class CompressionResponseStream
     /**
      * Set the compressionThreshold number and create buffer for this size
      */
-    protected void setBuffer(int threshold) {
-        compressionThreshold = threshold;
-        buffer = new byte[compressionThreshold];
+    protected void setCompressionThreshold(int compressionThreshold) {
+        this.compressionThreshold = compressionThreshold;
+        buffer = new byte[this.compressionThreshold];
+        if (debug > 1) {
+            System.out.println("compressionThreshold is set to "+ 
this.compressionThreshold);
+        }
+    }
+
+    /**
+     * The compression buffer size to avoid chunking
+     */
+    protected void setCompressionBuffer(int compressionBuffer) {
+        this.compressionBuffer = compressionBuffer;
+        if (debug > 1) {
+            System.out.println("compressionBuffer is set to "+ 
this.compressionBuffer);
+        }
+    }
+
+    /**
+     * Set supported mime types
+     */
+    public void setCompressionMimeTypes(String[] compressionMimeTypes) {
+        this.compressionMimeTypes = compressionMimeTypes;
         if (debug > 1) {
-            System.out.println("buffer is set to "+compressionThreshold);
+            System.out.println("compressionMimeTypes is set to " + 
this.compressionMimeTypes);
         }
     }
 
@@ -301,22 +327,53 @@ public class CompressionResponseStream
             if (debug > 1) {
                 System.out.println("new GZIPOutputStream");
             }
+
+            boolean alreadyCompressed = false;
+            String contentEncoding = response.getHeader("Content-Encoding");
+            if (contentEncoding != null) {
+                if (contentEncoding.contains("gzip")) {
+                    alreadyCompressed = true;
+                    if (debug > 0) {
+                        System.out.println("content is already compressed");
+                    }
+                } else {
+                    if (debug > 0) {
+                        System.out.println("content is not compressed yet");
+                    }
+                }
+            }
+
+            boolean compressibleMimeType = false;
+            // Check for compatible MIME-TYPE
+            if (compressionMimeTypes != null) {
+                if (startsWithStringArray(compressionMimeTypes, 
response.getContentType())) {
+                    compressibleMimeType = true;
+                    if (debug > 0) {
+                        System.out.println("mime type " + 
response.getContentType() + " is compressible");
+                    }
+                } else {
+                    if (debug > 0) {
+                        System.out.println("mime type " + 
response.getContentType() + " is not compressible");
+                    }
+                }
+            }
+
             if (response.isCommitted()) {
                 if (debug > 1)
                     System.out.print("Response already committed. Using 
original output stream");
                 gzipstream = output;
+            } else if (alreadyCompressed) {
+                if (debug > 1)
+                    System.out.print("Response already compressed. Using 
original output stream");
+                gzipstream = output;
+            } else if (!compressibleMimeType) {
+                if (debug > 1)
+                    System.out.print("Response mime type is not compressible. 
Using original output stream");
+                gzipstream = output;
             } else {
                 response.addHeader("Content-Encoding", "gzip");
-                String vary = response.getHeader("Vary");
-                if (vary == null) {
-                    // Add a new Vary header
-                    response.setHeader("Vary", "Accept-Encoding");
-                } else if (vary.equals("*")) {
-                    // No action required
-                } else {
-                    // Merge into current header
-                    response.setHeader("Vary", vary + ",Accept-Encoding");
-                }
+                response.setContentLength(-1);  // don't use any preset 
content-length as it will be wrong after gzipping
+                response.setBufferSize(compressionBuffer);
                 gzipstream = new GZIPOutputStream(output);
             }
         }
@@ -337,4 +394,20 @@ public class CompressionResponseStream
 
     }
 
+    /**
+     * Checks if any entry in the string array starts with the specified value
+     *
+     * @param sArray the StringArray
+     * @param value string
+     */
+    private boolean startsWithStringArray(String sArray[], String value) {
+        if (value == null)
+           return false;
+        for (int i = 0; i < sArray.length; i++) {
+            if (value.startsWith(sArray[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

Modified: 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java?rev=1349473&r1=1349472&r2=1349473&view=diff
==============================================================================
--- 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
 (original)
+++ 
tomcat/trunk/webapps/examples/WEB-INF/classes/compressionFilters/CompressionServletResponseWrapper.java
 Tue Jun 12 18:57:00 2012
@@ -19,6 +19,8 @@ package compressionFilters;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletResponse;
@@ -30,10 +32,9 @@ import javax.servlet.http.HttpServletRes
  *
  * @author Amy Roh
  * @author Dmitri Valdin
- * @version $Id$
  */
-
-public class CompressionServletResponseWrapper extends 
HttpServletResponseWrapper {
+public class CompressionServletResponseWrapper
+        extends HttpServletResponseWrapper {
 
     // ----------------------------------------------------- Constructor
 
@@ -41,7 +42,6 @@ public class CompressionServletResponseW
      * Calls the parent constructor which creates a ServletResponse adaptor
      * wrapping the given response object.
      */
-
     public CompressionServletResponseWrapper(HttpServletResponse response) {
         super(response);
         origResponse = response;
@@ -59,6 +59,11 @@ public class CompressionServletResponseW
     protected HttpServletResponse origResponse = null;
 
     /**
+     * Descriptive information about this Response implementation.
+     */
+    protected static final String info = "GZipServletResponseWrapper";
+
+    /**
      * The ServletOutputStream that has been returned by
      * <code>getOutputStream()</code>, if any.
      */
@@ -74,44 +79,61 @@ public class CompressionServletResponseW
     /**
      * The threshold number to compress
      */
-    protected int threshold = 0;
+    protected int compressionThreshold = 0;
+
+    /**
+     * The compression buffer size
+     */
+    protected int compressionBuffer = 8192;  // 8KB default
+
+    /**
+     * The mime types to compress
+     */
+    protected String[] compressionMimeTypes = {"text/html", "text/xml", 
"text/plain"};
 
     /**
      * Debug level
      */
-    private int debug = 0;
+    protected int debug = 0;
 
     /**
-     * Content type
+     * keeps a copy of all headers set
      */
-    protected String contentType = null;
+    private Map<String,String> headerCopies = new HashMap<String,String>();
+
 
     // --------------------------------------------------------- Public Methods
 
 
     /**
-     * Set content type
+     * Set threshold number
      */
-    @Override
-    public void setContentType(String contentType) {
+    public void setCompressionThreshold(int threshold) {
         if (debug > 1) {
-            System.out.println("setContentType to "+contentType);
+            System.out.println("setCompressionThreshold to " + threshold);
         }
-        this.contentType = contentType;
-        origResponse.setContentType(contentType);
+        this.compressionThreshold = threshold;
     }
 
-
     /**
-     * Set threshold number
+     * Set compression buffer
      */
-    public void setCompressionThreshold(int threshold) {
+    public void setCompressionBuffer(int buffer) {
         if (debug > 1) {
-            System.out.println("setCompressionThreshold to " + threshold);
+            System.out.println("setCompressionBuffer to " + buffer);
         }
-        this.threshold = threshold;
+        this.compressionBuffer = buffer;
     }
 
+    /**
+     * Set compressible mime types
+     */
+    public void setCompressionMimeTypes(String[] mimeTypes) {
+        if (debug > 1) {
+            System.out.println("setCompressionMimeTypes to " + mimeTypes);
+        }
+        this.compressionMimeTypes = mimeTypes;
+    }
 
     /**
      * Set debug level
@@ -132,13 +154,14 @@ public class CompressionServletResponseW
             System.out.println("createOutputStream gets called");
         }
 
-        CompressionResponseStream compressedStream =
-            new CompressionResponseStream(origResponse);
-        compressedStream.setDebugLevel(debug);
-        compressedStream.setBuffer(threshold);
-
-        return compressedStream;
+        CompressionResponseStream stream = new CompressionResponseStream(
+                this, origResponse.getOutputStream());
+        stream.setDebugLevel(debug);
+        stream.setCompressionThreshold(compressionThreshold);
+        stream.setCompressionBuffer(compressionBuffer);
+        stream.setCompressionMimeTypes(compressionMimeTypes);
 
+        return stream;
     }
 
 
@@ -170,7 +193,7 @@ public class CompressionServletResponseW
     @Override
     public void flushBuffer() throws IOException {
         if (debug > 1) {
-            System.out.println("flush buffer @ 
CompressionServletResponseWrapper");
+            System.out.println("flush buffer @ GZipServletResponseWrapper");
         }
         ((CompressionResponseStream)stream).flush();
 
@@ -219,7 +242,6 @@ public class CompressionServletResponseW
         if (debug > 1) {
             System.out.println("stream is set to "+stream+" in getWriter");
         }
-        //String charset = getCharsetFromContentType(contentType);
         String charEnc = origResponse.getCharacterEncoding();
         if (debug > 1) {
             System.out.println("character encoding is " + charEnc);
@@ -233,12 +255,27 @@ public class CompressionServletResponseW
         }
 
         return (writer);
+    }
 
+    @Override
+    public String getHeader(String name) {
+        return headerCopies.get(name);
     }
 
     @Override
-    public void setContentLength(int length) {
-        // Don't, as compression will change it
+    public void addHeader(String name, String value) {
+        if (headerCopies.containsKey(name)) {
+            String existingValue = headerCopies.get(name);
+            if ((existingValue != null) && (existingValue.length() > 0)) 
headerCopies.put(name, existingValue + "," + value);
+            else headerCopies.put(name, value);
+        } else headerCopies.put(name, value);
+        super.addHeader(name, value);
     }
 
+
+    @Override
+    public void setHeader(String name, String value) {
+        headerCopies.put(name, value);
+        super.setHeader(name, value);
+    }
 }

Modified: tomcat/trunk/webapps/examples/WEB-INF/web.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/web.xml?rev=1349473&r1=1349472&r2=1349473&view=diff
==============================================================================
--- tomcat/trunk/webapps/examples/WEB-INF/web.xml (original)
+++ tomcat/trunk/webapps/examples/WEB-INF/web.xml Tue Jun 12 18:57:00 2012
@@ -60,10 +60,17 @@
     <filter>
         <filter-name>Compression Filter</filter-name>
         <filter-class>compressionFilters.CompressionFilter</filter-class>
-
         <init-param>
-          <param-name>compressionThreshold</param-name>
-          <param-value>10</param-value>
+            <param-name>compressionThreshold</param-name>
+            <param-value>128</param-value>
+        </init-param>
+        <init-param>
+            <param-name>compressionBuffer</param-name>
+            <param-value>8192</param-value>
+        </init-param>
+        <init-param>
+            <param-name>compressionMimeTypes</param-name>
+            <param-value>text/html,text/plain,text/xml</param-value>
         </init-param>
         <init-param>
           <param-name>debug</param-name>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to