From: Roy T. Fielding Date: Thu, 12 Feb 2009 01:59:27 +0000 (+0000) Subject: Reimplement deflate_check_etag() so that it isn't such a pig X-Git-Tag: 2.3.2~59 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=60e1857f12d24048e159c60628471c6ec5406537;p=apache Reimplement deflate_check_etag() so that it isn't such a pig 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 --- diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c index b512c3b017..2dbadfe006 100644 --- a/modules/filters/mod_deflate.c +++ b/modules/filters/mod_deflate.c @@ -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) {