diff src/http/modules/ngx_http_not_modified_filter_module.c @ 680:597573166f34 NGINX_1_3_3

nginx 1.3.3 *) Feature: entity tags support and the "etag" directive. *) Bugfix: trailing dot in a source value was not ignored if the "map" directive was used with the "hostnames" parameter. *) Bugfix: incorrect location might be used to process a request if a URI was changed via a "rewrite" directive before an internal redirect to a named location.
author Igor Sysoev <http://sysoev.ru>
date Tue, 10 Jul 2012 00:00:00 +0400
parents d0f7a625f27c
children
line wrap: on
line diff
--- a/src/http/modules/ngx_http_not_modified_filter_module.c
+++ b/src/http/modules/ngx_http_not_modified_filter_module.c
@@ -10,8 +10,10 @@
 #include <ngx_http.h>
 
 
-static ngx_int_t ngx_http_test_precondition(ngx_http_request_t *r);
-static ngx_int_t ngx_http_test_not_modified(ngx_http_request_t *r);
+static ngx_uint_t ngx_http_test_if_unmodified(ngx_http_request_t *r);
+static ngx_uint_t ngx_http_test_if_modified(ngx_http_request_t *r);
+static ngx_uint_t ngx_http_test_if_match(ngx_http_request_t *r,
+    ngx_table_elt_t *header);
 static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);
 
 
@@ -59,20 +61,56 @@ ngx_http_not_modified_header_filter(ngx_
         return ngx_http_next_header_filter(r);
     }
 
-    if (r->headers_in.if_unmodified_since) {
-        return ngx_http_test_precondition(r);
+    if (r->headers_in.if_unmodified_since
+        && !ngx_http_test_if_unmodified(r))
+    {
+        return ngx_http_filter_finalize_request(r, NULL,
+                                                NGX_HTTP_PRECONDITION_FAILED);
+    }
+
+    if (r->headers_in.if_match
+        && !ngx_http_test_if_match(r, r->headers_in.if_match))
+    {
+        return ngx_http_filter_finalize_request(r, NULL,
+                                                NGX_HTTP_PRECONDITION_FAILED);
     }
 
-    if (r->headers_in.if_modified_since) {
-        return ngx_http_test_not_modified(r);
+    if (r->headers_in.if_modified_since || r->headers_in.if_none_match) {
+
+        if (r->headers_in.if_modified_since
+            && ngx_http_test_if_modified(r))
+        {
+            return ngx_http_next_header_filter(r);
+        }
+
+        if (r->headers_in.if_none_match
+            && !ngx_http_test_if_match(r, r->headers_in.if_none_match))
+        {
+            return ngx_http_next_header_filter(r);
+        }
+
+        /* not modified */
+
+        r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
+        r->headers_out.status_line.len = 0;
+        r->headers_out.content_type.len = 0;
+        ngx_http_clear_content_length(r);
+        ngx_http_clear_accept_ranges(r);
+
+        if (r->headers_out.content_encoding) {
+            r->headers_out.content_encoding->hash = 0;
+            r->headers_out.content_encoding = NULL;
+        }
+
+        return ngx_http_next_header_filter(r);
     }
 
     return ngx_http_next_header_filter(r);
 }
 
 
-static ngx_int_t
-ngx_http_test_precondition(ngx_http_request_t *r)
+static ngx_uint_t
+ngx_http_test_if_unmodified(ngx_http_request_t *r)
 {
     time_t  iums;
 
@@ -83,16 +121,15 @@ ngx_http_test_precondition(ngx_http_requ
                  "http iums:%d lm:%d", iums, r->headers_out.last_modified_time);
 
     if (iums >= r->headers_out.last_modified_time) {
-        return ngx_http_next_header_filter(r);
+        return 1;
     }
 
-    return ngx_http_filter_finalize_request(r, NULL,
-                                            NGX_HTTP_PRECONDITION_FAILED);
+    return 0;
 }
 
 
-static ngx_int_t
-ngx_http_test_not_modified(ngx_http_request_t *r)
+static ngx_uint_t
+ngx_http_test_if_modified(ngx_http_request_t *r)
 {
     time_t                     ims;
     ngx_http_core_loc_conf_t  *clcf;
@@ -100,7 +137,7 @@ ngx_http_test_not_modified(ngx_http_requ
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
-        return ngx_http_next_header_filter(r);
+        return 1;
     }
 
     ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
@@ -109,27 +146,87 @@ ngx_http_test_not_modified(ngx_http_requ
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http ims:%d lm:%d", ims, r->headers_out.last_modified_time);
 
-    if (ims != r->headers_out.last_modified_time) {
+    if (ims == r->headers_out.last_modified_time) {
+        return 0;
+    }
+
+    if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
+        || ims < r->headers_out.last_modified_time)
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+
+static ngx_uint_t
+ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header)
+{
+    u_char     *start, *end, ch;
+    ngx_str_t  *etag, *list;
+
+    list = &header->value;
+
+    if (list->len == 1 && list->data[0] == '*') {
+        return 1;
+    }
+
+    if (r->headers_out.etag == NULL) {
+        return 0;
+    }
+
+    etag = &r->headers_out.etag->value;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http im:\"%V\" etag:%V", list, etag);
+
+    start = list->data;
+    end = list->data + list->len;
 
-        if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
-            || ims < r->headers_out.last_modified_time)
-        {
-            return ngx_http_next_header_filter(r);
+    while (start < end) {
+
+        if (etag->len > (size_t) (end - start)) {
+            return 0;
+        }
+
+        if (ngx_strncmp(start, etag->data, etag->len) != 0) {
+            goto skip;
+        }
+
+        start += etag->len;
+
+        while (start < end) {
+            ch = *start;
+
+            if (ch == ' ' || ch == '\t') {
+                start++;
+                continue;
+            }
+
+            break;
+        }
+
+        if (start == end || *start == ',') {
+            return 1;
+        }
+
+    skip:
+
+        while (start < end && *start != ',') { start++; }
+        while (start < end) {
+            ch = *start;
+
+            if (ch == ' ' || ch == '\t' || ch == ',') {
+                start++;
+                continue;
+            }
+
+            break;
         }
     }
 
-    r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
-    r->headers_out.status_line.len = 0;
-    r->headers_out.content_type.len = 0;
-    ngx_http_clear_content_length(r);
-    ngx_http_clear_accept_ranges(r);
-
-    if (r->headers_out.content_encoding) {
-        r->headers_out.content_encoding->hash = 0;
-        r->headers_out.content_encoding = NULL;
-    }
-
-    return ngx_http_next_header_filter(r);
+    return 0;
 }