0
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9 #include <ngx_http.h>
|
|
10 #include <ngx_http_proxy_handler.h>
|
|
11
|
|
12
|
|
13 static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
|
|
14 int rc);
|
|
15 static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p);
|
|
16 static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p);
|
|
17
|
|
18
|
|
19 int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p)
|
|
20 {
|
|
21 char *last;
|
|
22 ngx_http_request_t *r;
|
|
23 ngx_http_proxy_cache_t *c;
|
|
24 ngx_http_proxy_upstream_conf_t *u;
|
|
25
|
|
26 r = p->request;
|
|
27
|
|
28 if (!(c = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_cache_t)))) {
|
|
29 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
30 }
|
|
31
|
|
32 p->cache = c;
|
|
33
|
|
34 c->ctx.file.fd = NGX_INVALID_FILE;
|
|
35 c->ctx.file.log = r->connection->log;
|
|
36 c->ctx.path = p->lcf->cache_path;
|
|
37
|
|
38 u = p->lcf->upstream;
|
|
39
|
|
40 c->ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len;
|
|
41 if (!(c->ctx.key.data = ngx_palloc(r->pool, c->ctx.key.len + 1))) {
|
|
42 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
43 }
|
|
44
|
|
45 last = ngx_cpymem(c->ctx.key.data, u->url.data, u->url.len);
|
|
46
|
|
47 last = ngx_cpymem(last, r->uri.data + u->location->len,
|
|
48 r->uri.len - u->location->len);
|
|
49
|
|
50 if (r->args.len > 0) {
|
|
51 *(last++) = '?';
|
|
52 last = ngx_cpymem(last, r->args.data, r->args.len);
|
|
53 }
|
|
54 *last = '\0';
|
|
55
|
|
56 p->header_in = ngx_create_temp_hunk(r->pool, p->lcf->header_buffer_size);
|
|
57 if (p->header_in == NULL) {
|
|
58 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
59 }
|
|
60 p->header_in->tag = (ngx_hunk_tag_t) &ngx_http_proxy_module;
|
|
61
|
|
62 c->ctx.buf = p->header_in;
|
|
63 c->ctx.log = r->connection->log;
|
|
64
|
|
65 return ngx_http_proxy_process_cached_response(p,
|
|
66 ngx_http_cache_get_file(r, &c->ctx));
|
|
67 }
|
|
68
|
|
69
|
|
70 static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
|
|
71 int rc)
|
|
72 {
|
|
73 if (rc == NGX_OK) {
|
|
74 p->state->cache_state = NGX_HTTP_PROXY_CACHE_HIT;
|
|
75 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
|
|
76
|
|
77 if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
|
|
78 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
79 }
|
|
80
|
|
81 p->valid_header_in = 1;
|
|
82
|
|
83 return ngx_http_proxy_send_cached_response(p);
|
|
84 }
|
|
85
|
|
86 if (rc == NGX_HTTP_CACHE_STALE) {
|
|
87 p->state->cache_state = NGX_HTTP_PROXY_CACHE_EXPR;
|
|
88
|
|
89 } else if (rc == NGX_HTTP_CACHE_AGED) {
|
|
90 p->state->cache_state = NGX_HTTP_PROXY_CACHE_AGED;
|
|
91 }
|
|
92
|
|
93 if (rc == NGX_HTTP_CACHE_STALE || rc == NGX_HTTP_CACHE_AGED) {
|
|
94 p->state->expired = ngx_time() - p->cache->ctx.expires;
|
|
95 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
|
|
96
|
|
97 if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
|
|
98 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
99 }
|
|
100
|
|
101 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
|
|
102 p->header_in->last = p->header_in->pos;
|
|
103
|
|
104 p->stale = 1;
|
|
105 p->valid_header_in = 1;
|
|
106
|
|
107 } else if (rc == NGX_DECLINED) {
|
|
108 p->state->cache_state = NGX_HTTP_PROXY_CACHE_MISS;
|
|
109 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
|
|
110 p->header_in->last = p->header_in->pos;
|
|
111 }
|
|
112
|
|
113 if (p->lcf->busy_lock) {
|
|
114 p->try_busy_lock = 1;
|
|
115
|
|
116 p->header_in->pos = p->header_in->start;
|
|
117 p->header_in->last = p->header_in->start;
|
|
118
|
|
119 p->busy_lock.time = 0;
|
|
120 p->busy_lock.event = p->request->connection->read;
|
|
121 p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler;
|
|
122 p->busy_lock.md5 = p->cache->ctx.md5;
|
|
123
|
|
124 ngx_http_proxy_cache_busy_lock(p);
|
|
125 return NGX_DONE;
|
|
126 }
|
|
127
|
|
128 return ngx_http_proxy_request_upstream(p);
|
|
129 }
|
|
130
|
|
131
|
|
132 static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p)
|
|
133 {
|
|
134 int rc, i;
|
|
135 ngx_table_elt_t *h;
|
|
136 ngx_http_request_t *r;
|
|
137 ngx_http_proxy_cache_t *c;
|
|
138
|
|
139 rc = ngx_http_proxy_parse_status_line(p);
|
|
140
|
|
141 c = p->cache;
|
|
142 r = p->request;
|
|
143
|
|
144 if (rc == NGX_AGAIN) {
|
|
145 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
|
146 "\"proxy_header_buffer_size\" "
|
|
147 "is too small to read header from \"%s\"",
|
|
148 c->ctx.file.name.data);
|
|
149 return NGX_ERROR;
|
|
150 }
|
|
151
|
|
152 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
|
|
153 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
|
154 "no valid HTTP/1.0 header in \"%s\"",
|
|
155 c->ctx.file.name.data);
|
|
156 return NGX_ERROR;
|
|
157 }
|
|
158
|
|
159 /* rc == NGX_OK */
|
|
160
|
|
161 c->status = p->status;
|
|
162 c->status_line.len = p->status_end - p->status_start;
|
|
163 c->status_line.data = ngx_palloc(r->pool, c->status_line.len + 1);
|
|
164 if (c->status_line.data == NULL) {
|
|
165 return NGX_ERROR;
|
|
166 }
|
|
167
|
|
168 /* reset for the possible parsing the upstream header */
|
|
169
|
|
170 p->status = 0;
|
|
171 p->status_count = 0;
|
|
172
|
|
173 ngx_cpystrn(c->status_line.data, p->status_start, c->status_line.len + 1);
|
|
174
|
|
175 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
10
|
176 "http cache status %ui \"%V\"",
|
|
177 c->status, &c->status_line);
|
0
|
178
|
|
179 /* TODO: ngx_init_table */
|
|
180 c->headers_in.headers = ngx_create_table(r->pool, 20);
|
|
181
|
|
182 for ( ;; ) {
|
|
183 rc = ngx_http_parse_header_line(r, p->header_in);
|
|
184
|
|
185 if (rc == NGX_OK) {
|
|
186
|
|
187 /* a header line has been parsed successfully */
|
|
188
|
|
189 h = ngx_http_add_header(&c->headers_in, ngx_http_proxy_headers_in);
|
|
190 if (h == NULL) {
|
|
191 return NGX_ERROR;
|
|
192 }
|
|
193
|
|
194 h->key.len = r->header_name_end - r->header_name_start;
|
|
195 h->value.len = r->header_end - r->header_start;
|
|
196
|
|
197 h->key.data = ngx_palloc(r->pool,
|
|
198 h->key.len + 1 + h->value.len + 1);
|
|
199 if (h->key.data == NULL) {
|
|
200 return NGX_ERROR;
|
|
201 }
|
|
202
|
|
203 h->value.data = h->key.data + h->key.len + 1;
|
|
204 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
|
|
205 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
|
|
206
|
|
207 for (i = 0; ngx_http_proxy_headers_in[i].name.len != 0; i++) {
|
|
208 if (ngx_http_proxy_headers_in[i].name.len != h->key.len) {
|
|
209 continue;
|
|
210 }
|
|
211
|
|
212 if (ngx_strcasecmp(ngx_http_proxy_headers_in[i].name.data,
|
|
213 h->key.data) == 0)
|
|
214 {
|
|
215 *((ngx_table_elt_t **) ((char *) &c->headers_in
|
|
216 + ngx_http_proxy_headers_in[i].offset)) = h;
|
|
217 break;
|
|
218 }
|
|
219 }
|
|
220
|
|
221 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
10
|
222 "http cache header: \"%V: %V\"", &h->key, &h->value);
|
0
|
223
|
|
224 continue;
|
|
225
|
|
226 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
|
|
227
|
|
228 /* a whole header has been parsed successfully */
|
|
229
|
|
230 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
|
231 "http cache header done");
|
|
232
|
|
233 c->ctx.file_start = p->header_in->pos - p->header_in->start;
|
|
234
|
|
235 return NGX_OK;
|
|
236
|
|
237 } else if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
|
|
238
|
|
239 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
|
240 "invalid header in \"%s\"",
|
|
241 c->ctx.file.name.data);
|
|
242 return NGX_ERROR;
|
|
243 }
|
|
244
|
|
245 /* rc == NGX_AGAIN || rc == NGX_HTTP_PARSE_TOO_LONG_HEADER */
|
|
246
|
|
247 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
|
248 "\"proxy_header_buffer_size\" "
|
|
249 "is too small to read header from \"%s\"",
|
|
250 c->ctx.file.name.data);
|
|
251 return NGX_ERROR;
|
|
252 }
|
|
253 }
|
|
254
|
|
255
|
|
256 void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p)
|
|
257 {
|
|
258 int rc, ft_type;
|
|
259
|
|
260 rc = ngx_http_busy_lock_cachable(p->lcf->busy_lock, &p->busy_lock,
|
|
261 p->try_busy_lock);
|
|
262
|
|
263 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
|
|
264 "http cache busy lock cachable: %d", rc);
|
|
265
|
|
266 if (rc == NGX_OK) {
|
|
267 if (p->try_busy_lock) {
|
|
268 p->busy_locked = 1;
|
|
269 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
|
|
270 p->header_in->last = p->header_in->pos;
|
|
271
|
|
272 ngx_http_proxy_request_upstream(p);
|
|
273 return;
|
|
274 }
|
|
275
|
|
276 ngx_http_proxy_cache_look_complete_request(p);
|
|
277 return;
|
|
278 }
|
|
279
|
|
280 p->try_busy_lock = 0;
|
|
281
|
|
282 if (p->cache->ctx.file.fd != NGX_INVALID_FILE
|
|
283 && !p->cache->ctx.file.info_valid)
|
|
284 {
|
|
285 if (ngx_fd_info(p->cache->ctx.file.fd, &p->cache->ctx.file.info)
|
|
286 == NGX_FILE_ERROR)
|
|
287 {
|
|
288 ngx_log_error(NGX_LOG_CRIT, p->request->connection->log, ngx_errno,
|
|
289 ngx_fd_info_n " \"%s\" failed",
|
|
290 p->cache->ctx.file.name.data);
|
|
291 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
292 return;
|
|
293 }
|
|
294
|
|
295 p->cache->ctx.file.info_valid = 1;
|
|
296 }
|
|
297
|
|
298 if (rc == NGX_AGAIN) {
|
|
299
|
18
|
300 if ((ngx_event_flags & (NGX_USE_CLEAR_EVENT|NGX_USE_KQUEUE_EVENT))
|
0
|
301 && !p->request->connection->write->active)
|
|
302 {
|
|
303 /*
|
|
304 * kqueue allows to detect when client closes prematurely
|
|
305 * connection
|
|
306 */
|
|
307
|
|
308 p->request->connection->write->event_handler =
|
|
309 ngx_http_proxy_check_broken_connection;
|
|
310
|
|
311 if (ngx_add_event(p->request->connection->write, NGX_WRITE_EVENT,
|
|
312 NGX_CLEAR_EVENT) == NGX_ERROR)
|
|
313 {
|
|
314 ngx_http_proxy_finalize_request(p,
|
|
315 NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
316 return;
|
|
317 }
|
|
318 }
|
|
319
|
|
320 return;
|
|
321 }
|
|
322
|
|
323 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
|
|
324
|
|
325 if (rc == NGX_DONE) {
|
|
326 ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
|
|
327
|
|
328 } else {
|
|
329 /* rc == NGX_ERROR */
|
|
330 ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
|
|
331 }
|
|
332
|
|
333 if (p->stale && (p->lcf->use_stale & ft_type)) {
|
|
334 ngx_http_proxy_finalize_request(p,
|
|
335 ngx_http_proxy_send_cached_response(p));
|
|
336 return;
|
|
337 }
|
|
338
|
|
339 p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
|
|
340 ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
|
|
341 }
|
|
342
|
|
343
|
|
344 static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p)
|
|
345 {
|
|
346 int rc;
|
|
347 ngx_http_cache_ctx_t *ctx;
|
|
348
|
|
349 if (!(ctx = ngx_pcalloc(p->request->pool, sizeof(ngx_http_cache_ctx_t)))) {
|
|
350 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
351 return;
|
|
352 }
|
|
353
|
|
354 *ctx = p->cache->ctx;
|
|
355
|
|
356 rc = ngx_http_cache_open_file(ctx, ngx_file_uniq(&p->cache->ctx.file.info));
|
|
357
|
|
358 if (rc == NGX_DECLINED || rc == NGX_HTTP_CACHE_THE_SAME) {
|
|
359 p->try_busy_lock = 1;
|
|
360 p->busy_lock.time = 0;
|
|
361 ngx_http_proxy_cache_busy_lock(p);
|
|
362 return;
|
|
363 }
|
|
364
|
|
365 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
|
|
366 "http cache old fd:%d, new fd:%d",
|
|
367 p->cache->ctx.file.fd, ctx->file.fd);
|
|
368
|
|
369 if (p->cache->ctx.file.fd != NGX_INVALID_FILE) {
|
|
370 if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) {
|
|
371 ngx_log_error(NGX_LOG_ALERT, p->request->connection->log, ngx_errno,
|
|
372 ngx_close_file_n " \"%s\" failed",
|
|
373 p->cache->ctx.file.name.data);
|
|
374 }
|
|
375 }
|
|
376
|
|
377 p->cache->ctx = *ctx;
|
|
378
|
|
379 p->status = 0;
|
|
380 p->status_count = 0;
|
|
381
|
|
382 ngx_http_proxy_finalize_request(p,
|
|
383 ngx_http_proxy_process_cached_response(p, rc));
|
|
384 }
|
|
385
|
|
386
|
|
387 int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p)
|
|
388 {
|
|
389 int rc, len, i;
|
|
390 off_t rest;
|
|
391 ngx_hunk_t *h0, *h1;
|
|
392 ngx_chain_t out[2];
|
|
393 ngx_http_request_t *r;
|
|
394
|
|
395 r = p->request;
|
|
396
|
|
397 r->headers_out.status = p->cache->status;
|
|
398
|
|
399 #if 0
|
|
400 r->headers_out.content_length_n = -1;
|
|
401 r->headers_out.content_length = NULL;
|
|
402 #endif
|
|
403
|
|
404 /* copy an cached header to r->headers_out */
|
|
405
|
|
406 if (ngx_http_proxy_copy_header(p, &p->cache->headers_in) == NGX_ERROR) {
|
|
407 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
408 }
|
|
409
|
|
410 /* we need to allocate all before the header would be sent */
|
|
411
|
|
412 len = p->header_in->end - (p->header_in->start + p->cache->ctx.file_start);
|
|
413
|
|
414 h0 = NULL;
|
|
415 h1 = NULL;
|
|
416
|
|
417 if (len) {
|
|
418 if (!((h0 = ngx_calloc_hunk(r->pool)))) {
|
|
419 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
420 }
|
|
421
|
|
422 if (!((h0->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
|
|
423 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
424 }
|
|
425 }
|
|
426
|
|
427 if (len < p->cache->ctx.length) {
|
|
428 if (!((h1 = ngx_calloc_hunk(r->pool)))) {
|
|
429 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
430 }
|
|
431
|
|
432 if (!((h1->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
|
|
433 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
434 }
|
|
435 }
|
|
436
|
|
437 rc = ngx_http_send_header(r);
|
|
438
|
|
439 /* NEEDED ??? */ p->header_sent = 1;
|
|
440
|
|
441 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
|
|
442 return rc;
|
|
443 }
|
|
444
|
|
445 rest = p->cache->ctx.length;
|
|
446
|
|
447 if (len) {
|
|
448 if (p->valid_header_in) {
|
|
449 h0->pos = p->header_in->start + p->cache->ctx.file_start;
|
|
450
|
|
451 if (len > p->cache->ctx.length) {
|
|
452 h0->last = h0->pos + p->cache->ctx.length;
|
|
453
|
|
454 } else {
|
|
455 h0->last = p->header_in->end;
|
|
456 }
|
|
457
|
|
458 h0->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
|
|
459 }
|
|
460
|
|
461 h0->type |= NGX_HUNK_FILE;
|
|
462 h0->file_pos = p->cache->ctx.file_start;
|
|
463
|
|
464 h0->file->fd = p->cache->ctx.file.fd;
|
|
465 h0->file->log = r->connection->log;
|
|
466
|
|
467 if (len > p->cache->ctx.length) {
|
|
468 h0->file_last = h0->file_pos + p->cache->ctx.length;
|
|
469 rest = 0;
|
|
470
|
|
471 } else {
|
|
472 h0->file_last = h0->file_pos + len;
|
|
473 rest -= len;
|
|
474 }
|
|
475
|
|
476 out[0].hunk = h0;
|
|
477 out[0].next = &out[1];
|
|
478 i = 0;
|
|
479
|
|
480 } else {
|
|
481 i = -1;
|
|
482 }
|
|
483
|
|
484 if (rest) {
|
|
485 h1->file_pos = p->cache->ctx.file_start + len;
|
|
486 h1->file_last = h1->file_pos + rest;
|
|
487 h1->type = NGX_HUNK_FILE;
|
|
488
|
|
489 h1->file->fd = p->cache->ctx.file.fd;
|
|
490 h1->file->log = r->connection->log;
|
|
491
|
|
492 out[++i].hunk = h1;
|
|
493 }
|
|
494
|
|
495 out[i].next = NULL;
|
|
496 if (!r->main) {
|
|
497 out[i].hunk->type |= NGX_HUNK_LAST;
|
|
498 }
|
|
499
|
|
500 r->file.fd = p->cache->ctx.file.fd;
|
|
501
|
|
502 return ngx_http_output_filter(r, out);
|
|
503 }
|
|
504
|
|
505
|
|
506 int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p)
|
|
507 {
|
|
508 time_t date, last_modified, expires, t;
|
|
509 ngx_http_proxy_headers_in_t *h;
|
|
510
|
|
511 switch (p->upstream->status) {
|
|
512 case NGX_HTTP_OK:
|
|
513 case NGX_HTTP_MOVED_PERMANENTLY:
|
|
514 case NGX_HTTP_MOVED_TEMPORARILY:
|
|
515 break;
|
|
516
|
|
517 #if 0
|
|
518 case NGX_HTTP_NOT_MODIFIED:
|
|
519 return 1;
|
|
520 #endif
|
|
521
|
|
522 default:
|
|
523 return 0;
|
|
524 }
|
|
525
|
|
526 h = &p->upstream->headers_in;
|
|
527
|
|
528 date = NGX_ERROR;
|
|
529 if (h->date) {
|
|
530 date = ngx_http_parse_time(h->date->value.data, h->date->value.len);
|
|
531 }
|
|
532 if (date == NGX_ERROR) {
|
|
533 date = ngx_time();
|
|
534 }
|
|
535 p->cache->ctx.date = date;
|
|
536
|
|
537 last_modified = NGX_ERROR;
|
|
538 if (h->last_modified) {
|
|
539 last_modified = ngx_http_parse_time(h->last_modified->value.data,
|
|
540 h->last_modified->value.len);
|
|
541 p->cache->ctx.last_modified = last_modified;
|
|
542 }
|
|
543
|
|
544 if (h->x_accel_expires) {
|
|
545 expires = ngx_atoi(h->x_accel_expires->value.data,
|
|
546 h->x_accel_expires->value.len);
|
|
547 if (expires != NGX_ERROR) {
|
|
548 p->state->reason = NGX_HTTP_PROXY_CACHE_XAE;
|
|
549 p->state->expires = expires;
|
|
550 p->cache->ctx.expires = date + expires;
|
|
551 return (expires > 0);
|
|
552 }
|
|
553 }
|
|
554
|
|
555 if (!p->lcf->ignore_expires) {
|
|
556
|
|
557 /* TODO: Cache-Control: no-cache, max-age= */
|
|
558
|
|
559 if (h->expires) {
|
|
560 expires = ngx_http_parse_time(h->expires->value.data,
|
|
561 h->expires->value.len);
|
|
562 if (expires != NGX_ERROR) {
|
|
563 p->state->reason = NGX_HTTP_PROXY_CACHE_EXP;
|
|
564 p->state->expires = expires - date;
|
|
565 p->cache->ctx.expires = expires;
|
|
566 return (date < expires);
|
|
567 }
|
|
568 }
|
|
569 }
|
|
570
|
|
571 if (p->upstream->status == NGX_HTTP_MOVED_PERMANENTLY) {
|
|
572 p->state->reason = NGX_HTTP_PROXY_CACHE_MVD;
|
|
573 p->state->expires = /* STUB: 1 hour */ 60 * 60;
|
|
574 p->cache->ctx.expires = /* STUB: 1 hour */ 60 * 60;
|
|
575 return 1;
|
|
576 }
|
|
577
|
|
578 if (p->upstream->status == NGX_HTTP_MOVED_TEMPORARILY) {
|
|
579 return 1;
|
|
580 }
|
|
581
|
|
582 if (last_modified != NGX_ERROR && p->lcf->lm_factor > 0) {
|
|
583
|
|
584 /* FIXME: time_t == int_64_t, we can use fpu */
|
|
585
|
|
586 p->state->reason = NGX_HTTP_PROXY_CACHE_LMF;
|
|
587 t = (time_t)
|
|
588 ((((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100);
|
|
589 p->state->expires = t;
|
|
590 p->cache->ctx.expires = ngx_time() + t;
|
|
591 return 1;
|
|
592 }
|
|
593
|
|
594 if (p->lcf->default_expires > 0) {
|
|
595 p->state->reason = NGX_HTTP_PROXY_CACHE_PDE;
|
|
596 p->state->expires = p->lcf->default_expires;
|
|
597 p->cache->ctx.expires = ngx_time() + p->lcf->default_expires;
|
|
598 return 1;
|
|
599 }
|
|
600
|
|
601 return 0;
|
|
602 }
|
|
603
|
|
604
|
|
605 int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
|
|
606 {
|
|
607 ngx_event_pipe_t *ep;
|
|
608
|
|
609 if (p->cache == NULL) {
|
|
610 return NGX_OK;
|
|
611 }
|
|
612
|
|
613 ep = p->upstream->event_pipe;
|
|
614
|
|
615 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
|
10
|
616 "http cache update len: %O:%O",
|
0
|
617 p->cache->ctx.length, ep->read_length);
|
|
618
|
|
619 if (p->cache->ctx.length == -1) {
|
|
620 /* TODO: test rc */
|
|
621 ngx_write_file(&ep->temp_file->file,
|
|
622 (char *) &ep->read_length, sizeof(off_t),
|
|
623 offsetof(ngx_http_cache_header_t, length));
|
|
624 }
|
|
625
|
|
626 return ngx_http_cache_update_file(p->request, &p->cache->ctx,
|
|
627 &ep->temp_file->file.name);
|
|
628 }
|