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