Author: markt
Date: Thu Apr 16 19:31:57 2009
New Revision: 765727

URL: http://svn.apache.org/viewvc?rev=765727&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=46538
ETag must vary between compressed and uncompressed versions.
Based on a patch by Oliver Schoett

Modified:
    tomcat/trunk/java/org/apache/coyote/http11/Constants.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
    tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java

Modified: tomcat/trunk/java/org/apache/coyote/http11/Constants.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Constants.java?rev=765727&r1=765726&r2=765727&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Constants.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Constants.java Thu Apr 16 
19:31:57 2009
@@ -148,7 +148,10 @@
         ByteChunk.convertToBytes("400");
     public static final byte[] _404_BYTES = 
         ByteChunk.convertToBytes("404");
-    
+    public static final String VARY = "Vary";
+    public static final String VARY_UNSPECIFIED = "*";
+    public static final String ACCEPT_ENCODING = "Accept-Encoding";
+    public static final String ETAG = "ETag";
 
     /**
      * Identity filters (input and output).

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java?rev=765727&r1=765726&r2=765727&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11AprProcessor.java Thu Apr 
16 19:31:57 2009
@@ -1486,16 +1486,9 @@
 
 
     /**
-     * Check for compression
+     * Check if browser allows compression
      */
-    private boolean isCompressable() {
-
-        // Nope Compression could works in HTTP 1.0 also
-        // cf: mod_deflate
-
-        // Compression only since HTTP 1.1
-        // if (! http11)
-        //    return false;
+    private boolean isCompressableBrowser() {
 
         // Check if browser support gzip encoding
         MessageBytes acceptEncodingMB =
@@ -1505,15 +1498,7 @@
             || (acceptEncodingMB.indexOf("gzip") == -1))
             return false;
 
-        // Check if content is not allready gzipped
-        MessageBytes contentEncodingMB =
-            response.getMimeHeaders().getValue("Content-Encoding");
-
-        if ((contentEncodingMB != null)
-            && (contentEncodingMB.indexOf("gzip") != -1))
-            return false;
-
-        // If force mode, allways compress (test purposes only)
+        // If force mode, always compress (test purposes only)
         if (compressionLevel == 2)
            return true;
 
@@ -1530,8 +1515,23 @@
                         return false;
             }
         }
+        return true;
+    }
+    
+    /*
+     * Check if response allows compression
+     */
+    private boolean isCompressableResponse() {
+        
+        // Check if content is not already gzipped
+        MessageBytes contentEncodingMB =
+            response.getMimeHeaders().getValue("Content-Encoding");
 
-        // Check if suffisant len to trig the compression
+        if ((contentEncodingMB != null)
+            && (contentEncodingMB.indexOf("gzip") != -1))
+            return false;
+
+        // Check if sufficient length to trigger the compression
         long contentLength = response.getContentLengthLong();
         if ((contentLength == -1)
             || (contentLength > compressionMinSize)) {
@@ -1598,18 +1598,35 @@
                     ((Long) 
request.getAttribute("org.apache.tomcat.sendfile.end")).longValue();
             }
         }
-        
+
+        MimeHeaders headers = response.getMimeHeaders();
+
         // Check for compression
         boolean useCompression = false;
         if (entityBody && (compressionLevel > 0) && (sendfileData == null)) {
-            useCompression = isCompressable();
+            if (isCompressableResponse()) {
+                // Always send the Vary header when response could be 
compressed
+                MessageBytes varyHeader = headers.getValue(Constants.VARY);
+                if (varyHeader == null) {
+                    headers.addValue(Constants.VARY).setString(
+                            Constants.ACCEPT_ENCODING);
+                } else {
+                    if (varyHeader.indexOf(Constants.ACCEPT_ENCODING) == -1 &&
+                            !varyHeader.equals(Constants.VARY_UNSPECIFIED)) {
+                        varyHeader.setString(varyHeader.toString() + "," +
+                                Constants.ACCEPT_ENCODING);
+                    }
+                }
+            }            
+            
+            useCompression = isCompressableBrowser();
+            
             // Change content-length to -1 to force chunking
             if (useCompression) {
                 response.setContentLength(-1);
             }
         }
 
