Klaus Demo nginx / 52859f2
a prelimiary proxy cache support Igor Sysoev 13 years ago
25 changed file(s) with 2608 addition(s) and 1795 deletion(s). Raw diff Collapse all Expand all
6161 if [ $HTTP != YES ]; then
6262 have=NGX_CRYPT . auto/nohave
6363 CRYPT_LIB=
64 fi
65
66
67 if [ $HTTP_CACHE = YES ]; then
68 USE_MD5=YES
69 have=NGX_HTTP_CACHE . auto/have
70 HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS"
6471 fi
6572
6673
304311 HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS"
305312 fi
306313
307 # STUB
308 #USE_MD5=YES
309 #HTTP_SRCS="$HTTP_SRCS $HTTP_CACHE_SRCS"
310 #HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS"
311
312314 if [ $HTTP_STUB_STATUS = YES ]; then
313315 have=NGX_STAT_STUB . auto/have
314316 HTTP_MODULES="$HTTP_MODULES ngx_http_stub_status_module"
5151 NGX_HTTP_PROXY_TEMP_PATH=
5252 NGX_HTTP_FASTCGI_TEMP_PATH=
5353
54 HTTP_CACHE=YES
5455 HTTP_CHARSET=YES
5556 HTTP_GZIP=YES
5657 HTTP_SSL=NO
164165 --with-ipv6) NGX_IPV6=YES ;;
165166
166167 --without-http) HTTP=NO ;;
168 --without-http-cache) HTTP_CACHE=NO ;;
169
167170 --http-log-path=*) NGX_HTTP_LOG_PATH="$value" ;;
168171 --http-client-body-temp-path=*) NGX_HTTP_CLIENT_TEMP_PATH="$value" ;;
169172 --http-proxy-temp-path=*) NGX_HTTP_PROXY_TEMP_PATH="$value" ;;
336339 files
337340
338341 --without-http disable HTTP server
342 --without-http-cache disable HTTP cache
339343
340344 --with-mail enable POP3/IMAP4/SMTP proxy module
341345 --with-mail_ssl_module enable ngx_mail_ssl_module
3232 src/core/ngx_cycle.h \
3333 src/core/ngx_conf_file.h \
3434 src/core/ngx_resolver.h \
35 src/core/ngx_open_file_cache.h \
36 src/core/ngx_garbage_collector.h"
35 src/core/ngx_open_file_cache.h"
3736
3837
3938 CORE_SRCS="src/core/nginx.c \
6160 src/core/ngx_cpuinfo.c \
6261 src/core/ngx_conf_file.c \
6362 src/core/ngx_resolver.c \
64 src/core/ngx_open_file_cache.c \
65 src/core/ngx_garbage_collector.c"
63 src/core/ngx_open_file_cache.c"
6664
6765
6866 REGEX_DEPS=src/core/ngx_regex.h
252250 ngx_http_core_module \
253251 ngx_http_log_module \
254252 ngx_http_upstream_module"
255
256 HTTP_CACHE_MODULE=ngx_http_cache_module
257253
258254 HTTP_WRITE_FILTER_MODULE="ngx_http_write_filter_module"
259255 HTTP_HEADER_FILTER_MODULE="ngx_http_header_filter_module"
312308
313309 HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c
314310
315 HTTP_CACHE_SRCS=src/http/ngx_http_cache.c
316311 HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c
317312
318313
263263 }
264264
265265 path->len = 0;
266 path->cleaner = (ngx_gc_handler_pt) cmd->post;
266 path->cleaner = (ngx_path_cleaner_pt) cmd->post;
267267 path->conf_file = cf->conf_file->file.name.data;
268268 path->line = cf->conf_file->line;
269269
284284 *slot = path;
285285
286286 if (ngx_add_path(cf, slot) == NGX_ERROR) {
287 return NGX_CONF_ERROR;
288 }
289
290 return NGX_CONF_OK;
291 }
292
293
294 char *
295 ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
296 ngx_path_init_t *init)
297 {
298 if (*path) {
299 return NGX_CONF_OK;
300 }
301
302 if (prev) {
303 *path = prev;
304 return NGX_CONF_OK;
305 }
306
307 *path = ngx_palloc(cf->pool, sizeof(ngx_path_t));
308 if (*path == NULL) {
309 return NGX_CONF_ERROR;
310 }
311
312 (*path)->name = init->name;
313
314 if (ngx_conf_full_name(cf->cycle, &(*path)->name, 0) != NGX_OK) {
315 return NGX_CONF_ERROR;
316 }
317
318 (*path)->level[0] = init->level[0];
319 (*path)->level[1] = init->level[1];
320 (*path)->level[2] = init->level[2];
321
322 (*path)->len = init->level[0] + (init->level[0] ? 1 : 0)
323 + init->level[1] + (init->level[1] ? 1 : 0)
324 + init->level[2] + (init->level[2] ? 1 : 0);
325
326 (*path)->cleaner = NULL;
327 (*path)->conf_file = NULL;
328
329 if (ngx_add_path(cf, path) != NGX_OK) {
287330 return NGX_CONF_ERROR;
288331 }
289332
1010 #include <ngx_config.h>
1111 #include <ngx_core.h>
1212
13 typedef struct ngx_path_s ngx_path_t;
14
15 #include <ngx_garbage_collector.h>
16
1713
1814 struct ngx_file_s {
19 ngx_fd_t fd;
20 ngx_str_t name;
21 ngx_file_info_t info;
15 ngx_fd_t fd;
16 ngx_str_t name;
17 ngx_file_info_t info;
2218
23 off_t offset;
24 off_t sys_offset;
19 off_t offset;
20 off_t sys_offset;
2521
26 ngx_log_t *log;
22 ngx_log_t *log;
2723
28 unsigned valid_info:1;
29 unsigned directio:1;
24 unsigned valid_info:1;
25 unsigned directio:1;
3026 };
3127
3228 #define NGX_MAX_PATH_LEVEL 3
3329
34 struct ngx_path_s {
35 ngx_str_t name;
36 size_t len;
37 size_t level[3];
38 ngx_gc_handler_pt cleaner;
3930
40 u_char *conf_file;
41 ngx_uint_t line;
42 };
31 typedef time_t (*ngx_path_cleaner_pt) (void *data);
4332
4433
4534 typedef struct {
46 ngx_file_t file;
47 off_t offset;
48 ngx_path_t *path;
49 ngx_pool_t *pool;
50 char *warn;
35 ngx_str_t name;
36 size_t len;
37 size_t level[3];
5138
52 ngx_uint_t access;
39 ngx_path_cleaner_pt cleaner;
40 void *data;
5341
54 unsigned log_level:8;
55 unsigned persistent:1;
56 unsigned clean:1;
42 u_char *conf_file;
43 ngx_uint_t line;
44 } ngx_path_t;
45
46
47 typedef struct {
48 ngx_str_t name;
49 size_t level[3];
50 } ngx_path_init_t;
51
52
53 typedef struct {
54 ngx_file_t file;
55 off_t offset;
56 ngx_path_t *path;
57 ngx_pool_t *pool;
58 char *warn;
59
60 ngx_uint_t access;
61
62 unsigned log_level:8;
63 unsigned persistent:1;
64 unsigned clean:1;
5765 } ngx_temp_file_t;
5866
5967
6068 typedef struct {
61 ngx_uint_t access;
62 ngx_uint_t path_access;
63 time_t time;
64 ngx_fd_t fd;
65 ngx_err_t rename_error;
69 ngx_uint_t access;
70 ngx_uint_t path_access;
71 time_t time;
72 ngx_fd_t fd;
73 ngx_err_t rename_error;
6674
67 unsigned create_path:1;
68 unsigned delete_file:1;
69 unsigned log_rename_error:1;
75 unsigned create_path:1;
76 unsigned delete_file:1;
77 unsigned log_rename_error:1;
7078
71 ngx_log_t *log;
79 ngx_log_t *log;
7280 } ngx_ext_rename_file_t;
7381
7482
112120 ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
113121
114122 char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
123 char *ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path,
124 ngx_path_t *prev, ngx_path_init_t *init);
115125 char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
116126
117127
118 #define ngx_conf_merge_path_value(curr, prev, path, l1, l2, l3, clean, cf) \
119 if (curr == NULL) { \
120 if (prev == NULL) { \
121 curr = ngx_palloc(cf->pool, sizeof(ngx_path_t)); \
122 if (curr == NULL) { \
123 return NGX_CONF_ERROR; \
124 } \
125 \
126 curr->name.len = sizeof(path) - 1; \
127 curr->name.data = (u_char *) path; \
128 \
129 if (ngx_conf_full_name(cf->cycle, &curr->name, 0) == NGX_ERROR) { \
130 return NGX_CONF_ERROR; \
131 } \
132 \
133 curr->level[0] = l1; \
134 curr->level[1] = l2; \
135 curr->level[2] = l3; \
136 curr->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0); \
137 curr->cleaner = clean; \
138 curr->conf_file = NULL; \
139 \
140 if (ngx_add_path(cf, &curr) == NGX_ERROR) { \
141 return NGX_CONF_ERROR; \
142 } \
143 \
144 } else { \
145 curr = prev; \
146 } \
147 }
148
149
150
151128 #endif /* _NGX_FILE_H_INCLUDED_ */
+0
-217
src/core/ngx_garbage_collector.c less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8
9
10
11 ngx_int_t ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, ngx_int_t level)
12 {
13 int rc;
14 u_char *last;
15 size_t len;
16 ngx_err_t err;
17 ngx_str_t fname, buf;
18 ngx_dir_t dir;
19
20 buf.len = 0;
21 #if (NGX_SUPPRESS_WARN)
22 buf.data = NULL;
23 fname.data = NULL;
24 #endif
25
26 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
27 "gc dir \"%s\":%d", dname->data, dname->len);
28
29 if (ngx_open_dir(dname, &dir) == NGX_ERROR) {
30 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
31 ngx_open_dir_n " \"%s\" failed", dname->data);
32 return NGX_ERROR;
33 }
34
35 for ( ;; ) {
36 ngx_set_errno(0);
37 if (ngx_read_dir(&dir) == NGX_ERROR) {
38 err = ngx_errno;
39
40 if (err != NGX_ENOMOREFILES) {
41 ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
42 ngx_read_dir_n " \"%s\" failed", dname->data);
43 rc = NGX_ERROR;
44
45 } else {
46 rc = NGX_OK;
47 }
48
49 break;
50 }
51
52 len = ngx_de_namelen(&dir);
53
54 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
55 "gc name \"%s\":%d", ngx_de_name(&dir), len);
56
57 if (len == 1 && ngx_de_name(&dir)[0] == '.') {
58 continue;
59 }
60
61 if (len == 2
62 && ngx_de_name(&dir)[0] == '.'
63 && ngx_de_name(&dir)[1] == '.')
64 {
65 continue;
66 }
67
68 fname.len = dname->len + 1+ len;
69
70 if (fname.len + NGX_DIR_MASK_LEN > buf.len) {
71
72 if (buf.len) {
73 ngx_free(buf.data);
74 }
75
76 buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN;
77
78 buf.data = ngx_alloc(buf.len + 1, ctx->log);
79 if (buf.data == NULL) {
80 return NGX_ABORT;
81 }
82 }
83
84 last = ngx_cpymem(buf.data, dname->data, dname->len);
85 *last++ = '/';
86 ngx_memcpy(last, ngx_de_name(&dir), len + 1);
87 fname.data = buf.data;
88
89 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
90 "gc path: \"%s\"", fname.data);
91
92 if (!dir.valid_info) {
93 if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) {
94 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
95 ngx_de_info_n " \"%s\" failed", fname.data);
96 continue;
97 }
98 }
99
100 if (ngx_de_is_dir(&dir)) {
101
102 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
103 "gc enter dir \"%s\"", fname.data);
104
105 if (level == -1
106 /* there can not be directory on the last level */
107 || level == NGX_MAX_PATH_LEVEL
108 /* an directory from the old path hierarchy */
109 || len != ctx->path->level[level])
110 {
111 if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) {
112 return NGX_ABORT;
113 }
114
115 fname.data[fname.len] = '\0';
116
117 ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
118 "delete old hierachy directory \"%s\"",
119 fname.data);
120
121 if (ngx_delete_dir(fname.data) == NGX_FILE_ERROR) {
122 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
123 ngx_delete_dir_n " \"%s\" failed",
124 fname.data);
125 } else {
126 ctx->deleted++;
127 ctx->freed += ngx_de_size(&dir);
128 }
129
130 continue;
131 }
132
133 if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) {
134 return NGX_ABORT;
135 }
136
137 } else if (ngx_de_is_file(&dir)) {
138
139 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
140 "gc file \"%s\"", fname.data);
141
142 if (level == -1
143 || (level < NGX_MAX_PATH_LEVEL && ctx->path->level[level] != 0))
144 {
145 if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
146 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
147 ngx_delete_file_n " \"%s\" failed",
148 fname.data);
149 } else {
150 ctx->deleted++;
151 ctx->freed += ngx_de_size(&dir);
152 }
153
154 continue;
155 }
156
157 if (ctx->handler(ctx, &fname, &dir) == NGX_ABORT) {
158 return NGX_ABORT;
159 }
160
161 } else {
162 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
163 "the file \"%s\" has unknown type, deleting",
164 fname.data);
165
166 if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
167 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
168 ngx_delete_file_n " \"%s\" failed", fname.data);
169 } else {
170 ctx->deleted++;
171 ctx->freed += ngx_de_size(&dir);
172 }
173 }
174 }
175
176 if (buf.len) {
177 ngx_free(buf.data);
178 }
179
180 if (ngx_close_dir(&dir) == NGX_ERROR) {
181 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
182 ngx_close_dir_n " \"%s\" failed", fname.data);
183 }
184
185 return rc;
186 }
187
188
189 ngx_int_t ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
190 ngx_dir_t *dir)
191 {
192 /*
193 * We use mtime only and do not use atime because:
194 * on NTFS access time has a resolution of 1 hour,
195 * on NT FAT access time has a resolution of 1 day,
196 * Unices have the mount option "noatime".
197 */
198
199 if (ngx_time() - ngx_de_mtime(dir) < 3600) {
200 return NGX_OK;
201 }
202
203 ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
204 "delete the stale temporary file \"%s\"", name->data);
205
206 if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
207 ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
208 ngx_delete_file_n " \"%s\" failed", name->data);
209 return NGX_ERROR;
210 }
211
212 ctx->deleted++;
213 ctx->freed += ngx_de_size(dir);
214
215 return NGX_OK;
216 }
+0
-31
src/core/ngx_garbage_collector.h less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #ifndef _NGX_GARBAGE_COLLECTOR_H_INCLUDED_
7 #define _NGX_GARBAGE_COLLECTOR_H_INCLUDED_
8
9
10 typedef struct ngx_gc_s ngx_gc_t;
11
12 typedef ngx_int_t (*ngx_gc_handler_pt) (ngx_gc_t *ctx, ngx_str_t *name,
13 ngx_dir_t *dir);
14
15
16 struct ngx_gc_s {
17 ngx_path_t *path;
18 u_int deleted;
19 off_t freed;
20 ngx_gc_handler_pt handler;
21 ngx_log_t *log;
22 };
23
24
25 ngx_int_t ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, ngx_int_t level);
26 ngx_int_t ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
27 ngx_dir_t *dir);
28
29
30 #endif /* _NGX_GARBAGE_COLLECTOR_H_INCLUDED_ */
325325
326326
327327 void
328 ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
329 {
330 ngx_pool_cleanup_t *c;
331 ngx_pool_cleanup_file_t *cf;
332
333 for (c = p->cleanup; c; c = c->next) {
334 if (c->handler == ngx_pool_cleanup_file) {
335
336 cf = c->data;
337
338 if (cf->fd == fd) {
339 c->handler(cf);
340 c->handler = NULL;
341 return;
342 }
343 }
344 }
345 }
346
347
348 void
328349 ngx_pool_cleanup_file(void *data)
329350 {
330351 ngx_pool_cleanup_file_t *c = data;
8181
8282
8383 ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
84 void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
8485 void ngx_pool_cleanup_file(void *data);
8586 void ngx_pool_delete_file(void *data);
8687
422422 size_t bsize;
423423 ngx_int_t rc;
424424 ngx_uint_t flush, prev_last_shadow;
425 ngx_chain_t *out, **ll, *cl;
425 ngx_chain_t *out, **ll, *cl, file;
426426 ngx_connection_t *downstream;
427427
428428 downstream = p->downstream;
485485 }
486486
487487 p->in = NULL;
488 }
489
490 if (p->cacheable && p->buf_to_file) {
491
492 file.buf = p->buf_to_file;
493 file.next = NULL;
494
495 if (ngx_write_chain_to_temp_file(p->temp_file, &file)
496 == NGX_ERROR)
497 {
498 return NGX_ABORT;
499 }
488500 }
489501
490502 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
287287 ngx_conf_set_path_slot,
288288 NGX_HTTP_LOC_CONF_OFFSET,
289289 offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
290 (void *) ngx_garbage_collector_temp_handler },
290 NULL },
291291
292292 { ngx_string("fastcgi_max_temp_file_size"),
293293 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
432432 ngx_string("X-Accel-Buffering"),
433433 ngx_string("X-Accel-Charset"),
434434 ngx_null_string
435 };
436
437
438 static ngx_path_init_t ngx_http_fastcgi_temp_path = {
439 ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
435440 };
436441
437442
19221927 |NGX_HTTP_UPSTREAM_FT_OFF;
19231928 }
19241929
1925 ngx_conf_merge_path_value(conf->upstream.temp_path,
1930 if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
19261931 prev->upstream.temp_path,
1927 NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0,
1928 ngx_garbage_collector_temp_handler, cf);
1932 &ngx_http_fastcgi_temp_path)
1933 != NGX_OK)
1934 {
1935 return NGX_CONF_ERROR;
1936 }
19291937
19301938 ngx_conf_merge_value(conf->upstream.pass_request_headers,
19311939 prev->upstream.pass_request_headers, 1);
8282 }
8383
8484 r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
85 r->headers_out.status_line.len = 0;
8586 r->headers_out.content_type.len = 0;
8687 ngx_http_clear_content_length(r);
8788 ngx_http_clear_accept_ranges(r);
3131
3232
3333 typedef struct {
34 ngx_str_t key_start;
3435 ngx_str_t schema;
3536 ngx_str_t host_header;
3637 ngx_str_t port;
8889
8990 static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
9091 ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
92 #if (NGX_HTTP_CACHE)
93 static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
94 #endif
9195 static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
9296 static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
9397 static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
115119 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
116120 static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
117121 void *parent, void *child);
122 static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf,
123 ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev);
118124
119125 static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
120126 void *conf);
122128 void *conf);
123129 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
124130 void *conf);
131 #if (NGX_HTTP_CACHE)
132 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
133 void *conf);
134 #endif
125135
126136 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
127137
134144 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
135145 ngx_http_proxy_loc_conf_t *plcf);
136146 #endif
137 static ngx_int_t ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
138 ngx_http_proxy_vars_t *v);
147 static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
139148
140149
141150 static ngx_conf_post_t ngx_http_proxy_lowat_post =
156165 };
157166
158167
168 ngx_module_t ngx_http_proxy_module;
169
170
159171 static ngx_command_t ngx_http_proxy_commands[] = {
160172
161173 { ngx_string("proxy_pass"),
305317 offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
306318 NULL },
307319
320 #if (NGX_HTTP_CACHE)
321
322 { ngx_string("proxy_cache"),
323 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
324 ngx_http_proxy_cache,
325 NGX_HTTP_LOC_CONF_OFFSET,
326 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache),
327 NULL },
328
329 { ngx_string("proxy_cache_path"),
330 NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
331 ngx_http_file_cache_set_slot,
332 0,
333 0,
334 &ngx_http_proxy_module },
335
336 { ngx_string("proxy_cache_valid"),
337 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
338 ngx_http_file_cache_valid_set_slot,
339 NGX_HTTP_LOC_CONF_OFFSET,
340 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
341 NULL },
342
343 { ngx_string("proxy_cache_min_uses"),
344 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
345 ngx_conf_set_num_slot,
346 NGX_HTTP_LOC_CONF_OFFSET,
347 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
348 NULL },
349
350 { ngx_string("proxy_cache_use_stale"),
351 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
352 ngx_conf_set_bitmask_slot,
353 NGX_HTTP_LOC_CONF_OFFSET,
354 offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
355 &ngx_http_proxy_next_upstream_masks },
356
357 #endif
358
308359 { ngx_string("proxy_temp_path"),
309360 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
310361 ngx_conf_set_path_slot,
311362 NGX_HTTP_LOC_CONF_OFFSET,
312363 offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
313 (void *) ngx_garbage_collector_temp_handler },
364 NULL },
314365
315366 { ngx_string("proxy_max_temp_file_size"),
316367 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
454505 };
455506
456507
508 static ngx_path_init_t ngx_http_proxy_temp_path = {
509 ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
510 };
511
512
457513 static ngx_int_t
458514 ngx_http_proxy_handler(ngx_http_request_t *r)
459515 {
501557
502558 u->conf = &plcf->upstream;
503559
560 #if (NGX_HTTP_CACHE)
561 u->create_key = ngx_http_proxy_create_key;
562 #endif
504563 u->create_request = ngx_http_proxy_create_request;
505564 u->reinit_request = ngx_http_proxy_reinit_request;
506565 u->process_header = ngx_http_proxy_process_status_line;
536595 ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
537596 ngx_http_proxy_loc_conf_t *plcf)
538597 {
539 u_char *p;
540 size_t add;
541 u_short port;
542 ngx_str_t proxy;
543 ngx_url_t u;
598 u_char *p;
599 size_t add;
600 u_short port;
601 ngx_str_t proxy;
602 ngx_url_t url;
603 ngx_http_upstream_t *u;
544604
545605 if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
546606 plcf->proxy_values->elts)
570630 return NGX_ERROR;
571631 }
572632
573 r->upstream->schema.len = add;
574 r->upstream->schema.data = proxy.data;
575
576 ngx_memzero(&u, sizeof(ngx_url_t));
577
578 u.url.len = proxy.len - add;
579 u.url.data = proxy.data + add;
580 u.default_port = port;
581 u.uri_part = 1;
582 u.no_resolve = 1;
583
584 if (ngx_parse_url(r->pool, &u) != NGX_OK) {
585 if (u.err) {
633 u = r->upstream;
634
635 u->schema.len = add;
636 u->schema.data = proxy.data;
637
638 ngx_memzero(&url, sizeof(ngx_url_t));
639
640 url.url.len = proxy.len - add;
641 url.url.data = proxy.data + add;
642 url.default_port = port;
643 url.uri_part = 1;
644 url.no_resolve = 1;
645
646 if (ngx_parse_url(r->pool, &url) != NGX_OK) {
647 if (url.err) {
586648 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
587 "%s in upstream \"%V\"", u.err, &u.url);
649 "%s in upstream \"%V\"", url.err, &url.url);
588650 }
589651
590652 return NGX_ERROR;
591653 }
592654
593 if (u.uri.len && u.uri.data[0] == '?') {
594 p = ngx_pnalloc(r->pool, u.uri.len + 1);
655 if (url.uri.len && url.uri.data[0] == '?') {
656 p = ngx_pnalloc(r->pool, url.uri.len + 1);
595657 if (p == NULL) {
596658 return NGX_ERROR;
597659 }
598660
599661 *p++ = '/';
600 ngx_memcpy(p, u.uri.data, u.uri.len);
601
602 u.uri.len++;
603 u.uri.data = p - 1;
604 }
605
606 if (ngx_http_proxy_set_vars(r->pool, &u, &ctx->vars) != NGX_OK) {
662 ngx_memcpy(p, url.uri.data, url.uri.len);
663
664 url.uri.len++;
665 url.uri.data = p - 1;
666 }
667
668 ctx->vars.key_start = u->schema;
669
670 ngx_http_proxy_set_vars(&url, &ctx->vars);
671
672 u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
673 if (u->resolved == NULL) {
607674 return NGX_ERROR;
608675 }
609676
610 r->upstream->resolved = ngx_pcalloc(r->pool,
611 sizeof(ngx_http_upstream_resolved_t));
612 if (r->upstream->resolved == NULL) {
677 if (url.addrs && url.addrs[0].sockaddr) {
678 u->resolved->sockaddr = url.addrs[0].sockaddr;
679 u->resolved->socklen = url.addrs[0].socklen;
680 u->resolved->naddrs = 1;
681 u->resolved->host = url.addrs[0].name;
682
683 } else {
684 u->resolved->host = url.host;
685 u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
686 u->resolved->no_port = url.no_port;
687 }
688
689 return NGX_OK;
690 }
691
692
693 #if (NGX_HTTP_CACHE)
694
695 static ngx_int_t
696 ngx_http_proxy_create_key(ngx_http_request_t *r)
697 {
698 size_t len, loc_len;
699 u_char *p;
700 uintptr_t escape;
701 ngx_str_t *key;
702 ngx_http_upstream_t *u;
703 ngx_http_proxy_ctx_t *ctx;
704 ngx_http_proxy_loc_conf_t *plcf;
705
706 u = r->upstream;
707
708 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
709
710 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
711
712 key = ngx_array_push(&r->cache->keys);
713 if (key == NULL) {
613714 return NGX_ERROR;
614715 }
615716
616 if (u.addrs && u.addrs[0].sockaddr) {
617 r->upstream->resolved->sockaddr = u.addrs[0].sockaddr;
618 r->upstream->resolved->socklen = u.addrs[0].socklen;
619 r->upstream->resolved->naddrs = 1;
620 r->upstream->resolved->host = u.addrs[0].name;
621
717 *key = ctx->vars.key_start;
718
719 key = ngx_array_push(&r->cache->keys);
720 if (key == NULL) {
721 return NGX_ERROR;
722 }
723
724 if (plcf->proxy_lengths) {
725
726 *key = ctx->vars.uri;
727 u->uri = ctx->vars.uri;
728
729 return NGX_OK;
730
731 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
732 {
733 *key = r->unparsed_uri;
734 u->uri = r->unparsed_uri;
735
736 return NGX_OK;
737 }
738
739 loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
740
741 if (r->quoted_uri || r->internal) {
742 escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
743 r->uri.len - loc_len, NGX_ESCAPE_URI);
622744 } else {
623 r->upstream->resolved->host = u.host;
624 r->upstream->resolved->port = (in_port_t) (u.no_port ? u.default_port:
625 u.port);
626 r->upstream->resolved->no_port = u.no_port;
627 }
745 escape = 0;
746 }
747
748 len = ctx->vars.uri.len + r->uri.len - loc_len + escape
749 + sizeof("?") - 1 + r->args.len;
750
751 p = ngx_pnalloc(r->pool, len);
752 if (p == NULL) {
753 return NGX_ERROR;
754 }
755
756 key->data = p;
757
758 if (r->valid_location) {
759 p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
760 }
761
762 if (escape) {
763 ngx_escape_uri(p, r->uri.data + loc_len,
764 r->uri.len - loc_len, NGX_ESCAPE_URI);
765 p += r->uri.len - loc_len + escape;
766
767 } else {
768 p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
769 }
770
771 if (r->args.len > 0) {
772 *p++ = '?';
773 p = ngx_copy(p, r->args.data, r->args.len);
774 }
775
776 key->len = p - key->data;
777 u->uri = *key;
628778
629779 return NGX_OK;
630780 }
781
782 #endif
631783
632784
633785 static ngx_int_t
634786 ngx_http_proxy_create_request(ngx_http_request_t *r)
635787 {
636 size_t len, loc_len, body_len;
788 size_t len, uri_len, loc_len, body_len;
637789 uintptr_t escape;
638790 ngx_buf_t *b;
639791 ngx_str_t method;
674826 ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
675827
676828 if (plcf->proxy_lengths) {
677 len += ctx->vars.uri.len;
829 uri_len = ctx->vars.uri.len;
678830
679831 } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
680832 {
681833 unparsed_uri = 1;
682 len += r->unparsed_uri.len;
834 uri_len = r->unparsed_uri.len;
683835
684836 } else {
685837 loc_len = (r->valid_location && ctx->vars.uri.len) ?
690842 r->uri.len - loc_len, NGX_ESCAPE_URI);
691843 }
692844
693 len += ctx->vars.uri.len + r->uri.len - loc_len + escape
694 + sizeof("?") - 1 + r->args.len;
695 }
845 uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
846 + sizeof("?") - 1 + r->args.len;
847 }
848
849 if (uri_len == 0) {
850 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
851 "zero length URI to proxy");
852 return NGX_ERROR;
853 }
854
855 len += uri_len;
696856
697857 ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
698858
9791139 u = r->upstream;
9801140
9811141 if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
1142
1143 #if (NGX_HTTP_CACHE)
1144
1145 if (r->cache) {
1146 r->http_version = NGX_HTTP_VERSION_9;
1147 u->headers_in.status_n = NGX_HTTP_OK;
1148 return NGX_OK;
1149 }
1150
1151 #endif
1152
9821153 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
9831154 "upstream sent no valid HTTP/1.0 header");
9841155
9951166 return NGX_OK;
9961167 }
9971168
1169 if (u->state) {
1170 u->state->status = ctx->status;
1171 }
1172
9981173 u->headers_in.status_n = ctx->status;
999 u->state->status = ctx->status;
10001174
10011175 u->headers_in.status_line.len = ctx->status_end - ctx->status_start;
10021176 u->headers_in.status_line.data = ngx_pnalloc(r->pool,
16371811 *
16381812 * conf->upstream.bufs.num = 0;
16391813 * conf->upstream.next_upstream = 0;
1814 * conf->upstream.use_stale_cache = 0;
16401815 * conf->upstream.temp_path = NULL;
16411816 * conf->upstream.hide_headers_hash = { NULL, 0 };
16421817 * conf->upstream.uri = { 0, NULL };
16741849 conf->upstream.pass_request_headers = NGX_CONF_UNSET;
16751850 conf->upstream.pass_request_body = NGX_CONF_UNSET;
16761851
1852 #if (NGX_HTTP_CACHE)
1853 conf->upstream.cache = NGX_CONF_UNSET_PTR;
1854 conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
1855 conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
1856 #endif
1857
16771858 conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
16781859 conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
16791860
17011882 ngx_http_proxy_loc_conf_t *prev = parent;
17021883 ngx_http_proxy_loc_conf_t *conf = child;
17031884
1704 u_char *p;
1705 size_t size;
1706 uintptr_t *code;
1707 ngx_uint_t i;
1708 ngx_keyval_t *src, *s, *h;
1709 ngx_hash_key_t *hk;
1710 ngx_hash_init_t hash;
1711 ngx_http_proxy_redirect_t *pr;
1712 ngx_http_script_compile_t sc;
1713 ngx_http_script_copy_code_t *copy;
1885 size_t size;
1886 ngx_keyval_t *s;
1887 ngx_hash_init_t hash;
1888 ngx_http_proxy_redirect_t *pr;
1889 ngx_http_script_compile_t sc;
17141890
17151891 if (conf->upstream.store != 0) {
17161892 ngx_conf_merge_value(conf->upstream.store,
18492025 |NGX_HTTP_UPSTREAM_FT_OFF;
18502026 }
18512027
1852 ngx_conf_merge_path_value(conf->upstream.temp_path,
2028 if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
18532029 prev->upstream.temp_path,
1854 NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
1855 ngx_garbage_collector_temp_handler, cf);
2030 &ngx_http_proxy_temp_path)
2031 != NGX_OK)
2032 {
2033 return NGX_CONF_ERROR;
2034 }
2035
2036
2037 #if (NGX_HTTP_CACHE)
2038
2039 ngx_conf_merge_ptr_value(conf->upstream.cache,
2040 prev->upstream.cache, NULL);
2041
2042 if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
2043 ngx_shm_zone_t *shm_zone;
2044
2045 shm_zone = conf->upstream.cache;
2046
2047 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2048 "\"proxy_cache\" zone \"%V\" is unknown",
2049 &shm_zone->name);
2050
2051 return NGX_CONF_ERROR;
2052 }
2053
2054 ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
2055 prev->upstream.cache_min_uses, 1);
2056
2057 ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
2058 prev->upstream.cache_use_stale,
2059 (NGX_CONF_BITMASK_SET
2060 |NGX_HTTP_UPSTREAM_FT_OFF));
2061
2062 if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
2063 conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
2064 |NGX_HTTP_UPSTREAM_FT_OFF;
2065 }
2066
2067 ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
2068 prev->upstream.cache_valid, NULL);
2069
2070 if (conf->upstream.cache_valid == NULL) {
2071 conf->upstream.cache = NULL;
2072 }
2073
2074 #endif
18562075
18572076 if (conf->method.len == 0) {
18582077 conf->method = prev->method;
19832202 s->value.data = (u_char *) "$proxy_internal_body_length";
19842203 }
19852204
2205 if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
2206 return NGX_CONF_ERROR;
2207 }
2208
2209 return NGX_CONF_OK;
2210 }
2211
2212
2213 static ngx_int_t
2214 ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
2215 ngx_http_proxy_loc_conf_t *prev)
2216 {
2217 u_char *p;
2218 size_t size;
2219 uintptr_t *code;
2220 ngx_uint_t i;
2221 ngx_keyval_t *src, *s, *h;
2222 ngx_hash_key_t *hk;
2223 ngx_hash_init_t hash;
2224 ngx_http_script_compile_t sc;
2225 ngx_http_script_copy_code_t *copy;
19862226
19872227 if (conf->headers_source == NULL) {
19882228 conf->flushes = prev->flushes;
19932233 }
19942234
19952235 if (conf->headers_set_hash.buckets) {
1996 return NGX_CONF_OK;
2236 return NGX_OK;
19972237 }
19982238
19992239
20002240 conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_hash_key_t));
20012241 if (conf->headers_names == NULL) {
2002 return NGX_CONF_ERROR;
2242 return NGX_ERROR;
20032243 }
20042244
20052245 if (conf->headers_source == NULL) {
20062246 conf->headers_source = ngx_array_create(cf->pool, 4,
20072247 sizeof(ngx_keyval_t));
20082248 if (conf->headers_source == NULL) {
2009 return NGX_CONF_ERROR;
2249 return NGX_ERROR;
20102250 }
20112251 }
20122252
20132253 conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
20142254 if (conf->headers_set_len == NULL) {
2015 return NGX_CONF_ERROR;
2255 return NGX_ERROR;
20162256 }
20172257
20182258 conf->headers_set = ngx_array_create(cf->pool, 512, 1);
20192259 if (conf->headers_set == NULL) {
2020 return NGX_CONF_ERROR;
2260 return NGX_ERROR;
20212261 }
20222262
20232263
20332273
20342274 s = ngx_array_push(conf->headers_source);
20352275 if (s == NULL) {
2036 return NGX_CONF_ERROR;
2276 return NGX_ERROR;
20372277 }
20382278
20392279 *s = *h;
20512291
20522292 hk = ngx_array_push(conf->headers_names);
20532293 if (hk == NULL) {
2054 return NGX_CONF_ERROR;
2294 return NGX_ERROR;
20552295 }
20562296
20572297 hk->key = src[i].key;
20662306 copy = ngx_array_push_n(conf->headers_set_len,
20672307 sizeof(ngx_http_script_copy_code_t));
20682308 if (copy == NULL) {
2069 return NGX_CONF_ERROR;
2309 return NGX_ERROR;
20702310 }
20712311
20722312 copy->code = (ngx_http_script_code_pt)
20832323
20842324 copy = ngx_array_push_n(conf->headers_set, size);
20852325 if (copy == NULL) {
2086 return NGX_CONF_ERROR;
2326 return NGX_ERROR;
20872327 }
20882328
20892329 copy->code = ngx_http_script_copy_code;
21012341 copy = ngx_array_push_n(conf->headers_set_len,
21022342 sizeof(ngx_http_script_copy_code_t));
21032343 if (copy == NULL) {
2104 return NGX_CONF_ERROR;
2344 return NGX_ERROR;
21052345 }
21062346
21072347 copy->code = (ngx_http_script_code_pt)
21152355
21162356 copy = ngx_array_push_n(conf->headers_set, size);
21172357 if (copy == NULL) {
2118 return NGX_CONF_ERROR;
2358 return NGX_ERROR;
21192359 }
21202360
21212361 copy->code = ngx_http_script_copy_code;
21352375 sc.values = &conf->headers_set;
21362376
21372377 if (ngx_http_script_compile(&sc) != NGX_OK) {
2138 return NGX_CONF_ERROR;
2378 return NGX_ERROR;
21392379 }
21402380
21412381
21422382 copy = ngx_array_push_n(conf->headers_set_len,
21432383 sizeof(ngx_http_script_copy_code_t));
21442384 if (copy == NULL) {
2145 return NGX_CONF_ERROR;
2385 return NGX_ERROR;
21462386 }
21472387
21482388 copy->code = (ngx_http_script_code_pt)
21562396
21572397 copy = ngx_array_push_n(conf->headers_set, size);
21582398 if (copy == NULL) {
2159 return NGX_CONF_ERROR;
2399 return NGX_ERROR;
21602400 }
21612401
21622402 copy->code = ngx_http_script_copy_code;
21682408
21692409 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
21702410 if (code == NULL) {
2171 return NGX_CONF_ERROR;
2411 return NGX_ERROR;
21722412 }
21732413
21742414 *code = (uintptr_t) NULL;
21752415
21762416 code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
21772417 if (code == NULL) {
2178 return NGX_CONF_ERROR;
2418 return NGX_ERROR;
21792419 }
21802420
21812421 *code = (uintptr_t) NULL;
21832423
21842424 code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
21852425 if (code == NULL) {
2186 return NGX_CONF_ERROR;
2426 return NGX_ERROR;
21872427 }
21882428
21892429 *code = (uintptr_t) NULL;
22012441 conf->headers_names->nelts)
22022442 != NGX_OK)
22032443 {
2204 return NGX_CONF_ERROR;
2205 }
2206
2207 return NGX_CONF_OK;
2444 return NGX_ERROR;
2445 }
2446
2447 return NGX_OK;
22082448 }
22092449
22102450
22972537 return NGX_CONF_ERROR;
22982538 }
22992539
2300 if (ngx_http_proxy_set_vars(cf->pool, &u, &plcf->vars) != NGX_OK) {
2301 return NGX_CONF_ERROR;
2302 }
2303
23042540 plcf->vars.schema.len = add;
23052541 plcf->vars.schema.data = url->data;
2542 plcf->vars.key_start = plcf->vars.schema;
2543
2544 ngx_http_proxy_set_vars(&u, &plcf->vars);
2545
2546 clcf->handler = ngx_http_proxy_handler;
2547
23062548 plcf->location = clcf->name;
2307
2308 clcf->handler = ngx_http_proxy_handler;
23092549
23102550 if (clcf->named
23112551 #if (NGX_PCRE)
24722712 }
24732713
24742714
2715 #if (NGX_HTTP_CACHE)
2716
2717 static char *
2718 ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
2719 {
2720 ngx_http_proxy_loc_conf_t *plcf = conf;
2721
2722 ngx_str_t *value;
2723
2724 value = cf->args->elts;
2725
2726 if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
2727 return "is duplicate";
2728 }
2729
2730 if (ngx_strcmp(value[1].data, "off") == 0) {
2731 plcf->upstream.cache = NULL;
2732 return NGX_CONF_OK;
2733 }
2734
2735 plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
2736 &ngx_http_proxy_module);
2737 if (plcf->upstream.cache == NULL) {
2738 return NGX_CONF_ERROR;
2739 }
2740
2741 return NGX_CONF_OK;
2742 }
2743
2744 #endif
2745
2746
24752747 static char *
24762748 ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
24772749 {
25622834 #endif
25632835
25642836
2565 static ngx_int_t
2566 ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
2567 ngx_http_proxy_vars_t *v)
2837 static void
2838 ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
25682839 {
25692840 if (u->family != AF_UNIX) {
2841
25702842 if (u->no_port || u->port == u->default_port) {
2843
25712844 v->host_header = u->host;
25722845
25732846 if (u->default_port == 80) {
25842857 v->host_header.data = u->host.data;
25852858 v->port = u->port_text;
25862859 }
2860
2861 v->key_start.len += v->host_header.len;
25872862
25882863 } else {
25892864 v->host_header.len = sizeof("localhost") - 1;
25902865 v->host_header.data = (u_char *) "localhost";
25912866 v->port.len = 0;
25922867 v->port.data = (u_char *) "";
2868 v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
25932869 }
25942870
25952871 v->uri = u->uri;
2596
2597 return NGX_OK;
2598 }
2872 }
198198 ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
199199
200200 r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
201 r->headers_out.status_line.len = 0;
201202
202203 if (ctx->ranges.nelts == 1) {
203204 return ngx_http_range_singlepart_header(r, ctx);
707708 ngx_http_range_multipart_body(ngx_http_request_t *r,
708709 ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in)
709710 {
711 off_t body_start;
710712 ngx_buf_t *b, *buf;
711713 ngx_uint_t i;
712714 ngx_chain_t *out, *hcl, *rcl, *dcl, **ll;
715717 ll = &out;
716718 buf = in->buf;
717719 range = ctx->ranges.elts;
720
721 #if (NGX_HTTP_CACHE)
722 body_start = r->cached ? r->cache->body_start : 0;
723 #else
724 body_start = 0;
725 #endif
718726
719727 for (i = 0; i < ctx->ranges.nelts; i++) {
720728
776784 b->file = buf->file;
777785
778786 if (buf->in_file) {
779 b->file_pos = range[i].start;
780 b->file_last = range[i].end;
787 b->file_pos = body_start + range[i].start;
788 b->file_last = body_start + range[i].end;
781789 }
782790
783791 if (ngx_buf_in_memory(buf)) {
99
1010 #include <ngx_config.h>
1111 #include <ngx_core.h>
12 #include <ngx_garbage_collector.h>
1312
1413
15 typedef struct ngx_http_request_s ngx_http_request_t;
16 typedef struct ngx_http_upstream_s ngx_http_upstream_t;
17 typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t;
14 typedef struct ngx_http_request_s ngx_http_request_t;
15 typedef struct ngx_http_upstream_s ngx_http_upstream_t;
16 typedef struct ngx_http_cache_s ngx_http_cache_t;
17 typedef struct ngx_http_file_cache_s ngx_http_file_cache_t;
18 typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t;
1819
1920 typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r,
2021 ngx_table_elt_t *h, ngx_uint_t offset);
2122 typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r,
2223 ngx_http_request_t *sr, u_char *buf, size_t len);
2324
24
25 #if (NGX_HTTP_CACHE)
26 #include <ngx_http_cache.h>
27 #endif
28 /* STUB */
29 #include <ngx_http_cache.h>
3025
3126 #include <ngx_http_variables.h>
3227 #include <ngx_http_request.h>
3732 #include <ngx_http_script.h>
3833 #include <ngx_http_core_module.h>
3934
35 #if (NGX_HTTP_CACHE)
36 #include <ngx_http_cache.h>
37 #endif
4038 #if (NGX_HTTP_SSI)
4139 #include <ngx_http_ssi_filter_module.h>
4240 #endif
+0
-576
src/http/ngx_http_cache.c less more
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8 #include <ngx_http.h>
9
10
11 #if 0
12
13 static ngx_http_module_t ngx_http_cache_module_ctx = {
14 NULL, /* pre conf */
15
16 NULL, /* create main configuration */
17 NULL, /* init main configuration */
18
19 NULL, /* create server configuration */
20 NULL, /* merge server configuration */
21
22 NULL, /* create location configuration */
23 NULL /* merge location configuration */
24 };
25
26
27 ngx_module_t ngx_http_cache_module = {
28 NGX_MODULE,
29 &ngx_http_cache_module_ctx, /* module context */
30 NULL, /* module directives */
31 NGX_HTTP_MODULE, /* module type */
32 NULL, /* init module */
33 NULL /* init process */
34 };
35
36 #endif
37
38
39 static ngx_int_t ngx_http_cache_create(ngx_http_request_t *r)
40 {
41 ngx_str_t *key;
42
43 if (!(r->cache = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)))) {
44 return NGX_ERROR;
45 }
46
47 if (ngx_array_init(&r->cache->key, r->pool, 5, sizeof(ngx_str_t))
48 == NGX_ERROR)
49 {
50 return NGX_ERROR;
51 }
52
53 /* preallocate the primary key */
54
55 if (!(key = ngx_array_push(&r->cache->key))) {
56 return NGX_ERROR;
57 }
58
59 key->len = 0;
60 key->data = NULL;
61
62 /*
63 * we use offsetof() because sizeof() pads the struct size to the int size
64 */
65
66 r->cache->header_size = offsetof(ngx_http_cache_header_t, key);
67
68 r->cache->log = r->connection->log;
69 r->cache->file.log = r->connection->log;
70
71 return NGX_OK;
72 }
73
74
75 ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx)
76 {
77 ngx_str_t *key;
78 ngx_http_cache_t *c;
79
80 if (r->cache == NULL) {
81 if (ngx_http_cache_create(r) == NGX_ERROR) {
82 return NGX_ABORT;
83 }
84 }
85
86 c = r->cache;
87 key = c->key.elts;
88
89 if (ctx->primary) {
90 key[0] = ctx->key;
91 c->header_size += ctx->key.len;
92 c->key_len += ctx->key.len;
93 c->buf = ctx->buf;
94
95 } else {
96 if (key[0].len == 0) {
97 key[0] = r->uri;
98 c->header_size += r->uri.len;
99 c->key_len += ctx->key.len;
100 }
101
102 if (!(key = ngx_array_push(&r->cache->key))) {
103 return NGX_ABORT;
104 }
105
106 c->header_size += ctx->key.len;
107 c->key_len += ctx->key.len;
108 }
109
110 #if 0
111
112 if (ctx->memory) {
113 ngx_http_memory_cache_get(r, ctx);
114 }
115
116 #endif
117
118 if (ctx->file) {
119 return ngx_http_file_cache_get(r, ctx);
120 }
121
122 return NGX_DECLINED;
123 }
124
125
126 #if 0
127
128
129 ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *hash,
130 ngx_http_cleanup_t *cleanup,
131 ngx_str_t *key, uint32_t *crc)
132 {
133 ngx_uint_t i;
134 ngx_http_cache_t *c;
135
136 *crc = ngx_crc(key->data, key->len);
137
138 c = hash->elts + *crc % hash->hash * hash->nelts;
139
140 if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
141 return (void *) NGX_ERROR;
142 }
143
144 for (i = 0; i < hash->nelts; i++) {
145 if (c[i].crc == *crc
146 && c[i].key.len == key->len
147 && ngx_rstrncmp(c[i].key.data, key->data, key->len) == 0)
148 {
149 #if 0
150 if (c[i].expired) {
151 ngx_mutex_unlock(&hash->mutex);
152 return (void *) NGX_AGAIN;
153 }
154 #endif
155
156 c[i].refs++;
157
158 if ((!(c[i].notify && (ngx_event_flags & NGX_USE_KQUEUE_EVENT)))
159 && (ngx_cached_time - c[i].updated >= hash->update))
160 {
161 c[i].expired = 1;
162 }
163
164 ngx_mutex_unlock(&hash->mutex);
165
166 if (cleanup) {
167 cleanup->data.cache.hash = hash;
168 cleanup->data.cache.cache = &c[i];
169 cleanup->valid = 1;
170 cleanup->cache = 1;
171 }
172
173 return &c[i];
174 }
175 }
176
177 ngx_mutex_unlock(&hash->mutex);
178
179 return NULL;
180 }
181
182
183 ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash,
184 ngx_http_cache_t *cache,
185 ngx_http_cleanup_t *cleanup,
186 ngx_str_t *key, uint32_t crc,
187 ngx_str_t *value, ngx_log_t *log)
188 {
189 time_t old;
190 ngx_uint_t i;
191 ngx_http_cache_t *c;
192
193 old = ngx_cached_time + 1;
194
195 c = hash->elts + crc % hash->hash * hash->nelts;
196
197 if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
198 return (void *) NGX_ERROR;
199 }
200
201 if (cache == NULL) {
202
203 /* allocate a new entry */
204
205 for (i = 0; i < hash->nelts; i++) {
206 if (c[i].refs > 0) {
207 /* a busy entry */
208 continue;
209 }
210
211 if (c[i].key.len == 0) {
212 /* a free entry is found */
213 cache = &c[i];
214 break;
215 }
216
217 /* looking for the oldest cache entry */
218
219 if (old > c[i].accessed) {
220
221 old = c[i].accessed;
222 cache = &c[i];
223 }
224 }
225
226 if (cache == NULL) {
227 ngx_mutex_unlock(&hash->mutex);
228 return NULL;
229 }
230
231 ngx_http_cache_free(cache, key, value, log);
232
233 if (cache->key.data == NULL) {
234 cache->key.data = ngx_alloc(key->len, log);
235 if (cache->key.data == NULL) {
236 ngx_http_cache_free(cache, NULL, NULL, log);
237 ngx_mutex_unlock(&hash->mutex);
238 return NULL;
239 }
240 }
241
242 cache->key.len = key->len;
243 ngx_memcpy(cache->key.data, key->data, key->len);
244
245 } else if (value) {
246 ngx_http_cache_free(cache, key, value, log);
247 }
248
249 if (value) {
250 if (cache->data.value.data == NULL) {
251 cache->data.value.data = ngx_alloc(value->len, log);
252 if (cache->data.value.data == NULL) {
253 ngx_http_cache_free(cache, NULL, NULL, log);
254 ngx_mutex_unlock(&hash->mutex);
255 return NULL;
256 }
257 }
258
259 cache->data.value.len = value->len;
260 ngx_memcpy(cache->data.value.data, value->data, value->len);
261 }
262
263 cache->crc = crc;
264 cache->key.len = key->len;
265
266 cache->refs = 1;
267 cache->count = 0;
268
269 cache->deleted = 0;
270 cache->expired = 0;
271 cache->memory = 0;
272 cache->mmap = 0;
273 cache->notify = 0;
274
275 if (cleanup) {
276 cleanup->data.cache.hash = hash;
277 cleanup->data.cache.cache = cache;
278 cleanup->valid = 1;
279 cleanup->cache = 1;
280 }
281
282 ngx_mutex_unlock(&hash->mutex);
283
284 return cache;
285 }
286
287
288 void ngx_http_cache_free(ngx_http_cache_t *cache,
289 ngx_str_t *key, ngx_str_t *value, ngx_log_t *log)
290 {
291 if (cache->memory) {
292 if (cache->data.value.data
293 && (value == NULL || value->len > cache->data.value.len))
294 {
295 ngx_free(cache->data.value.data);
296 cache->data.value.data = NULL;
297 }
298 }
299
300 /* TODO: mmap */
301
302 cache->data.value.len = 0;
303
304 if (cache->fd != NGX_INVALID_FILE) {
305
306 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
307 "http cache close fd: %d", cache->fd);
308
309 if (ngx_close_file(cache->fd) == NGX_FILE_ERROR) {
310 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
311 ngx_close_file_n " \"%s\" failed",
312 cache->key.data);
313 }
314
315 cache->fd = NGX_INVALID_FILE;
316 }
317
318 if (cache->key.data && (key == NULL || key->len > cache->key.len)) {
319 ngx_free(cache->key.data);
320 cache->key.data = NULL;
321 }
322
323 cache->key.len = 0;
324
325 cache->refs = 0;
326 }
327
328
329 void ngx_http_cache_lock(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache)
330 {
331 if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
332 return;
333 }
334 }
335
336
337 void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
338 ngx_http_cache_t *cache, ngx_log_t *log)
339 {
340 if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
341 return;
342 }
343
344 cache->refs--;
345
346 if (cache->refs == 0 && cache->deleted) {
347 ngx_http_cache_free(cache, NULL, NULL, log);
348 }
349
350 ngx_mutex_unlock(&hash->mutex);
351 }
352
353
354 #if 0
355
356 ngx_http_cache_add_file_event(ngx_http_cache_hash_t *hash,
357 ngx_http_cache_t *cache)
358 {
359 ngx_event_t *ev;
360 ngx_http_cache_event_ctx_t *ctx;
361
362 ev = &ngx_cycle->read_events[fd];
363 ngx_memzero(ev, sizeof(ngx_event_t);
364
365 ev->data = data;
366 ev->event_handler = ngx_http_cache_invalidate;
367
368 return ngx_add_event(ev, NGX_VNODE_EVENT, 0);
369 }
370
371
372 void ngx_http_cache_invalidate(ngx_event_t *ev)
373 {
374 ngx_http_cache_event_ctx_t *ctx;
375
376 ctx = ev->data;
377
378 ngx_http_cache_lock(&ctx->hash->mutex);
379
380 if (ctx->cache->refs == 0)
381 ngx_http_cache_free(ctx->cache, NULL, NULL, ctx->log);
382
383 } else {
384 ctx->cache->deleted = 1;
385 }
386
387 ngx_http_cache_unlock(&ctx->hash->mutex);
388 }
389
390 #endif
391
392
393 /* TODO: currently fd only */
394
395 ngx_int_t ngx_http_send_cached(ngx_http_request_t *r)
396 {
397 ngx_int_t rc;
398 ngx_hunk_t *h;
399 ngx_chain_t out;
400 ngx_http_log_ctx_t *ctx;
401
402 ctx = r->connection->log->data;
403 ctx->action = "sending response to client";
404
405 r->headers_out.status = NGX_HTTP_OK;
406 r->headers_out.content_length_n = r->cache->data.size;
407 r->headers_out.last_modified_time = r->cache->last_modified;
408
409 if (ngx_http_set_content_type(r) != NGX_OK) {
410 return NGX_HTTP_INTERNAL_SERVER_ERROR;
411 }
412
413 /* we need to allocate all before the header would be sent */
414
415 if (!(h = ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)))) {
416 return NGX_HTTP_INTERNAL_SERVER_ERROR;
417 }
418
419 if (!(h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
420 return NGX_HTTP_INTERNAL_SERVER_ERROR;
421 }
422
423 rc = ngx_http_send_header(r);
424
425 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
426 return rc;
427 }
428
429 h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
430
431 h->file_pos = 0;
432 h->file_last = r->cache->data.size;
433
434 h->file->fd = r->cache->fd;
435 h->file->log = r->connection->log;
436
437 out.hunk = h;
438 out.next = NULL;
439
440 return ngx_http_output_filter(r, &out);
441 }
442
443
444 char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
445 {
446 char *p = conf;
447
448 ngx_int_t i, j, dup, invalid;
449 ngx_str_t *value, line;
450 ngx_http_cache_t *c;
451 ngx_http_cache_hash_t *ch, **chp;
452
453 chp = (ngx_http_cache_hash_t **) (p + cmd->offset);
454 if (*chp) {
455 return "is duplicate";
456 }
457
458 if (!(ch = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_hash_t)))) {
459 return NGX_CONF_ERROR;
460 }
461 *chp = ch;
462
463 dup = 0;
464 invalid = 0;
465
466 value = cf->args->elts;
467
468 for (i = 1; i < cf->args->nelts; i++) {
469
470 if (value[i].data[1] != '=') {
471 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
472 "invalid value \"%s\"", value[i].data);
473 return NGX_CONF_ERROR;
474 }
475
476 switch (value[i].data[0]) {
477
478 case 'h':
479 if (ch->hash) {
480 dup = 1;
481 break;
482 }
483
484 ch->hash = ngx_atoi(value[i].data + 2, value[i].len - 2);
485 if (ch->hash == (size_t) NGX_ERROR || ch->hash == 0) {
486 invalid = 1;
487 break;
488 }
489
490 continue;
491
492 case 'n':
493 if (ch->nelts) {
494 dup = 1;
495 break;
496 }
497
498 ch->nelts = ngx_atoi(value[i].data + 2, value[i].len - 2);
499 if (ch->nelts == (size_t) NGX_ERROR || ch->nelts == 0) {
500 invalid = 1;
501 break;
502 }
503
504 continue;
505
506 case 'l':
507 if (ch->life) {
508 dup = 1;
509 break;
510 }
511
512 line.len = value[i].len - 2;
513 line.data = value[i].data + 2;
514
515 ch->life = ngx_parse_time(&line, 1);
516 if (ch->life == NGX_ERROR || ch->life == 0) {
517 invalid = 1;
518 break;
519 }
520
521 continue;
522
523 case 'u':
524 if (ch->update) {
525 dup = 1;
526 break;
527 }
528
529 line.len = value[i].len - 2;
530 line.data = value[i].data + 2;
531
532 ch->update = ngx_parse_time(&line, 1);
533 if (ch->update == NGX_ERROR || ch->update == 0) {
534 invalid = 1;
535 break;
536 }
537
538 continue;
539
540 default:
541 invalid = 1;
542 }
543
544 if (dup) {
545 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
546 "duplicate value \"%s\"", value[i].data);
547 return NGX_CONF_ERROR;
548 }
549
550 if (invalid) {
551 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
552 "invalid value \"%s\"", value[i].data);
553 return NGX_CONF_ERROR;
554 }
555 }
556
557 ch->elts = ngx_pcalloc(cf->pool,
558 ch->hash * ch->nelts * sizeof(ngx_http_cache_t));
559 if (ch->elts == NULL) {
560 return NGX_CONF_ERROR;
561 }
562
563 for (i = 0; i < (ngx_int_t) ch->hash; i++) {
564 c = ch->elts + i * ch->nelts;
565
566 for (j = 0; j < (ngx_int_t) ch->nelts; j++) {
567 c[j].fd = NGX_INVALID_FILE;
568 }
569 }
570
571 return NGX_CONF_OK;
572 }
573
574
575 #endif
1212 #include <ngx_http.h>
1313
1414
15 /*
16 * The 3 bits allows the 7 uses before the cache entry allocation.
17 * We can use maximum 7 bits, i.e up to the 127 uses.
18 */
19 #define NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS 3
15 /**/
16 #define NGX_HTTP_CACHE_STALE 1
17 #define NGX_HTTP_CACHE_AGED 2
18 #define NGX_HTTP_CACHE_THE_SAME 3
19 /**/
20
21 #define NGX_HTTP_CACHE_KEY_LEN 16
2022
2123
2224 typedef struct {
23 uint32_t crc;
24 ngx_str_t key;
25 time_t accessed;
25 ngx_uint_t status;
26 time_t valid;
27 } ngx_http_cache_valid_t;
2628
27 unsigned refs:20; /* 1048576 references */
2829
29 unsigned count:NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS;
30 /* ngx_http_file_cache_node_t takes exactly 64 bytes on FreeBSD/i386 */
3031
31 unsigned deleted:1;
32 unsigned expired:1;
33 unsigned memory:1;
34 unsigned mmap:1;
35 unsigned notify:1;
32 typedef struct {
33 ngx_rbtree_node_t node;
34 ngx_queue_t queue;
3635
37 ngx_fd_t fd;
38 #if (NGX_USE_HTTP_FILE_CACHE_UNIQ)
39 ngx_file_uniq_t uniq; /* no needed with kqueue */
40 #endif
41 time_t last_modified;
42 time_t updated;
36 u_char key[NGX_HTTP_CACHE_KEY_LEN
37 - sizeof(ngx_rbtree_key_t)];
4338
44 union {
45 off_t size;
46 ngx_str_t value;
47 } data;
48 } ngx_http_cache_entry_t;
39 unsigned count:20;
40 unsigned uses:10;
41 unsigned valid_msec:10;
42 unsigned error:10;
43 /* 7 unused bits */
44 unsigned exists:1;
45
46 ngx_file_uniq_t uniq;
47 time_t expire;
48 time_t valid_sec;
49 size_t body_start;
50 } ngx_http_file_cache_node_t;
51
52
53 struct ngx_http_cache_s {
54 ngx_file_t file;
55 ngx_array_t keys;
56 uint32_t crc32;
57 u_char key[NGX_HTTP_CACHE_KEY_LEN];
58
59 ngx_file_uniq_t uniq;
60 time_t valid_sec;
61 time_t last_modified;
62 time_t date;
63
64 size_t header_start;
65 size_t body_start;
66 off_t length;
67
68 ngx_uint_t min_uses;
69 ngx_uint_t uses;
70 ngx_uint_t error;
71 ngx_uint_t valid_msec;
72
73 ngx_buf_t *buf;
74
75 ngx_http_file_cache_t *file_cache;
76 ngx_http_file_cache_node_t *node;
77
78 unsigned updated:1;
79 unsigned exists:1;
80 unsigned temp_file:1;
81 };
4982
5083
5184 typedef struct {
52 time_t expires;
53 time_t last_modified;
54 time_t date;
55 off_t length;
56 size_t key_len;
57 char key[1];
58 } ngx_http_cache_header_t;
85 time_t valid_sec;
86 time_t last_modified;
87 time_t date;
88 uint32_t crc32;
89 u_short valid_msec;
90 u_short header_start;
91 u_short body_start;
92 } ngx_http_file_cache_header_t;
5993
6094
61 #define NGX_HTTP_CACHE_HASH 7
62 #define NGX_HTTP_CACHE_NELTS 4
95 struct ngx_http_file_cache_s {
96 ngx_rbtree_t *rbtree;
97 ngx_queue_t *queue;
98 ngx_slab_pool_t *shpool;
6399
64 typedef struct {
65 ngx_http_cache_entry_t *elts;
66 size_t hash;
67 size_t nelts;
68 time_t life;
69 time_t update;
70 #if (NGX_THREADS)
71 ngx_mutex_t mutex;
72 #endif
73 ngx_pool_t *pool;
74 } ngx_http_cache_hash_t;
100 ngx_path_t *path;
101
102 time_t inactive;
103 time_t created;
104 time_t clean_time;
105 time_t next_clean_time;
106
107 ngx_shm_zone_t *shm_zone;
108 };
75109
76110
77 typedef struct {
78 ngx_http_cache_hash_t *hash;
79 ngx_http_cache_entry_t *cache;
80 ngx_file_t file;
81 ngx_array_t key;
82 uint32_t crc;
83 u_char md5[16];
84 ngx_path_t *path;
85 ngx_buf_t *buf;
86 time_t expires;
87 time_t last_modified;
88 time_t date;
89 off_t length;
90 size_t key_len;
91 size_t file_start;
92 ngx_file_uniq_t uniq;
93 ngx_log_t *log;
94
95 /* STUB */
96 ssize_t header_size;
97 ngx_str_t key0;
98 } ngx_http_cache_t;
111 void ngx_http_file_cache_create_key(ngx_http_request_t *r);
112 ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r);
113 void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf);
114 void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf);
115 ngx_int_t ngx_http_cache_send(ngx_http_request_t *);
116 void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf);
117 time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status);
99118
100119
101 typedef struct {
102 ngx_path_t *path;
103 ngx_str_t key;
104 ngx_buf_t *buf;
105
106 unsigned file:1;
107 unsigned memory:1;
108 unsigned primary:1;
109 } ngx_http_cache_ctx_t;
110
111
112 #define NGX_HTTP_CACHE_STALE 1
113 #define NGX_HTTP_CACHE_AGED 2
114 #define NGX_HTTP_CACHE_THE_SAME 3
115
116
117 ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx);
118
119 ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r,
120 ngx_http_cache_ctx_t *ctx);
121
122 ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c);
123
124 ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name,
125 ngx_dir_t *dir);
126
127
128 #if 0
129
130 ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache,
131 ngx_http_cleanup_t *cleanup,
132 ngx_str_t *key, uint32_t *crc);
133
134 ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash,
135 ngx_http_cache_t *cache,
136 ngx_http_cleanup_t *cleanup,
137 ngx_str_t *key, uint32_t crc,
138 ngx_str_t *value, ngx_log_t *log);
139 void ngx_http_cache_free(ngx_http_cache_t *cache,
140 ngx_str_t *key, ngx_str_t *value, ngx_log_t *log);
141 void ngx_http_cache_lock(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache);
142 void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
143 ngx_http_cache_t *cache, ngx_log_t *log);
144
145 int ngx_http_cache_update_file(ngx_http_request_t *r,ngx_http_cache_ctx_t *ctx,
146 ngx_str_t *temp_file);
147
148 int ngx_http_send_cached(ngx_http_request_t *r);
149
150
151 char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
152
153 #endif
120 char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
121 void *conf);
122 char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
123 void *conf);
154124
155125
156126 #endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */
118118 };
119119
120120
121 static ngx_path_init_t ngx_http_client_temp_path = {
122 ngx_string(NGX_HTTP_CLIENT_TEMP_PATH), { 0, 0, 0 }
123 };
124
125
121126 #if (NGX_HTTP_GZIP)
122127
123128 static ngx_conf_enum_t ngx_http_gzip_http_version[] = {
346351 ngx_conf_set_path_slot,
347352 NGX_HTTP_LOC_CONF_OFFSET,
348353 offsetof(ngx_http_core_loc_conf_t, client_body_temp_path),
349 (void *) ngx_garbage_collector_temp_handler },
354 NULL },
350355
351356 { ngx_string("client_body_in_file_only"),
352357 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
21832188 r->loc_conf = cscf->ctx->loc_conf;
21842189
21852190 ngx_http_update_location_config(r);
2191
2192 #if (NGX_HTTP_CACHE)
2193 r->cache = NULL;
2194 #endif
21862195
21872196 r->internal = 1;
21882197
31553164 conf->resolver = prev->resolver;
31563165 }
31573166
3158 ngx_conf_merge_path_value(conf->client_body_temp_path,
3167 if (ngx_conf_merge_path_value(cf, &conf->client_body_temp_path,
31593168 prev->client_body_temp_path,
3160 NGX_HTTP_CLIENT_TEMP_PATH, 0, 0, 0,
3161 ngx_garbage_collector_temp_handler, cf);
3169 &ngx_http_client_temp_path)
3170 != NGX_OK)
3171 {
3172 return NGX_CONF_ERROR;
3173 }
31623174
31633175 ngx_conf_merge_value(conf->reset_timedout_connection,
31643176 prev->reset_timedout_connection, 0);
66 #include <ngx_config.h>
77 #include <ngx_core.h>
88 #include <ngx_http.h>
9
10
11 #if (NGX_HAVE_OPENSSL_MD5_H)
12 #include <openssl/md5.h>
13 #else
14 #include <md5.h>
15 #endif
16
17 #if (NGX_OPENSSL_MD5)
18 #define MD5Init MD5_Init
19 #define MD5Update MD5_Update
20 #define MD5Final MD5_Final
21 #endif
22
23
24 ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r,
25 ngx_http_cache_ctx_t *ctx)
26 {
9 #include <ngx_md5.h>
10
11
12 static ngx_int_t ngx_http_file_cache_exists(ngx_http_request_t *r,
13 ngx_http_file_cache_t *cache);
14 static ngx_http_file_cache_node_t *
15 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
16 static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
17 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
18 static void ngx_http_file_cache_cleanup(void *data);
19 static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache,
20 ngx_uint_t force);
21 static ngx_int_t ngx_http_file_cache_clean_noop(ngx_tree_ctx_t *ctx,
22 ngx_str_t *path);
23 static ngx_int_t ngx_http_file_cache_clean_file(ngx_tree_ctx_t *ctx,
24 ngx_str_t *path);
25
26
27 static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' };
28
29
30 static ngx_int_t
31 ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data)
32 {
33 ngx_http_file_cache_t *ocache = data;
34
35 ngx_rbtree_node_t *sentinel;
36 ngx_http_file_cache_t *cache;
37
38 cache = shm_zone->data;
39
40 if (ocache) {
41 if (ngx_strcmp(cache->path->name.data, ocache->path->name.data) != 0) {
42 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
43 "cache \"%V\" uses the \"%V\" cache path "
44 "while previously it used the \"%V\" cache path",
45 &shm_zone->name, &cache->path->name,
46 &ocache->path->name);
47
48 return NGX_ERROR;
49 }
50
51 cache->rbtree = ocache->rbtree;
52 cache->queue = ocache->queue;
53 cache->shpool = ocache->shpool;
54 cache->created = ocache->created;
55
56 return NGX_OK;
57 }
58
59 cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
60
61 cache->rbtree = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_t));
62 if (cache->rbtree == NULL) {
63 return NGX_ERROR;
64 }
65
66 sentinel = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_node_t));
67 if (sentinel == NULL) {
68 return NGX_ERROR;
69 }
70
71 ngx_rbtree_init(cache->rbtree, sentinel,
72 ngx_http_file_cache_rbtree_insert_value);
73
74 cache->queue = ngx_slab_alloc(cache->shpool, sizeof(ngx_queue_t));
75 if (cache->queue == NULL) {
76 return NGX_ERROR;
77 }
78
79 ngx_queue_init(cache->queue);
80
81 cache->created = ngx_time();
82
83 return NGX_OK;
84 }
85
86
87 void
88 ngx_http_file_cache_create_key(ngx_http_request_t *r)
89 {
90 size_t len;
91 ngx_str_t *key;
2792 ngx_uint_t i;
28 ngx_str_t *key;
93 ngx_md5_t md5;
2994 ngx_http_cache_t *c;
30 MD5_CTX md5;
3195
3296 c = r->cache;
3397
34 c->file.name.len = ctx->path->name.len + 1 + ctx->path->len + 32;
35 if (!(c->file.name.data = ngx_palloc(r->pool, c->file.name.len + 1))) {
36 return NGX_ABORT;
37 }
38
39 MD5Init(&md5);
40
41 key = c->key.elts;
42 for (i = 0; i < c->key.nelts; i++) {
43 MD5Update(&md5, key[i].data, key[i].len);
44 }
45
46 MD5Update(&md5, ctx->key.data, ctx->key.len);
47
48 MD5Final(c->md5, &md5);
49
50 ngx_memcpy(c->file.name.data, ctx->path->name.data, ctx->path->name.len);
51
52 ngx_md5_text(c->file.name.data + ctx->path->name.len + 1 + ctx->path->len,
53 c->md5);
54
55 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
56 "file cache key: %V, md5: %s", &ctx->key,
57 c->file.name.data + ctx->path->name.len + 1 + ctx->path->len);
58
59 ngx_create_hashed_filename(&c->file, ctx->path);
98 len = 0;
99
100 ngx_crc32_init(c->crc32);
101 ngx_md5_init(&md5);
102
103 key = c->keys.elts;
104 for (i = 0; i < c->keys.nelts; i++) {
105 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
106 "http cache key: \"%V\"", &key[i]);
107
108 len += key[i].len;
109
110 ngx_crc32_update(&c->crc32, key[i].data, key[i].len);
111 ngx_md5_update(&md5, key[i].data, key[i].len);
112 }
113
114 c->header_start = sizeof(ngx_http_file_cache_header_t)
115 + sizeof(ngx_http_file_cache_key) + len + 1;
116
117 ngx_crc32_final(c->crc32);
118 ngx_md5_final(c->key, &md5);
119 }
120
121
122 ngx_int_t
123 ngx_http_file_cache_open(ngx_http_request_t *r)
124 {
125 u_char *p;
126 time_t now;
127 ssize_t n;
128 ngx_int_t rc, rv;
129 ngx_uint_t cold, test;
130 ngx_path_t *path;
131 ngx_http_cache_t *c;
132 ngx_pool_cleanup_t *cln;
133 ngx_open_file_info_t of;
134 ngx_http_file_cache_t *cache;
135 ngx_http_core_loc_conf_t *clcf;
136 ngx_http_file_cache_header_t *h;
137
138 c = r->cache;
139 cache = c->file_cache;
140
141 cln = ngx_pool_cleanup_add(r->pool, 0);
142 if (cln == NULL) {
143 return NGX_ERROR;
144 }
145
146 rc = ngx_http_file_cache_exists(r, cache);
147
148 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
149 "http file cache exists: %i u:%ui e:%d",
150 rc, c->uses, c->exists);
151
152 if (rc == NGX_ERROR) {
153 return rc;
154 }
155
156 cln->handler = ngx_http_file_cache_cleanup;
157 cln->data = c;
158
159 if (rc == NGX_AGAIN) {
160 return rc;
161 }
162
163 now = ngx_time();
164
165 cold = (now - cache->created < cache->inactive) ? 1 : 0;
166
167 if (rc == NGX_OK) {
168
169 if (c->error) {
170 return c->error;
171 }
172
173 c->temp_file = 1;
174 test = c->exists ? 1 : 0;
175 rv = NGX_DECLINED;
176
177 } else { /* rc == NGX_DECLINED */
178
179 if (c->min_uses > 1) {
180
181 if (!cold) {
182 return NGX_AGAIN;
183 }
184
185 test = 1;
186 rv = NGX_AGAIN;
187
188 } else {
189 c->temp_file = 1;
190 test = cold ? 1 : 0;
191 rv = NGX_DECLINED;
192 }
193 }
194
195 path = cache->path;
196
197 c->file.name.len = path->name.len + 1 + path->len
198 + 2 * NGX_HTTP_CACHE_KEY_LEN;
199
200 c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
201 if (c->file.name.data == NULL) {
202 return NGX_ERROR;
203 }
204
205 ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
206
207 p = c->file.name.data + path->name.len + 1 + path->len;
208 p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
209 *p = '\0';
210
211 ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
212
213 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
214 "cache file: \"%s\"", c->file.name.data);
215
216 if (!test) {
217 return NGX_DECLINED;
218 }
219
220 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
221
222 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
223
224 of.uniq = c->uniq;
225 of.valid = clcf->open_file_cache_valid;
226 of.min_uses = clcf->open_file_cache_min_uses;
227 of.events = clcf->open_file_cache_events;
228 of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
229
230 if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool)
231 != NGX_OK)
232 {
233 switch (of.err) {
234
235 case 0:
236 return NGX_ERROR;
237
238 case NGX_ENOENT:
239 case NGX_ENOTDIR:
240 return rv;
241
242 default:
243 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
244 ngx_open_file_n " \"%s\" failed", c->file.name.data);
245 return NGX_ERROR;
246 }
247 }
60248
61249 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
62 "file cache name: %s", c->file.name.data);
63
64 return ngx_http_file_cache_open(r->cache);
65 }
66
67
68 ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c)
69 {
70 ssize_t n;
71 ngx_err_t err;
72 ngx_http_cache_header_t *h;
73
74 c->file.fd = ngx_open_file(c->file.name.data,
75 NGX_FILE_RDONLY, NGX_FILE_OPEN);
76
77 if (c->file.fd == NGX_INVALID_FILE) {
78 err = ngx_errno;
79
80 if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
81 return NGX_DECLINED;
82 }
83
84 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
85 ngx_open_file_n " \"%s\" failed", c->file.name.data);
250 "http file cache fd: %d", of.fd);
251
252 c->file.fd = of.fd;
253
254 c->buf = ngx_create_temp_buf(r->pool, c->body_start);
255 if (c->buf == NULL) {
86256 return NGX_ERROR;
87257 }
88258
89 if (c->uniq) {
90 if (ngx_fd_info(c->file.fd, &c->file.info) == NGX_FILE_ERROR) {
91 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
92 ngx_fd_info_n " \"%s\" failed", c->file.name.data);
93
94 return NGX_ERROR;
95 }
96
97 if (ngx_file_uniq(&c->file.info) == c->uniq) {
98 if (ngx_close_file(c->file.fd) == NGX_FILE_ERROR) {
99 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
100 ngx_close_file_n " \"%s\" failed",
101 c->file.name.data);
102 }
103
104 return NGX_HTTP_CACHE_THE_SAME;
105 }
106 }
107
108 n = ngx_read_file(&c->file, c->buf->pos, c->buf->end - c->buf->last, 0);
109
110 if (n == NGX_ERROR || n == NGX_AGAIN) {
259 n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
260
261 if (n == NGX_ERROR) {
111262 return n;
112263 }
113264
114 if (n <= c->header_size) {
115 ngx_log_error(NGX_LOG_CRIT, c->log, 0,
265 if ((size_t) n <= c->header_start) {
266 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
116267 "cache file \"%s\" is too small", c->file.name.data);
117268 return NGX_ERROR;
118269 }
119270
120 h = (ngx_http_cache_header_t *) c->buf->pos;
121 c->expires = h->expires;
122 c->last_modified= h->last_modified;
271 h = (ngx_http_file_cache_header_t *) c->buf->pos;
272
273 if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) {
274 ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
275 "cache file \"%s\" has md5 collision", c->file.name.data);
276 return NGX_DECLINED;
277 }
278
279 c->buf->last += n;
280
281 c->valid_sec = h->valid_sec;
282 c->last_modified = h->last_modified;
123283 c->date = h->date;
124 c->length = h->length;
125
126 if (h->key_len > (size_t) (c->buf->end - c->buf->pos)) {
127 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
128 "cache file \"%s\" is probably invalid",
129 c->file.name.data);
130 return NGX_DECLINED;
131 }
132
133 #if 0
134
135 /* TODO */
136
137 if (c->key_len && h->key_len != c->key_len) {
138
139 ngx_strncmp(h->key, c->key_data, h->key_len) != 0))
140
141 h->key[h->key_len] = '\0';
142 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
143 "md5 collision: \"%s\" and \"%s\"",
144 h->key, c->key.data);
145 return NGX_DECLINED;
146 }
147
148 #endif
149
150 c->buf->last += n;
151
152 if (c->expires < ngx_time()) {
153 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
154 "http file cache expired");
284 c->valid_msec = h->valid_msec;
285 c->length = of.size;
286 c->body_start = h->body_start;
287
288 r->cached = 1;
289
290 if (cold) {
291
292 ngx_shmtx_lock(&cache->shpool->mutex);
293
294 c->node->uses = c->min_uses;
295 c->node->body_start = c->body_start;
296 c->node->exists = 1;
297
298 ngx_shmtx_unlock(&cache->shpool->mutex);
299 }
300
301 if (c->valid_sec < now) {
302
303 c->uses = c->min_uses;
304
305 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
306 "http file cache expired: %T %T", c->valid_sec, now);
307
155308 return NGX_HTTP_CACHE_STALE;
156309 }
157310
158311 /* TODO: NGX_HTTP_CACHE_AGED */
159312
160 /* STUB */ return NGX_DECLINED;
161
162313 return NGX_OK;
163314 }
164315
165316
166 #if 0
167
168
169 int ngx_http_cache_update_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx,
170 ngx_str_t *temp_file)
171 {
172 int retry;
173 ngx_err_t err;
174
175 retry = 0;
317 static ngx_int_t
318 ngx_http_file_cache_exists(ngx_http_request_t *r, ngx_http_file_cache_t *cache)
319 {
320 ngx_int_t rc;
321 ngx_http_file_cache_node_t *fcn;
322
323 ngx_shmtx_lock(&cache->shpool->mutex);
324
325 fcn = ngx_http_file_cache_lookup(cache, r->cache->key);
326
327 if (fcn) {
328 ngx_queue_remove(&fcn->queue);
329
330 if (fcn->error) {
331
332 if (fcn->valid_sec < ngx_time()) {
333 goto renew;
334 }
335
336 rc = NGX_OK;
337
338 goto done;
339 }
340
341 fcn->uses++;
342 fcn->count++;
343
344 if (fcn->exists) {
345
346 r->cache->exists = fcn->exists;
347 r->cache->body_start = fcn->body_start;
348
349 rc = NGX_OK;
350
351 goto done;
352 }
353
354 if (fcn->uses >= r->cache->min_uses) {
355
356 r->cache->exists = fcn->exists;
357
358 if (fcn->body_start) {
359 r->cache->body_start = fcn->body_start;
360 }
361
362 rc = NGX_OK;
363
364 } else {
365 rc = NGX_AGAIN;
366 }
367
368 goto done;
369 }
370
371 fcn = ngx_slab_alloc_locked(cache->shpool,
372 sizeof(ngx_http_file_cache_node_t));
373 if (fcn == NULL) {
374 ngx_shmtx_unlock(&cache->shpool->mutex);
375
376 (void) ngx_http_file_cache_expire(cache, 1);
377
378 ngx_shmtx_lock(&cache->shpool->mutex);
379
380 fcn = ngx_slab_alloc_locked(cache->shpool,
381 sizeof(ngx_http_file_cache_node_t));
382 if (fcn == NULL) {
383 rc = NGX_ERROR;
384 goto failed;
385 }
386 }
387
388 ngx_memcpy((u_char *) &fcn->node.key, r->cache->key,
389 sizeof(ngx_rbtree_key_t));
390
391 ngx_memcpy(fcn->key, &r->cache->key[sizeof(ngx_rbtree_key_t)],
392 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
393
394 ngx_rbtree_insert(cache->rbtree, &fcn->node);
395
396 renew:
397
398 rc = NGX_DECLINED;
399
400 fcn->uses = 1;
401 fcn->count = 1;
402 fcn->valid_msec = 0;
403 fcn->error = 0;
404 fcn->exists = 0;
405 fcn->valid_sec = 0;
406 fcn->uniq = 0;
407 fcn->body_start = 0;
408
409 done:
410
411 fcn->expire = ngx_time() + cache->inactive;
412
413 ngx_queue_insert_head(cache->queue, &fcn->queue);
414
415 r->cache->uniq = fcn->uniq;
416 r->cache->uses = fcn->uses;
417 r->cache->error = fcn->error;
418 r->cache->node = fcn;
419
420 failed:
421
422 ngx_shmtx_unlock(&cache->shpool->mutex);
423
424 return rc;
425 }
426
427
428 static ngx_http_file_cache_node_t *
429 ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key)
430 {
431 ngx_int_t rc;
432 ngx_rbtree_key_t node_key;
433 ngx_rbtree_node_t *node, *sentinel;
434 ngx_http_file_cache_node_t *fcn;
435
436 ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t));
437
438 node = cache->rbtree->root;
439 sentinel = cache->rbtree->sentinel;
440
441 while (node != sentinel) {
442
443 if (node_key < node->key) {
444 node = node->left;
445 continue;
446 }
447
448 if (node_key > node->key) {
449 node = node->right;
450 continue;
451 }
452
453 /* node_key == node->key */
454
455 do {
456 fcn = (ngx_http_file_cache_node_t *) node;
457
458 rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key,
459 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
460
461 if (rc == 0) {
462 return fcn;
463 }
464
465 node = (rc < 0) ? node->left : node->right;
466
467 } while (node != sentinel && node_key == node->key);
468
469 break;
470 }
471
472 /* not found */
473
474 return NULL;
475 }
476
477
478 static void
479 ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
480 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
481 {
482 ngx_rbtree_node_t **p;
483 ngx_http_file_cache_node_t *cn, *cnt;
176484
177485 for ( ;; ) {
178 if (ngx_rename_file(temp_file->data, ctx->file.name.data) == NGX_OK) {
179 return NGX_OK;
180 }
181
182 err = ngx_errno;
183
184 #if (NGX_WIN32)
185 if (err == NGX_EEXIST) {
186 if (ngx_win32_rename_file(temp_file, &ctx->file.name, r->pool)
187 == NGX_ERROR)
188 {
189 return NGX_ERROR;
190 }
191 }
192 #endif
193
194 if (retry || (err != NGX_ENOENT && err != NGX_ENOTDIR)) {
195 ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
196 ngx_rename_file_n "(\"%s\", \"%s\") failed",
197 temp_file->data, ctx->file.name.data);
198
199 return NGX_ERROR;
200 }
201
202 if (ngx_create_path(&ctx->file, ctx->path) == NGX_ERROR) {
203 return NGX_ERROR;
204 }
205
206 retry = 1;
207 }
208 }
209
210
211 #endif
212
213
214 ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name,
215 ngx_dir_t *dir)
216 {
217 int rc;
218 ngx_buf_t buf;
219 ngx_http_cache_t c;
220 u_char data[sizeof(ngx_http_cache_header_t)];
221
222 ngx_memzero(&c, sizeof(ngx_http_cache_t));
223
224 c.file.fd = NGX_INVALID_FILE;
225 c.file.name = *name;
226 c.file.log = gc->log;
227
228 c.header_size = sizeof(ngx_http_cache_header_t);
229 c.buf = &buf;
230 c.log = gc->log;
231 c.key_len = 0;
232
233 buf.memory = 1;
234 buf.temporary = 1;
235 buf.pos = data;
236 buf.last = data;
237 buf.start = data;
238 buf.end = data + sizeof(ngx_http_cache_header_t);
239
240 rc = ngx_http_file_cache_open(&c);
241
242 /* TODO: NGX_AGAIN */
243
244 if (rc != NGX_ERROR&& rc != NGX_DECLINED && rc != NGX_HTTP_CACHE_STALE) {
486
487 if (node->key < temp->key) {
488
489 p = &temp->left;
490
491 } else if (node->key > temp->key) {
492
493 p = &temp->right;
494
495 } else { /* node->key == temp->key */
496
497 cn = (ngx_http_file_cache_node_t *) node;
498 cnt = (ngx_http_file_cache_node_t *) temp;
499
500 p = (ngx_memcmp(cn->key, cnt->key,
501 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t))
502 < 0)
503 ? &temp->left : &temp->right;
504 }
505
506 if (*p == sentinel) {
507 break;
508 }
509
510 temp = *p;
511 }
512
513 *p = node;
514 node->parent = temp;
515 node->left = sentinel;
516 node->right = sentinel;
517 ngx_rbt_red(node);
518 }
519
520
521 void
522 ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
523 {
524 ngx_http_file_cache_header_t *h = (ngx_http_file_cache_header_t *) buf;
525
526 u_char *p;
527 ngx_str_t *key;
528 ngx_uint_t i;
529 ngx_http_cache_t *c;
530
531 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
532 "http file cache set header");
533
534 c = r->cache;
535
536 h->valid_sec = c->valid_sec;
537 h->last_modified = c->last_modified;
538 h->date = c->date;
539 h->crc32 = c->crc32;
540 h->valid_msec = (u_short) c->valid_msec;
541 h->header_start = (u_short) c->header_start;
542 h->body_start = (u_short) c->body_start;
543
544 p = buf + sizeof(ngx_http_file_cache_header_t);
545
546 p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key));
547
548 key = c->keys.elts;
549 for (i = 0; i < c->keys.nelts; i++) {
550 p = ngx_copy(p, key[i].data, key[i].len);
551 }
552
553 *p = LF;
554 }
555
556
557 void
558 ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
559 {
560 ngx_int_t rc;
561 ngx_file_uniq_t uniq;
562 ngx_file_info_t fi;
563 ngx_http_cache_t *c;
564 ngx_ext_rename_file_t ext;
565 ngx_http_file_cache_t *cache;
566
567 c = r->cache;
568
569 if (c->updated) {
570 return;
571 }
572
573 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
574 "http file cache update");
575
576 c->updated = 1;
577
578 cache = c->file_cache;
579
580 uniq = 0;
581
582 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
583 "http file cache rename: \"%s\" to \"%s\"",
584 tf->file.name.data, c->file.name.data);
585
586 ext.access = NGX_FILE_OWNER_ACCESS;
587 ext.path_access = NGX_FILE_OWNER_ACCESS;
588 ext.time = -1;
589 ext.create_path = 1;
590 ext.delete_file = 1;
591 ext.log_rename_error = 1;
592 ext.log = r->connection->log;
593
594 rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);
595
596 if (rc == NGX_OK) {
597
598 if (ngx_fd_info(tf->file.fd, &fi) == NGX_FILE_ERROR) {
599 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
600 ngx_fd_info_n " \"%s\" failed", tf->file.name.data);
601
602 rc = NGX_ERROR;
603
604 } else {
605 uniq = ngx_file_uniq(&fi);
606 }
607 }
608
609 ngx_shmtx_lock(&cache->shpool->mutex);
610
611 c->node->count--;
612 c->node->uniq = uniq;
613 c->node->body_start = c->body_start;
614
615 if (rc == NGX_OK) {
616 c->node->exists = 1;
617 }
618
619 ngx_shmtx_unlock(&cache->shpool->mutex);
620 }
621
622
623 ngx_int_t
624 ngx_http_cache_send(ngx_http_request_t *r)
625 {
626 ngx_int_t rc;
627 ngx_buf_t *b;
628 ngx_chain_t out;
629 ngx_http_cache_t *c;
630
631 c = r->cache;
632
633 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
634 "http file cache send: %s", c->file.name.data);
635
636 /* we need to allocate all before the header would be sent */
637
638 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
639 if (b == NULL) {
640 return NGX_HTTP_INTERNAL_SERVER_ERROR;
641 }
642
643 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
644 if (b->file == NULL) {
645 return NGX_HTTP_INTERNAL_SERVER_ERROR;
646 }
647
648 rc = ngx_http_send_header(r);
649
650 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
651 return rc;
652 }
653
654 b->file_pos = c->body_start;
655 b->file_last = c->length;
656
657 b->in_file = (c->length - c->body_start) ? 1: 0;
658 b->last_buf = (r == r->main) ? 1: 0;
659 b->last_in_chain = 1;
660
661 b->file->fd = c->file.fd;
662 b->file->name = c->file.name;
663 b->file->log = r->connection->log;
664
665 out.buf = b;
666 out.next = NULL;
667
668 return ngx_http_output_filter(r, &out);
669 }
670
671
672 void
673 ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf)
674 {
675 ngx_http_cache_t *c;
676 ngx_http_file_cache_t *cache;
677
678 c = r->cache;
679
680 if (c->updated) {
681 return;
682 }
683
684 c->updated = 1;
685
686 cache = c->file_cache;
687
688 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
689 "http file cache free");
690
691 ngx_shmtx_lock(&cache->shpool->mutex);
692
693 c->node->count--;
694
695 if (c->error) {
696 c->node->valid_sec = c->valid_sec;
697 c->node->valid_msec = c->valid_msec;
698 c->node->error = c->error;
699 }
700
701 ngx_shmtx_unlock(&cache->shpool->mutex);
702
703 if (c->temp_file) {
704 if (tf && tf->file.fd != NGX_INVALID_FILE) {
705 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
706 "http file cache incomplete: \"%s\"",
707 tf->file.name.data);
708
709 if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
710 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
711 ngx_delete_file_n " \"%s\" failed",
712 tf->file.name.data);
713 }
714 }
715 }
716 }
717
718
719 static void
720 ngx_http_file_cache_cleanup(void *data)
721 {
722 ngx_http_cache_t *c = data;
723
724 ngx_http_file_cache_t *cache;
725
726 if (c->updated) {
727 return;
728 }
729
730 c->updated = 1;
731
732 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
733 "http file cache cleanup");
734
735 if (c->error) {
736 return;
737 }
738
739 cache = c->file_cache;
740
741 ngx_shmtx_lock(&cache->shpool->mutex);
742
743 c->node->count--;
744
745 ngx_shmtx_unlock(&cache->shpool->mutex);
746 }
747
748
749 static time_t
750 ngx_http_file_cache_expire(ngx_http_file_cache_t *cache, ngx_uint_t forced)
751 {
752 u_char *name, *p;
753 size_t len;
754 time_t now, wait;
755 ngx_uint_t tries;
756 ngx_path_t *path;
757 ngx_queue_t *q;
758 ngx_http_file_cache_node_t *fcn;
759 u_char key[2 * NGX_HTTP_CACHE_KEY_LEN];
760
761 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
762 "http file cache expire");
763
764 path = cache->path;
765 len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
766
767 now = ngx_time();
768
769 ngx_shmtx_lock(&cache->shpool->mutex);
770
771 tries = 0;
772
773 for ( ;; ) {
774
775 if (ngx_queue_empty(cache->queue)) {
776 wait = cache->inactive;
777 break;
778 }
779
780 q = ngx_queue_last(cache->queue);
781
782 fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
783
784 if (!forced) {
785 wait = fcn->expire - now;
786
787 if (wait > 0) {
788 break;
789 }
790 }
791
792 ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
793 "http file cache expire: #%d %d %02xd%02xd%02xd%02xd",
794 fcn->count, fcn->exists,
795 fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
796
797 if (fcn->count) {
798
799 if (!forced) {
800
801 p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
802 sizeof(ngx_rbtree_key_t));
803 (void) ngx_hex_dump(p, fcn->key,
804 NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
805
806 /*
807 * abnormally exited workers may leave locked cache entries,
808 * and although it may be safe to remove them completely,
809 * we prefer to remove them from inactive queue and rbtree
810 * only, and to allow other leaks
811 */
812
813 ngx_queue_remove(q);
814
815 ngx_rbtree_delete(cache->rbtree, &fcn->node);
816
817 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
818 "ignore long locked inactive cache entry %*s",
819 NGX_HTTP_CACHE_KEY_LEN, key);
820 }
821
822 if (tries++ < 10) {
823 continue;
824 }
825 </