]> granicus.if.org Git - apache/commitdiff
Reimplement deflate_check_etag() so that it isn't such a pig
authorRoy T. Fielding <fielding@apache.org>
Thu, 12 Feb 2009 01:59:27 +0000 (01:59 +0000)
committerRoy T. Fielding <fielding@apache.org>
Thu, 12 Feb 2009 01:59:27 +0000 (01:59 +0000)
and correctly works with weak etags.  Related to PR 39727.

Note that there remains an error in ap_meets_conditions because
that function does not currently check for a transformed etag.
I am working on that.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@743595 13f79535-47bb-0310-9956-ffa450edef68

modules/filters/mod_deflate.c

index b512c3b0177aa36b03fe7809c8a1704e8b84f842..2dbadfe006ef75db706860cb06993701de049907 100644 (file)
@@ -381,26 +381,43 @@ static apr_status_t deflate_ctx_cleanup(void *data)
         ctx->libz_end_func(&ctx->stream);
     return APR_SUCCESS;
 }
-/* PR 39727: we're screwing up our clients if we leave a strong ETag
- * header while transforming content.  Henrik Nordstrom suggests
- * appending ";gzip".
- *
- * Pending a more thorough review of our Etag handling, let's just
- * implement his suggestion.  It fixes the bug, or at least turns it
- * from a showstopper to an inefficiency.  And it breaks nothing that
- * wasn't already broken.
+
+/* ETag must be unique among the possible representations, so a change
+ * to content-encoding requires a corresponding change to the ETag.
+ * This routine appends -transform (e.g., -gzip) to the entity-tag
+ * value inside the double-quotes if an ETag has already been set
+ * and its value already contains double-quotes. PR 39727
  */
 static void deflate_check_etag(request_rec *r, const char *transform)
 {
     const char *etag = apr_table_get(r->headers_out, "ETag");
-    if ((etag && (strlen(etag) > 2))) {
-        if (etag[0] == '"') {
-            etag = apr_pstrndup(r->pool, etag, strlen(etag) - 1);
-            apr_table_set(r->headers_out, "ETag",
-                          apr_pstrcat(r->pool, etag, "-", transform, "\"", NULL));
+    apr_size_t etaglen;
+
+    if ((etag && ((etaglen = strlen(etag)) > 2))) {
+        if (etag[etaglen - 1] == '"') {
+            apr_size_t transformlen = strlen(transform);
+            char *newtag = apr_palloc(r->pool, etaglen + transformlen + 2);
+            char *d = newtag;
+            char *e = d + etaglen - 1;
+            const char *s = etag;
+
+            for (; d < e; ++d, ++s) {
+                *d = *s;          /* copy etag to newtag up to last quote */
+            }
+            *d++ = '-';           /* append dash to newtag */
+            s = transform;
+            e = d + transformlen;
+            for (; d < e; ++d, ++s) {
+                *d = *s;          /* copy transform to newtag */
+            }
+            *d++ = '"';           /* append quote to newtag */
+            *d   = '\0';          /* null terminate newtag */
+
+            apr_table_setn(r->headers_out, "ETag", newtag);
         }
     }   
 }
+
 static apr_status_t deflate_out_filter(ap_filter_t *f,
                                        apr_bucket_brigade *bb)
 {