Mercurial > hg > nginx-vendor-current
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; }