Mercurial > hg > nginx
changeset 4744:5b93a9ac60ed
Entity tags: basic support in not modified filter.
This includes handling of ETag headers (if present in a response) with
basic support for If-Match, If-None-Match conditionals in not modified
filter.
Note that the "r->headers_out.last_modified_time == -1" check in the not
modified filter is left as is intentionally. It's to prevent handling
of If-* headers in case of proxy without cache (much like currently
done with If-Modified-Since).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sat, 07 Jul 2012 21:20:27 +0000 |
parents | 84cc73e01aa8 |
children | 4752060ca462 |
files | src/http/modules/ngx_http_not_modified_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h |
diffstat | 3 files changed, 102 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/http/modules/ngx_http_not_modified_filter_module.c Sat Jul 07 21:18:30 2012 +0000 +++ b/src/http/modules/ngx_http_not_modified_filter_module.c Sat Jul 07 21:20:27 2012 +0000 @@ -12,6 +12,8 @@ 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); @@ -66,9 +68,27 @@ NGX_HTTP_PRECONDITION_FAILED); } - if (r->headers_in.if_modified_since - && !ngx_http_test_if_modified(r)) + 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 || 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; @@ -140,6 +160,76 @@ } +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; + + 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; + } + } + + return 0; +} + + static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf) {
--- a/src/http/ngx_http_request.c Sat Jul 07 21:18:30 2012 +0000 +++ b/src/http/ngx_http_request.c Sat Jul 07 21:20:27 2012 +0000 @@ -93,6 +93,14 @@ offsetof(ngx_http_headers_in_t, if_unmodified_since), ngx_http_process_unique_header_line }, + { ngx_string("If-Match"), + offsetof(ngx_http_headers_in_t, if_match), + ngx_http_process_unique_header_line }, + + { ngx_string("If-None-Match"), + offsetof(ngx_http_headers_in_t, if_none_match), + ngx_http_process_unique_header_line }, + { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), ngx_http_process_user_agent },
--- a/src/http/ngx_http_request.h Sat Jul 07 21:18:30 2012 +0000 +++ b/src/http/ngx_http_request.h Sat Jul 07 21:20:27 2012 +0000 @@ -172,6 +172,8 @@ ngx_table_elt_t *connection; ngx_table_elt_t *if_modified_since; ngx_table_elt_t *if_unmodified_since; + ngx_table_elt_t *if_match; + ngx_table_elt_t *if_none_match; ngx_table_elt_t *user_agent; ngx_table_elt_t *referer; ngx_table_elt_t *content_length;