comparison src/http/modules/ngx_http_not_modified_filter_module.c @ 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 bb3d74fc4aea
comparison
equal deleted inserted replaced
4743:84cc73e01aa8 4744:5b93a9ac60ed
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 static ngx_uint_t ngx_http_test_if_unmodified(ngx_http_request_t *r); 13 static ngx_uint_t ngx_http_test_if_unmodified(ngx_http_request_t *r);
14 static ngx_uint_t ngx_http_test_if_modified(ngx_http_request_t *r); 14 static ngx_uint_t ngx_http_test_if_modified(ngx_http_request_t *r);
15 static ngx_uint_t ngx_http_test_if_match(ngx_http_request_t *r,
16 ngx_table_elt_t *header);
15 static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf); 17 static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);
16 18
17 19
18 static ngx_http_module_t ngx_http_not_modified_filter_module_ctx = { 20 static ngx_http_module_t ngx_http_not_modified_filter_module_ctx = {
19 NULL, /* preconfiguration */ 21 NULL, /* preconfiguration */
64 { 66 {
65 return ngx_http_filter_finalize_request(r, NULL, 67 return ngx_http_filter_finalize_request(r, NULL,
66 NGX_HTTP_PRECONDITION_FAILED); 68 NGX_HTTP_PRECONDITION_FAILED);
67 } 69 }
68 70
69 if (r->headers_in.if_modified_since 71 if (r->headers_in.if_match
70 && !ngx_http_test_if_modified(r)) 72 && !ngx_http_test_if_match(r, r->headers_in.if_match))
71 { 73 {
74 return ngx_http_filter_finalize_request(r, NULL,
75 NGX_HTTP_PRECONDITION_FAILED);
76 }
77
78 if (r->headers_in.if_modified_since || r->headers_in.if_none_match) {
79
80 if (r->headers_in.if_modified_since
81 && ngx_http_test_if_modified(r))
82 {
83 return ngx_http_next_header_filter(r);
84 }
85
86 if (r->headers_in.if_none_match
87 && !ngx_http_test_if_match(r, r->headers_in.if_none_match))
88 {
89 return ngx_http_next_header_filter(r);
90 }
91
72 /* not modified */ 92 /* not modified */
73 93
74 r->headers_out.status = NGX_HTTP_NOT_MODIFIED; 94 r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
75 r->headers_out.status_line.len = 0; 95 r->headers_out.status_line.len = 0;
76 r->headers_out.content_type.len = 0; 96 r->headers_out.content_type.len = 0;
138 158
139 return 0; 159 return 0;
140 } 160 }
141 161
142 162
163 static ngx_uint_t
164 ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header)
165 {
166 u_char *start, *end, ch;
167 ngx_str_t *etag, *list;
168
169 list = &header->value;
170
171 if (list->len == 1 && list->data[0] == '*') {
172 return 1;
173 }
174
175 if (r->headers_out.etag == NULL) {
176 return 0;
177 }
178
179 etag = &r->headers_out.etag->value;
180
181 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
182 "http im:\"%V\" etag:%V", list, etag);
183
184 start = list->data;
185 end = list->data + list->len;
186
187 while (start < end) {
188
189 if (etag->len > (size_t) (end - start)) {
190 return 0;
191 }
192
193 if (ngx_strncmp(start, etag->data, etag->len) != 0) {
194 goto skip;
195 }
196
197 start += etag->len;
198
199 while (start < end) {
200 ch = *start;
201
202 if (ch == ' ' || ch == '\t') {
203 start++;
204 continue;
205 }
206
207 break;
208 }
209
210 if (start == end || *start == ',') {
211 return 1;
212 }
213
214 skip:
215
216 while (start < end && *start != ',') { start++; }
217 while (start < end) {
218 ch = *start;
219
220 if (ch == ' ' || ch == '\t' || ch == ',') {
221 start++;
222 continue;
223 }
224
225 break;
226 }
227 }
228
229 return 0;
230 }
231
232
143 static ngx_int_t 233 static ngx_int_t
144 ngx_http_not_modified_filter_init(ngx_conf_t *cf) 234 ngx_http_not_modified_filter_init(ngx_conf_t *cf)
145 { 235 {
146 ngx_http_next_header_filter = ngx_http_top_header_filter; 236 ngx_http_next_header_filter = ngx_http_top_header_filter;
147 ngx_http_top_header_filter = ngx_http_not_modified_header_filter; 237 ngx_http_top_header_filter = ngx_http_not_modified_header_filter;