-        MimeHeaders headers = response.getMimeHeaders();
         if (!entityBody) {
             response.setContentLength(-1);
         } else {
@@ -1645,8 +1662,22 @@
         if (useCompression) {
             outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
             headers.setValue("Content-Encoding").setString("gzip");
-            // Make Proxies happy via Vary (from mod_deflate)
-            headers.setValue("Vary").setString("Accept-Encoding");
+            
+            // Ensure eTag for compressed content is different to eTag for
+            // uncompressed content
+            MessageBytes eTagHeader = headers.getValue(Constants.ETAG);
+            if (eTagHeader != null) {
+                String eTag = eTagHeader.toString();
+                int len = eTag.length();
+                if (len > 1 && eTag.charAt(len - 1) == '"') {
+                    // Add compression marker before closing quote
+                    eTag = eTag.substring(0, len -1) + "-gz\"";
+                } else {
+                    // Unquoted ETag - shouldn't happen - TODO complain
+                    eTag = eTag + "-gz";
+                }
+                eTagHeader.setString(eTag);
+            }
         }
 
         // Add date header

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java?rev=765727&r1=765726&r2=765727&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11NioProcessor.java Thu Apr 
16 19:31:57 2009
@@ -1529,16 +1529,9 @@
 
 
     /**
-     * Check for compression
+     * Check if browser allows compression
      */
-    private boolean isCompressable() {
-
-        // Nope Compression could works in HTTP 1.0 also
-        // cf: mod_deflate
-
-        // Compression only since HTTP 1.1
-        // if (! http11)
-        //    return false;
+    private boolean isCompressableBrowser() {
 
         // Check if browser support gzip encoding
         MessageBytes acceptEncodingMB =
@@ -1548,15 +1541,7 @@
             || (acceptEncodingMB.indexOf("gzip") == -1))
             return false;
 
-        // Check if content is not allready gzipped
-        MessageBytes contentEncodingMB =
-            response.getMimeHeaders().getValue("Content-Encoding");
-
-        if ((contentEncodingMB != null)
-            && (contentEncodingMB.indexOf("gzip") != -1))
-            return false;
-
-        // If force mode, allways compress (test purposes only)
+        // If force mode, always compress (test purposes only)
         if (compressionLevel == 2)
            return true;
 
@@ -1573,8 +1558,23 @@
                         return false;
             }
         }
+        return true;
+    }
+    
+    /*
+     * Check if response allows compression
+     */
+    private boolean isCompressableResponse() {
+        
+        // Check if content is not already gzipped
+        MessageBytes contentEncodingMB =
+            response.getMimeHeaders().getValue("Content-Encoding");
 
-        // Check if suffisant len to trig the compression
+        if ((contentEncodingMB != null)
+            && (contentEncodingMB.indexOf("gzip") != -1))
+            return false;
+
+        // Check if sufficient length to trigger the compression
         long contentLength = response.getContentLengthLong();
         if ((contentLength == -1)
             || (contentLength > compressionMinSize)) {
@@ -1639,19 +1639,33 @@
             }
         }
 
-
+        MimeHeaders headers = response.getMimeHeaders();
 
         // Check for compression
         boolean useCompression = false;
         if (entityBody && (compressionLevel > 0) && (sendfileData == null)) {
-            useCompression = isCompressable();
+            if (isCompressableResponse()) {
+                // Always send the Vary header when response could be 
compressed
+                MessageBytes varyHeader = headers.getValue(Constants.VARY);
+                if (varyHeader == null) {
+                    headers.addValue(Constants.VARY).setString(
+                            Constants.ACCEPT_ENCODING);
+                } else {
+                    if (varyHeader.indexOf(Constants.ACCEPT_ENCODING) == -1 &&
+                            !varyHeader.equals(Constants.VARY_UNSPECIFIED)) {
+                        varyHeader.setString(varyHeader.toString() + "," +
+                                Constants.ACCEPT_ENCODING);
+                    }
+                }
+            }
+            useCompression = isCompressableBrowser();
+            
             // Change content-length to -1 to force chunking
             if (useCompression) {
                 response.setContentLength(-1);
             }
         }
 
