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,
|
|
176 "http cache status %d \"%s\"",
|
|
177 c->status, c->status_line.data);
|
|
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,
|
|
222 "http cache header: \"%s: %s\"",
|
|
223 h->key.data, h->value.data);
|
|
224
|
|
225 continue;
|
|
226
|
|
227 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
|
|
228
|
|
229 /* a whole header has been parsed successfully */
|
|
230
|
|
231 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
|
232 "http cache header done");
|
|
233
|
|
234 c->ctx.file_start = p->header_in->pos - p->header_in->start;
|
|
235
|
|
236 return NGX_OK;
|
|
237
|
|
238 } else if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
|
|
239
|
|
240 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
|
241 "invalid header in \"%s\"",
|
|
242 c->ctx.file.name.data);
|
|
243 return NGX_ERROR;
|
|
244 }
|
|
245
|
|
246 /* rc == NGX_AGAIN || rc == NGX_HTTP_PARSE_TOO_LONG_HEADER */
|
|
247
|
|
248 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
|
249 "\"proxy_header_buffer_size\" "
|
|
250 "is too small to read header from \"%s\"",
|
|
251 c->ctx.file.name.data);
|
|
252 return NGX_ERROR;
|
|
253 }
|
|
254 }
|
|
255
|
|
256
|
|
257 void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p)
|
|
258 {
|
|
259 int rc, ft_type;
|
|
260
|
|
261 rc = ngx_http_busy_lock_cachable(p->lcf->busy_lock, &p->busy_lock,
|
|
262 p->try_busy_lock);
|
|
263
|
|
264 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
|
|
265 "http cache busy lock cachable: %d", rc);
|
|
266
|
|
267 if (rc == NGX_OK) {
|
|
268 if (p->try_busy_lock) {
|
|
269 p->busy_locked = 1;
|
|
270 p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
|
|
271 p->header_in->last = p->header_in->pos;
|
|
272
|
|
273 ngx_http_proxy_request_upstream(p);
|
|
274 return;
|
|
275 }
|
|
276
|
|
277 ngx_http_proxy_cache_look_complete_request(p);
|
|
278 return;
|
|
279 }
|
|
280
|
|
281 p->try_busy_lock = 0;
|
|
282
|
|
283 if (p->cache->ctx.file.fd != NGX_INVALID_FILE
|
|
284 && !p->cache->ctx.file.info_valid)
|
|
285 {
|
|
286 if (ngx_fd_info(p->cache->ctx.file.fd, &p->cache->ctx.file.info)
|
|
287 == NGX_FILE_ERROR)
|
|
288 {
|
|
289 ngx_log_error(NGX_LOG_CRIT, p->request->connection->log, ngx_errno,
|
|
290 ngx_fd_info_n " \"%s\" failed",
|
|
291 p->cache->ctx.file.name.data);
|
|
292 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
293 return;
|
|
294 }
|
|
295
|
|
296 p->cache->ctx.file.info_valid = 1;
|
|
297 }
|
|
298
|
|
299 if (rc == NGX_AGAIN) {
|
|
300
|
|
301 if ((ngx_event_flags & (NGX_USE_CLEAR_EVENT|NGX_HAVE_KQUEUE_EVENT))
|
|
302 && !p->request->connection->write->active)
|
|
303 {
|
|
304 /*
|
|
305 * kqueue allows to detect when client closes prematurely
|
|
306 * connection
|
|
307 */
|
|
308
|
|
309 p->request->connection->write->event_handler =
|
|
310 ngx_http_proxy_check_broken_connection;
|
|
311
|
|
312 if (ngx_add_event(p->request->connection->write, NGX_WRITE_EVENT,
|
|
313 NGX_CLEAR_EVENT) == NGX_ERROR)
|
|
314 {
|
|
315 ngx_http_proxy_finalize_request(p,
|
|
316 NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
317 return;
|
|
318 }
|
|
319 }
|
|
320
|
|
321 return;
|
|
322 }
|
|
323
|
|
324 ngx_http_busy_unlock(p->lcf->busy_lock, &p->busy_lock);
|
|
325
|
|
326 if (rc == NGX_DONE) {
|
|
327 ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
|
|
328
|
|
329 } else {
|
|
330 /* rc == NGX_ERROR */
|
|
331 ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
|
|
332 }
|
|
333
|
|
334 if (p->stale && (p->lcf->use_stale & ft_type)) {
|
|
335 ngx_http_proxy_finalize_request(p,
|
|
336 ngx_http_proxy_send_cached_response(p));
|
|
337 return;
|
|
338 }
|
|
339
|
|
340 p->state->status = NGX_HTTP_SERVICE_UNAVAILABLE;
|
|
341 ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
|
|
342 }
|
|
343
|
|
344
|
|
345 static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p)
|
|
346 {
|
|
347 int rc;
|
|
348 ngx_http_cache_ctx_t *ctx;
|
|
349
|
|
350 if (!(ctx = ngx_pcalloc(p->request->pool, sizeof(ngx_http_cache_ctx_t)))) {
|
|
351 ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
352 return;
|
|
353 }
|
|
354
|
|
355 *ctx = p->cache->ctx;
|
|
356
|
|
357 rc = ngx_http_cache_open_file(ctx, ngx_file_uniq(&p->cache->ctx.file.info));
|
|
358
|
|
359 if (rc == NGX_DECLINED || rc == NGX_HTTP_CACHE_THE_SAME) {
|
|
360 p->try_busy_lock = 1;
|
|
361 p->busy_lock.time = 0;
|
|
362 ngx_http_proxy_cache_busy_lock(p);
|
|
363 return;
|
|
364 }
|
|
365
|
|
366 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
|
|
367 "http cache old fd:%d, new fd:%d",
|
|
368 p->cache->ctx.file.fd, ctx->file.fd);
|
|
369
|
|
370 if (p->cache->ctx.file.fd != NGX_INVALID_FILE) {
|
|
371 if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) {
|
|
372 ngx_log_error(NGX_LOG_ALERT, p->request->connection->log, ngx_errno,
|
|
373 ngx_close_file_n " \"%s\" failed",
|
|
374 p->cache->ctx.file.name.data);
|
|
375 }
|
|
376 }
|
|
377
|
|
378 p->cache->ctx = *ctx;
|
|
379
|
|
380 p->status = 0;
|
|
381 p->status_count = 0;
|
|
382
|
|
383 ngx_http_proxy_finalize_request(p,
|
|
384 ngx_http_proxy_process_cached_response(p, rc));
|
|
385 }
|
|
386
|
|
387
|
|
388 int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p)
|
|
389 {
|
|
390 int rc, len, i;
|
|
391 off_t rest;
|
|
392 ngx_hunk_t *h0, *h1;
|
|
393 ngx_chain_t out[2];
|
|
394 ngx_http_request_t *r;
|
|
395
|
|
396 r = p->request;
|
|
397
|
|
398 r->headers_out.status = p->cache->status;
|
|
399
|
|
400 #if 0
|
|
401 r->headers_out.content_length_n = -1;
|
|
402 r->headers_out.content_length = NULL;
|
|
403 #endif
|
|
404
|
|
405 /* copy an cached header to r->headers_out */
|
|
406
|
|
407 if (ngx_http_proxy_copy_header(p, &p->cache->headers_in) == NGX_ERROR) {
|
|
408 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
409 }
|
|
410
|
|
411 /* we need to allocate all before the header would be sent */
|
|
412
|
|
413 len = p->header_in->end - (p->header_in->start + p->cache->ctx.file_start);
|
|
414
|
|
415 h0 = NULL;
|
|
416 h1 = NULL;
|
|
417
|
|
418 if (len) {
|
|
419 if (!((h0 = ngx_calloc_hunk(r->pool)))) {
|
|
420 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
421 }
|
|
422
|
|
423 if (!((h0->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
|
|
424 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
425 }
|
|
426 }
|
|
427
|
|
428 if (len < p->cache->ctx.length) {
|
|
429 if (!((h1 = ngx_calloc_hunk(r->pool)))) {
|
|
430 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
431 }
|
|
432
|
|
433 if (!((h1->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t))))) {
|
|
434 return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
|
435 }
|
|
436 }
|
|
437
|
|
438 rc = ngx_http_send_header(r);
|
|
439
|
|
440 /* NEEDED ??? */ p->header_sent = 1;
|
|
441
|
|
442 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
|
|
443 return rc;
|
|
444 }
|
|
445
|
|
446 rest = p->cache->ctx.length;
|
|
447
|
|
448 if (len) {
|
|
449 if (p->valid_header_in) {
|
|
450 h0->pos = p->header_in->start + p->cache->ctx.file_start;
|
|
451
|
|
452 if (len > p->cache->ctx.length) {
|
|
453 h0->last = h0->pos + p->cache->ctx.length;
|
|
454
|
|
455 } else {
|
|
456 h0->last = p->header_in->end;
|
|
457 }
|
|
458
|
|
459 h0->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
|
|
460 }
|
|
461
|
|
462 h0->type |= NGX_HUNK_FILE;
|
|
463 h0->file_pos = p->cache->ctx.file_start;
|
|
464
|
|
465 h0->file->fd = p->cache->ctx.file.fd;
|
|
466 h0->file->log = r->connection->log;
|
|
467
|
|
468 if (len > p->cache->ctx.length) {
|
|
469 h0->file_last = h0->file_pos + p->cache->ctx.length;
|
|
470 rest = 0;
|
|
471
|
|
472 } else {
|
|
473 h0->file_last = h0->file_pos + len;
|
|
474 rest -= len;
|
|
475 }
|
|
476
|
|
477 out[0].hunk = h0;
|
|
478 out[0].next = &out[1];
|
|
479 i = 0;
|
|
480
|
|
481 } else {
|
|
482 i = -1;
|
|
483 }
|
|
484
|
|
485 if (rest) {
|
|
486 h1->file_pos = p->cache->ctx.file_start + len;
|
|
487 h1->file_last = h1->file_pos + rest;
|
|
488 h1->type = NGX_HUNK_FILE;
|
|
489
|
|
490 h1->file->fd = p->cache->ctx.file.fd;
|
|
491 h1->file->log = r->connection->log;
|
|
492
|
|
493 out[++i].hunk = h1;
|
|
494 }
|
|
495
|
|
496 out[i].next = NULL;
|
|
497 if (!r->main) {
|
|
498 out[i].hunk->type |= NGX_HUNK_LAST;
|
|
499 }
|
|
500
|
|
501 r->file.fd = p->cache->ctx.file.fd;
|
|
502
|
|
503 return ngx_http_output_filter(r, out);
|
|
504 }
|
|
505
|
|
506
|
|
507 int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p)
|
|
508 {
|
|
509 time_t date, last_modified, expires, t;
|
|
510 ngx_http_proxy_headers_in_t *h;
|
|
511
|
|
512 switch (p->upstream->status) {
|
|
513 case NGX_HTTP_OK:
|
|
514 case NGX_HTTP_MOVED_PERMANENTLY:
|
|
515 case NGX_HTTP_MOVED_TEMPORARILY:
|
|
516 break;
|
|
517
|
|
518 #if 0
|
|
519 case NGX_HTTP_NOT_MODIFIED:
|
|
520 return 1;
|
|
521 #endif
|
|
522
|
|
523 default:
|
|
524 return 0;
|
|
525 }
|
|
526
|
|
527 h = &p->upstream->headers_in;
|
|
528
|
|
529 date = NGX_ERROR;
|
|
530 if (h->date) {
|
|
531 date = ngx_http_parse_time(h->date->value.data, h->date->value.len);
|
|
532 }
|
|
533 if (date == NGX_ERROR) {
|
|
534 date = ngx_time();
|
|
535 }
|
|
536 p->cache->ctx.date = date;
|
|
537
|
|
538 last_modified = NGX_ERROR;
|
|
539 if (h->last_modified) {
|
|
540 last_modified = ngx_http_parse_time(h->last_modified->value.data,
|
|
541 h->last_modified->value.len);
|
|
542 p->cache->ctx.last_modified = last_modified;
|
|
543 }
|
|
544
|
|
545 if (h->x_accel_expires) {
|
|
546 expires = ngx_atoi(h->x_accel_expires->value.data,
|
|
547 h->x_accel_expires->value.len);
|
|
548 if (expires != NGX_ERROR) {
|
|
549 p->state->reason = NGX_HTTP_PROXY_CACHE_XAE;
|
|
550 p->state->expires = expires;
|
|
551 p->cache->ctx.expires = date + expires;
|
|
552 return (expires > 0);
|
|
553 }
|
|
554 }
|
|
555
|
|
556 if (!p->lcf->ignore_expires) {
|
|
557
|
|
558 /* TODO: Cache-Control: no-cache, max-age= */
|
|
559
|
|
560 if (h->expires) {
|
|
561 expires = ngx_http_parse_time(h->expires->value.data,
|
|
562 h->expires->value.len);
|
|
563 if (expires != NGX_ERROR) {
|
|
564 p->state->reason = NGX_HTTP_PROXY_CACHE_EXP;
|
|
565 p->state->expires = expires - date;
|
|
566 p->cache->ctx.expires = expires;
|
|
567 return (date < expires);
|
|
568 }
|
|
569 }
|
|
570 }
|
|
571
|
|
572 if (p->upstream->status == NGX_HTTP_MOVED_PERMANENTLY) {
|
|
573 p->state->reason = NGX_HTTP_PROXY_CACHE_MVD;
|
|
574 p->state->expires = /* STUB: 1 hour */ 60 * 60;
|
|
575 p->cache->ctx.expires = /* STUB: 1 hour */ 60 * 60;
|
|
576 return 1;
|
|
577 }
|
|
578
|
|
579 if (p->upstream->status == NGX_HTTP_MOVED_TEMPORARILY) {
|
|
580 return 1;
|
|
581 }
|
|
582
|
|
583 if (last_modified != NGX_ERROR && p->lcf->lm_factor > 0) {
|
|
584
|
|
585 /* FIXME: time_t == int_64_t, we can use fpu */
|
|
586
|
|
587 p->state->reason = NGX_HTTP_PROXY_CACHE_LMF;
|
|
588 t = (time_t)
|
|
589 ((((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100);
|
|
590 p->state->expires = t;
|
|
591 p->cache->ctx.expires = ngx_time() + t;
|
|
592 return 1;
|
|
593 }
|
|
594
|
|
595 if (p->lcf->default_expires > 0) {
|
|
596 p->state->reason = NGX_HTTP_PROXY_CACHE_PDE;
|
|
597 p->state->expires = p->lcf->default_expires;
|
|
598 p->cache->ctx.expires = ngx_time() + p->lcf->default_expires;
|
|
599 return 1;
|
|
600 }
|
|
601
|
|
602 return 0;
|
|
603 }
|
|
604
|
|
605
|
|
606 int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
|
|
607 {
|
|
608 ngx_event_pipe_t *ep;
|
|
609
|
|
610 if (p->cache == NULL) {
|
|
611 return NGX_OK;
|
|
612 }
|
|
613
|
|
614 ep = p->upstream->event_pipe;
|
|
615
|
|
616 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->request->connection->log, 0,
|
|
617 "http cache update len: " OFF_T_FMT ":" OFF_T_FMT,
|
|
618 p->cache->ctx.length, ep->read_length);
|
|
619
|
|
620 if (p->cache->ctx.length == -1) {
|
|
621 /* TODO: test rc */
|
|
622 ngx_write_file(&ep->temp_file->file,
|
|
623 (char *) &ep->read_length, sizeof(off_t),
|
|
624 offsetof(ngx_http_cache_header_t, length));
|
|
625 }
|
|
626
|
|
627 return ngx_http_cache_update_file(p->request, &p->cache->ctx,
|
|
628 &ep->temp_file->file.name);
|
|
629 }
|