@@ -372,22 +372,40 @@ static apr_status_t deflate_ctx_cleanup(void *data)
372372 ctx -> libz_end_func (& ctx -> stream );
373373 return APR_SUCCESS ;
374374}
375- /* PR 39727: we're screwing up our clients if we leave a strong ETag
376- * header while transforming content. Henrik Nordstrom suggests
377- * appending ";gzip".
378- *
379- * Pending a more thorough review of our Etag handling, let's just
380- * implement his suggestion. It fixes the bug, or at least turns it
381- * from a showstopper to an inefficiency. And it breaks nothing that
382- * wasn't already broken.
375+ /* ETag must be unique among the possible representations, so a change
376+ * to content-encoding requires a corresponding change to the ETag.
377+ * This routine appends -transform (e.g., -gzip) to the entity-tag
378+ * value inside the double-quotes if an ETag has already been set
379+ * and its value already contains double-quotes. PR 39727
383380 */
384381static void deflate_check_etag (request_rec * r , const char * transform )
385382{
386383 const char * etag = apr_table_get (r -> headers_out , "ETag" );
387- if (etag && (((etag [0 ] != 'W' ) && (etag [0 ] != 'w' )) || (etag [1 ] != '/' ))) {
388- apr_table_set (r -> headers_out , "ETag" ,
389- apr_pstrcat (r -> pool , etag , "-" , transform , NULL ));
390- }
384+ apr_size_t etaglen ;
385+
386+ if ((etag && ((etaglen = strlen (etag )) > 2 ))) {
387+ if (etag [etaglen - 1 ] == '"' ) {
388+ apr_size_t transformlen = strlen (transform );
389+ char * newtag = apr_palloc (r -> pool , etaglen + transformlen + 2 );
390+ char * d = newtag ;
391+ char * e = d + etaglen - 1 ;
392+ const char * s = etag ;
393+
394+ for (; d < e ; ++ d , ++ s ) {
395+ * d = * s ; /* copy etag to newtag up to last quote */
396+ }
397+ * d ++ = '-' ; /* append dash to newtag */
398+ s = transform ;
399+ e = d + transformlen ;
400+ for (; d < e ; ++ d , ++ s ) {
401+ * d = * s ; /* copy transform to newtag */
402+ }
403+ * d ++ = '"' ; /* append quote to newtag */
404+ * d = '\0' ; /* null terminate newtag */
405+
406+ apr_table_setn (r -> headers_out , "ETag" , newtag );
407+ }
408+ }
391409}
392410static apr_status_t deflate_out_filter (ap_filter_t * f ,
393411 apr_bucket_brigade * bb )
0 commit comments