Add Support for Weak ETags

Maxim Dounin mdounin at mdounin.ru
Tue Nov 12 16:46:27 UTC 2013


Hello!

On Mon, Nov 04, 2013 at 05:14:12PM -0800, Aaron Peschel wrote:

> I reduced the scope of the changes to just the gzip and gunzip modules.

I don't think that limiting the scope to gzip and gunzip is 
correct either.  From cache validation point of view, weak etags 
are mostly identical to Last-Modified, and removing etags 
completely should mostly follow ngx_http_clear_last_modified().

Here is a patch, untested:

# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1384274233 -14400
#      Tue Nov 12 20:37:13 2013 +0400
# Node ID 2c4e71a1c9a3467ba53115b693549c41f248164e
# Parent  f3c95d2d7d5e2d69c4b4fd99421b3193d43adab0
Entity tags: only clear strict etags if weak ones are ok.

diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -121,7 +121,7 @@ ngx_http_addition_header_filter(ngx_http
 
     ngx_http_clear_content_length(r);
     ngx_http_clear_accept_ranges(r);
-    ngx_http_clear_etag(r);
+    ngx_http_clear_strict_etag(r);
 
     return ngx_http_next_header_filter(r);
 }
diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c
--- a/src/http/modules/ngx_http_gunzip_filter_module.c
+++ b/src/http/modules/ngx_http_gunzip_filter_module.c
@@ -165,7 +165,7 @@ ngx_http_gunzip_header_filter(ngx_http_r
 
     ngx_http_clear_content_length(r);
     ngx_http_clear_accept_ranges(r);
-    ngx_http_clear_etag(r);
+    ngx_http_clear_strict_etag(r);
 
     return ngx_http_next_header_filter(r);
 }
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -306,7 +306,7 @@ ngx_http_gzip_header_filter(ngx_http_req
 
     ngx_http_clear_content_length(r);
     ngx_http_clear_accept_ranges(r);
-    ngx_http_clear_etag(r);
+    ngx_http_clear_strict_etag(r);
 
     return ngx_http_next_header_filter(r);
 }
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -368,10 +368,13 @@ ngx_http_ssi_header_filter(ngx_http_requ
     if (r == r->main) {
         ngx_http_clear_content_length(r);
         ngx_http_clear_accept_ranges(r);
-        ngx_http_clear_etag(r);
 
         if (!slcf->last_modified) {
             ngx_http_clear_last_modified(r);
+            ngx_http_clear_etag(r);
+
+        } else {
+            ngx_http_clear_strict_etag(r);
         }
     }
 
diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -175,10 +175,13 @@ ngx_http_sub_header_filter(ngx_http_requ
 
     if (r == r->main) {
         ngx_http_clear_content_length(r);
-        ngx_http_clear_etag(r);
 
         if (!slcf->last_modified) {
             ngx_http_clear_last_modified(r);
+            ngx_http_clear_etag(r);
+
+        } else {
+            ngx_http_clear_strict_etag(r);
         }
     }
 
diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -337,12 +337,14 @@ ngx_http_xslt_send(ngx_http_request_t *r
             r->headers_out.content_length = NULL;
         }
 
-        ngx_http_clear_etag(r);
-
         conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
 
         if (!conf->last_modified) {
             ngx_http_clear_last_modified(r);
+            ngx_http_clear_etag(r);
+
+        } else {
+            ngx_http_clear_strict_etag(r);
         }
     }
 
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -579,5 +579,16 @@ extern ngx_str_t  ngx_http_core_get_meth
         r->headers_out.etag = NULL;                                           \
     }
 
+#define ngx_http_clear_strict_etag(r)                                         \
+                                                                              \
+    if (r->headers_out.etag                                                   \
+        && (r->headers_out.etag->value.len < 2                                \
+            || r->headers_out.etag->value.data[0] != 'W'                      \
+            || r->headers_out.etag->value.data[1] != '/'))                    \
+    {                                                                         \
+        r->headers_out.etag->hash = 0;                                        \
+        r->headers_out.etag = NULL;                                           \
+    }
+
 
 #endif /* _NGX_HTTP_CORE_H_INCLUDED_ */


But I don't really sure we need preserving weak etags aproach.  It 
requires a backend to know that weak etags can be used, while 
strict ones can't.  This is basically what we already have - but 
with Last-Modified instead of etags.

It could be done better - strict etags can be downgraded to weak 
ones if we change entity representation (but not semantics).  This 
way it will do its best while handling all possible responses.  
This will require much more changes though.

> # HG changeset patch
> # User Aaron Peschel <aaron.peschel at gmail.com>
> # Date 1383613159 28800
> #      Mon Nov 04 16:59:19 2013 -0800
> # Node ID c0a50e6aac95feac6393dd6bff0b30bd1a05ef9e
> # Parent  e6a1623f87bc96d5ec62b6d77356aa47dbc60756
> Add Support for Weak ETags
> 
> This is a response to rev 4746 which removed ETags. 4746 removes the ETag field
> from the header in all instances where content is modified by the web server
> prior to being sent to the requesting client. This is far more stringent than
> required by the HTTP spec.

Just a side note: referring to Mercurial changesets with revision 
numbers can be ambigous, as different clones may have different 
revision numbers.  It's a good idea to referer to a revision hash 
or a revision id and hash as shown by hg log, e.g. 4746:4a18bf1833a9.

-- 
Maxim Dounin
http://nginx.org/en/donation.html



More information about the nginx-devel mailing list