-        MimeHeaders headers = response.getMimeHeaders();
         if (!entityBody) {
             response.setContentLength(-1);
         } else {
@@ -1687,8 +1701,22 @@
         if (useCompression) {
             outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
             headers.setValue("Content-Encoding").setString("gzip");
-            // Make Proxies happy via Vary (from mod_deflate)
-            headers.setValue("Vary").setString("Accept-Encoding");
+            
+            // Ensure eTag for compressed content is different to eTag for
+            // uncompressed content
+            MessageBytes eTagHeader = headers.getValue(Constants.ETAG);
+            if (eTagHeader != null) {
+                String eTag = eTagHeader.toString();
+                int len = eTag.length();
+                if (len > 1 && eTag.charAt(len - 1) == '"') {
+                    // Add compression marker before closing quote
+                    eTag = eTag.substring(0, len -1) + "-gz\"";
+                } else {
+                    // Unquoted ETag - shouldn't happen - TODO complain
+                    eTag = eTag + "-gz";
+                }
+                eTagHeader.setString(eTag);
+            }
         }
 
         // Add date header

Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java?rev=765727&r1=765726&r2=765727&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11Processor.java Thu Apr 16 
19:31:57 2009
@@ -1399,16 +1399,9 @@
 
 
     /**
-     * Check for compression
+     * Check if browser allows compression
      */
-    private boolean isCompressable() {
-
-        // Nope Compression could works in HTTP 1.0 also
-        // cf: mod_deflate
-
-        // Compression only since HTTP 1.1
-        // if (! http11)
-        //    return false;
+    private boolean isCompressableBrowser() {
 
         // Check if browser support gzip encoding
         MessageBytes acceptEncodingMB =
@@ -1418,15 +1411,7 @@
             || (acceptEncodingMB.indexOf("gzip") == -1))
             return false;
 
-        // Check if content is not allready gzipped
-        MessageBytes contentEncodingMB =
-            response.getMimeHeaders().getValue("Content-Encoding");
-
-        if ((contentEncodingMB != null)
-            && (contentEncodingMB.indexOf("gzip") != -1))
-            return false;
-
-        // If force mode, allways compress (test purposes only)
+        // If force mode, always compress (test purposes only)
         if (compressionLevel == 2)
            return true;
 
@@ -1443,8 +1428,23 @@
                         return false;
             }
         }
+        return true;
+    }
+    
+    /*
+     * Check if response allows compression
+     */
+    private boolean isCompressableResponse() {
+        
+        // Check if content is not already gzipped
+        MessageBytes contentEncodingMB =
+            response.getMimeHeaders().getValue("Content-Encoding");
 
-        // Check if suffisant len to trig the compression
+        if ((contentEncodingMB != null)
+            && (contentEncodingMB.indexOf("gzip") != -1))
+            return false;
+
+        // Check if sufficient length to trigger the compression
         long contentLength = response.getContentLengthLong();
         if ((contentLength == -1)
             || (contentLength > compressionMinSize)) {
@@ -1495,18 +1495,34 @@
             contentDelimitation = true;
         }
 
+        MimeHeaders headers = response.getMimeHeaders();
+
         // Check for compression
         boolean useCompression = false;
         if (entityBody && (compressionLevel > 0)) {
-            useCompression = isCompressable();
-
+            if (isCompressableResponse()) {
+                // Always send the Vary header when response could be 
compressed
+                MessageBytes varyHeader = headers.getValue(Constants.VARY);
+                if (varyHeader == null) {
+                    headers.addValue(Constants.VARY).setString(
+                            Constants.ACCEPT_ENCODING);
+                } else {
+                    if (varyHeader.indexOf(Constants.ACCEPT_ENCODING) == -1 &&
+                        !varyHeader.equals(Constants.VARY_UNSPECIFIED)) {
+                        varyHeader.setString(varyHeader.toString() + "," +
+                                Constants.ACCEPT_ENCODING);
+                    }
+                }
+            }
+            
+            useCompression = isCompressableBrowser();
+            
             // Change content-length to -1 to force chunking
             if (useCompression) {
                 response.setContentLength(-1);
             }
         }
 
-        MimeHeaders headers = response.getMimeHeaders();
         if (!entityBody) {
             response.setContentLength(-1);
         } else {
@@ -1542,8 +1558,22 @@
         if (useCompression) {
             outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
             headers.setValue("Content-Encoding").setString("gzip");
-            // Make Proxies happy via Vary (from mod_deflate)
-            headers.setValue("Vary").setString("Accept-Encoding");
+            
+            // Ensure eTag for compressed content is different to eTag for
+            // uncompressed content
+            MessageBytes eTagHeader = headers.getValue(Constants.ETAG);
+            if (eTagHeader != null) {
+                String eTag = eTagHeader.toString();
+                int len = eTag.length();
+                if (len > 1 && eTag.charAt(len - 1) == '"') {
+                    // Add compression marker before closing quote
+                    eTag = eTag.substring(0, len -1) + "-gz\"";
+                } else {
+                    // Unquoted ETag - shouldn't happen - TODO complain
+                    eTag = eTag + "-gz";
+                }
+                eTagHeader.setString(eTag);
+            }
         }
 
         // Add date header



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

Reply via email to