Annotation of embedaddon/nginx/src/http/modules/ngx_http_not_modified_filter_module.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Igor Sysoev
4: * Copyright (C) Nginx, Inc.
5: */
6:
7:
8: #include <ngx_config.h>
9: #include <ngx_core.h>
10: #include <ngx_http.h>
11:
12:
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);
15: static ngx_uint_t ngx_http_test_if_match(ngx_http_request_t *r,
16: ngx_table_elt_t *header);
17: static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);
18:
19:
20: static ngx_http_module_t ngx_http_not_modified_filter_module_ctx = {
21: NULL, /* preconfiguration */
22: ngx_http_not_modified_filter_init, /* postconfiguration */
23:
24: NULL, /* create main configuration */
25: NULL, /* init main configuration */
26:
27: NULL, /* create server configuration */
28: NULL, /* merge server configuration */
29:
30: NULL, /* create location configuration */
31: NULL /* merge location configuration */
32: };
33:
34:
35: ngx_module_t ngx_http_not_modified_filter_module = {
36: NGX_MODULE_V1,
37: &ngx_http_not_modified_filter_module_ctx, /* module context */
38: NULL, /* module directives */
39: NGX_HTTP_MODULE, /* module type */
40: NULL, /* init master */
41: NULL, /* init module */
42: NULL, /* init process */
43: NULL, /* init thread */
44: NULL, /* exit thread */
45: NULL, /* exit process */
46: NULL, /* exit master */
47: NGX_MODULE_V1_PADDING
48: };
49:
50:
51: static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
52:
53:
54: static ngx_int_t
55: ngx_http_not_modified_header_filter(ngx_http_request_t *r)
56: {
57: if (r->headers_out.status != NGX_HTTP_OK
58: || r != r->main
59: || r->headers_out.last_modified_time == -1)
60: {
61: return ngx_http_next_header_filter(r);
62: }
63:
64: if (r->headers_in.if_unmodified_since
65: && !ngx_http_test_if_unmodified(r))
66: {
67: return ngx_http_filter_finalize_request(r, NULL,
68: NGX_HTTP_PRECONDITION_FAILED);
69: }
70:
71: if (r->headers_in.if_match
72: && !ngx_http_test_if_match(r, r->headers_in.if_match))
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:
92: /* not modified */
93:
94: r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
95: r->headers_out.status_line.len = 0;
96: r->headers_out.content_type.len = 0;
97: ngx_http_clear_content_length(r);
98: ngx_http_clear_accept_ranges(r);
99:
100: if (r->headers_out.content_encoding) {
101: r->headers_out.content_encoding->hash = 0;
102: r->headers_out.content_encoding = NULL;
103: }
104:
105: return ngx_http_next_header_filter(r);
106: }
107:
108: return ngx_http_next_header_filter(r);
109: }
110:
111:
112: static ngx_uint_t
113: ngx_http_test_if_unmodified(ngx_http_request_t *r)
114: {
115: time_t iums;
116:
117: iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data,
118: r->headers_in.if_unmodified_since->value.len);
119:
120: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
121: "http iums:%d lm:%d", iums, r->headers_out.last_modified_time);
122:
123: if (iums >= r->headers_out.last_modified_time) {
124: return 1;
125: }
126:
127: return 0;
128: }
129:
130:
131: static ngx_uint_t
132: ngx_http_test_if_modified(ngx_http_request_t *r)
133: {
134: time_t ims;
135: ngx_http_core_loc_conf_t *clcf;
136:
137: clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
138:
139: if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
140: return 1;
141: }
142:
143: ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
144: r->headers_in.if_modified_since->value.len);
145:
146: ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
147: "http ims:%d lm:%d", ims, r->headers_out.last_modified_time);
148:
149: if (ims == r->headers_out.last_modified_time) {
150: return 0;
151: }
152:
153: if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
154: || ims < r->headers_out.last_modified_time)
155: {
156: return 1;
157: }
158:
159: return 0;
160: }
161:
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:
233: static ngx_int_t
234: ngx_http_not_modified_filter_init(ngx_conf_t *cf)
235: {
236: ngx_http_next_header_filter = ngx_http_top_header_filter;
237: ngx_http_top_header_filter = ngx_http_not_modified_header_filter;
238:
239: return NGX_OK;
240: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>