# HG changeset patch # User Igor Sysoev # Date 1279483200 -14400 # Node ID b6a5942a4e6a372aea8083d8d714748f02482cdd # Parent 913af46ee7834d5699da5fce71e29eb07e69201b nginx 0.8.46 *) Change: now the "proxy_no_cache", "fastcgi_no_cache", "uwsgi_no_cache", and "scgi_no_cache" directives affect on a cached response saving only. *) Feature: the "proxy_cache_bypass", "fastcgi_cache_bypass", "uwsgi_cache_bypass", and "scgi_cache_bypass" directives. *) Bugfix: nginx did not free memory in cache keys zones if there was an error during working with backend: the memory was freed only after inactivity time or on memory low condition. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,18 @@ +Changes with nginx 0.8.46 19 Jul 2010 + + *) Change: now the "proxy_no_cache", "fastcgi_no_cache", + "uwsgi_no_cache", and "sсgi_no_cache" directives affect on a cached + response saving only. + + *) Feature: the "proxy_cache_bypass", "fastcgi_cache_bypass", + "uwsgi_cache_bypass", and "sсgi_cache_bypass" directives. + + *) Bugfix: nginx did not free memory in cache keys zones if there was + an error during working with backend: the memory was freed only + after inactivity time or on memory low condition. + + Changes with nginx 0.8.45 13 Jul 2010 *) Feature: ngx_http_xslt_filter improvements. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,18 @@ +Изменения в nginx 0.8.46 19.07.2010 + + *) Изменение: директивы proxy_no_cache, fastcgi_no_cache, + uwsgi_no_cache и sсgi_no_cache теперь влияют только на сохранение + закэшированного ответа. + + *) Добавление: директивы proxy_cache_bypass, fastcgi_cache_bypass, + uwsgi_cache_bypass и sсgi_cache_bypass. + + *) Исправление: nginx не освобождал память в keys_zone кэшей в случае + ошибки работы с бэкендом: память освобождалась только по истечении + времени неактивности или при недостатке памяти. + + Изменения в nginx 0.8.45 13.07.2010 *) Добавление: улучшения в модуле ngx_http_xslt_filter. diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 8045 -#define NGINX_VERSION "0.8.45" +#define nginx_version 8046 +#define NGINX_VERSION "0.8.46" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -330,9 +330,16 @@ static ngx_command_t ngx_http_fastcgi_c 0, &ngx_http_fastcgi_module }, + { ngx_string("fastcgi_cache_bypass"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_set_predicate_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_bypass), + NULL }, + { ngx_string("fastcgi_no_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_no_cache_set_slot, + ngx_http_set_predicate_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache), NULL }, @@ -1985,6 +1992,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; #endif @@ -2208,9 +2216,18 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD; + ngx_conf_merge_ptr_value(conf->upstream.cache_bypass, + prev->upstream.cache_bypass, NULL); + ngx_conf_merge_ptr_value(conf->upstream.no_cache, prev->upstream.no_cache, NULL); + if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "\"fastcgi_no_cache\" functionality has been changed in 0.8.46, " + "now it should be used together with \"fastcgi_cache_bypass\""); + } + ngx_conf_merge_ptr_value(conf->upstream.cache_valid, prev->upstream.cache_valid, NULL); diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -339,9 +339,16 @@ static ngx_command_t ngx_http_proxy_com 0, &ngx_http_proxy_module }, + { ngx_string("proxy_cache_bypass"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_set_predicate_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_bypass), + NULL }, + { ngx_string("proxy_no_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_no_cache_set_slot, + ngx_http_set_predicate_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache), NULL }, @@ -1678,6 +1685,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; #endif @@ -1902,9 +1910,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t |NGX_HTTP_UPSTREAM_FT_OFF; } + ngx_conf_merge_ptr_value(conf->upstream.cache_bypass, + prev->upstream.cache_bypass, NULL); + ngx_conf_merge_ptr_value(conf->upstream.no_cache, prev->upstream.no_cache, NULL); + if (conf->upstream.no_cache && conf->upstream.cache_bypass == NULL) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "\"proxy_no_cache\" functionality has been changed in 0.8.46, " + "now it should be used together with \"proxy_cache_bypass\""); + } + ngx_conf_merge_ptr_value(conf->upstream.cache_valid, prev->upstream.cache_valid, NULL); diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -196,9 +196,16 @@ static ngx_command_t ngx_http_scgi_comma 0, &ngx_http_scgi_module }, + { ngx_string("scgi_cache_bypass"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_set_predicate_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_scgi_loc_conf_t, upstream.cache_bypass), + NULL }, + { ngx_string("scgi_no_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_no_cache_set_slot, + ngx_http_set_predicate_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_scgi_loc_conf_t, upstream.no_cache), NULL }, @@ -1015,6 +1022,8 @@ ngx_http_scgi_create_loc_conf(ngx_conf_t #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; + conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; #endif @@ -1233,6 +1242,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD; + ngx_conf_merge_ptr_value(conf->upstream.cache_bypass, + prev->upstream.cache_bypass, NULL); + ngx_conf_merge_ptr_value(conf->upstream.no_cache, prev->upstream.no_cache, NULL); diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -223,9 +223,16 @@ static ngx_command_t ngx_http_uwsgi_comm 0, &ngx_http_uwsgi_module }, + { ngx_string("uwsgi_cache_bypass"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_set_predicate_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.cache_bypass), + NULL }, + { ngx_string("uwsgi_no_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_no_cache_set_slot, + ngx_http_set_predicate_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_uwsgi_loc_conf_t, upstream.no_cache), NULL }, @@ -1068,6 +1075,8 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_ #if (NGX_HTTP_CACHE) conf->upstream.cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_bypass = NGX_CONF_UNSET_PTR; + conf->upstream.no_cache = NGX_CONF_UNSET_PTR; conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; #endif @@ -1286,6 +1295,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD; + ngx_conf_merge_ptr_value(conf->upstream.cache_bypass, + prev->upstream.cache_bypass, NULL); + ngx_conf_merge_ptr_value(conf->upstream.no_cache, prev->upstream.no_cache, NULL); diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -48,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.8.45'; +our $VERSION = '0.8.46'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -14,11 +14,12 @@ #define NGX_HTTP_CACHE_MISS 1 -#define NGX_HTTP_CACHE_EXPIRED 2 -#define NGX_HTTP_CACHE_STALE 3 -#define NGX_HTTP_CACHE_UPDATING 4 -#define NGX_HTTP_CACHE_HIT 5 -#define NGX_HTTP_CACHE_SCARCE 6 +#define NGX_HTTP_CACHE_BYPASS 2 +#define NGX_HTTP_CACHE_EXPIRED 3 +#define NGX_HTTP_CACHE_STALE 4 +#define NGX_HTTP_CACHE_UPDATING 5 +#define NGX_HTTP_CACHE_HIT 6 +#define NGX_HTTP_CACHE_SCARCE 7 #define NGX_HTTP_CACHE_KEY_LEN 16 @@ -121,6 +122,8 @@ struct ngx_http_file_cache_s { }; +ngx_int_t ngx_http_file_cache_new(ngx_http_request_t *r); +ngx_int_t ngx_http_file_cache_create(ngx_http_request_t *r); void ngx_http_file_cache_create_key(ngx_http_request_t *r); ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r); void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf); @@ -134,10 +137,6 @@ char *ngx_http_file_cache_set_slot(ngx_c char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -ngx_int_t ngx_http_cache(ngx_http_request_t *r, ngx_array_t *no_cache); -char *ngx_http_no_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - extern ngx_str_t ngx_http_cache_status[]; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -19,6 +19,8 @@ static void ngx_http_cache_aio_event_han #endif static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_name(ngx_http_request_t *r, + ngx_path_t *path); static ngx_http_file_cache_node_t * ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, @@ -44,6 +46,7 @@ static ngx_int_t ngx_http_file_cache_del ngx_str_t ngx_http_cache_status[] = { ngx_string("MISS"), + ngx_string("BYPASS"), ngx_string("EXPIRED"), ngx_string("STALE"), ngx_string("UPDATING"), @@ -142,6 +145,59 @@ ngx_http_file_cache_init(ngx_shm_zone_t } +ngx_int_t +ngx_http_file_cache_new(ngx_http_request_t *r) +{ + ngx_http_cache_t *c; + + c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); + if (c == NULL) { + return NGX_ERROR; + } + + if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) { + return NGX_ERROR; + } + + r->cache = c; + c->file.log = r->connection->log; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_file_cache_create(ngx_http_request_t *r) +{ + ngx_http_cache_t *c; + ngx_pool_cleanup_t *cln; + ngx_http_file_cache_t *cache; + + ngx_http_file_cache_create_key(r); + + c = r->cache; + cache = c->file_cache; + + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + if (ngx_http_file_cache_exists(cache, c) == NGX_ERROR) { + return NGX_ERROR; + } + + cln->handler = ngx_http_file_cache_cleanup; + cln->data = c; + + if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + void ngx_http_file_cache_create_key(ngx_http_request_t *r) { @@ -180,10 +236,8 @@ ngx_http_file_cache_create_key(ngx_http_ ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r) { - u_char *p; ngx_int_t rc, rv; ngx_uint_t cold, test; - ngx_path_t *path; ngx_http_cache_t *c; ngx_pool_cleanup_t *cln; ngx_open_file_info_t of; @@ -249,27 +303,10 @@ ngx_http_file_cache_open(ngx_http_reques } } - path = cache->path; - - c->file.name.len = path->name.len + 1 + path->len - + 2 * NGX_HTTP_CACHE_KEY_LEN; - - c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1); - if (c->file.name.data == NULL) { + if (ngx_http_file_cache_name(r, cache->path) != NGX_OK) { return NGX_ERROR; } - ngx_memcpy(c->file.name.data, path->name.data, path->name.len); - - p = c->file.name.data + path->name.len + 1 + path->len; - p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN); - *p = '\0'; - - ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "cache file: \"%s\"", c->file.name.data); - if (!test) { return NGX_DECLINED; } @@ -574,6 +611,37 @@ failed: } +static ngx_int_t +ngx_http_file_cache_name(ngx_http_request_t *r, ngx_path_t *path) +{ + u_char *p; + ngx_http_cache_t *c; + + c = r->cache; + + c->file.name.len = path->name.len + 1 + path->len + + 2 * NGX_HTTP_CACHE_KEY_LEN; + + c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1); + if (c->file.name.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(c->file.name.data, path->name.data, path->name.len); + + p = c->file.name.data + path->name.len + 1 + path->len; + p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN); + *p = '\0'; + + ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "cache file: \"%s\"", c->file.name.data); + + return NGX_OK; +} + + static ngx_http_file_cache_node_t * ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key) { @@ -835,8 +903,9 @@ ngx_http_cache_send(ngx_http_request_t * void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf) { - ngx_http_cache_t *c; - ngx_http_file_cache_t *cache; + ngx_http_cache_t *c; + ngx_http_file_cache_t *cache; + ngx_http_file_cache_node_t *fcn; c = r->cache; @@ -853,16 +922,22 @@ ngx_http_file_cache_free(ngx_http_reques ngx_shmtx_lock(&cache->shpool->mutex); - c->node->count--; + fcn = c->node; + fcn->count--; + fcn->updating = 0; if (c->error) { - c->node->valid_sec = c->valid_sec; - c->node->valid_msec = c->valid_msec; - c->node->error = c->error; + fcn->valid_sec = c->valid_sec; + fcn->valid_msec = c->valid_msec; + fcn->error = c->error; + + } else if (fcn->valid_msec == 0 && fcn->count == 0) { + ngx_queue_remove(&fcn->queue); + ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); + ngx_slab_free_locked(cache->shpool, fcn); + c->node = NULL; } - c->node->updating = 0; - ngx_shmtx_unlock(&cache->shpool->mutex); if (c->temp_file) { @@ -1104,9 +1179,7 @@ ngx_http_file_cache_delete(ngx_http_file *p = '\0'; ngx_queue_remove(q); - ngx_rbtree_delete(&cache->sh->rbtree, &fcn->node); - ngx_slab_free_locked(cache->shpool, fcn); ngx_shmtx_unlock(&cache->shpool->mutex); diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -211,6 +211,76 @@ ngx_http_compile_complex_value(ngx_http_ } +ngx_int_t +ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates) +{ + ngx_str_t val; + ngx_uint_t i; + ngx_http_complex_value_t *cv; + + if (predicates == NULL) { + return NGX_OK; + } + + cv = predicates->elts; + + for (i = 0; i < predicates->nelts; i++) { + if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) { + return NGX_ERROR; + } + + if (val.len && val.data[0] != '0') { + return NGX_DECLINED; + } + } + + return NGX_OK; +} + + +char * +ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_uint_t i; + ngx_array_t **a; + ngx_http_complex_value_t *cv; + ngx_http_compile_complex_value_t ccv; + + a = (ngx_array_t **) (p + cmd->offset); + + if (*a == NGX_CONF_UNSET_PTR) { + *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + cv = ngx_array_push(*a); + if (cv == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[i]; + ccv.complex_value = cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} + + ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -208,6 +208,11 @@ ngx_int_t ngx_http_complex_value(ngx_htt ngx_http_complex_value_t *val, ngx_str_t *value); ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); +ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, + ngx_array_t *predicates); +char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value); ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc); u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -633,11 +633,17 @@ ngx_http_upstream_cache(ngx_http_request if (c == NULL) { - if (u->conf->no_cache) { - rc = ngx_http_cache(r, u->conf->no_cache); - if (rc != NGX_OK) { - return rc; - } + switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) { + + case NGX_ERROR: + return NGX_ERROR; + + case NGX_DECLINED: + u->cache_status = NGX_HTTP_CACHE_BYPASS; + return NGX_DECLINED; + + default: /* NGX_OK */ + break; } if (!(r->method & u->conf->cache_methods)) { @@ -648,18 +654,10 @@ ngx_http_upstream_cache(ngx_http_request u->method = ngx_http_core_get_method; } - c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); - if (c == NULL) { + if (ngx_http_file_cache_new(r) != NGX_OK) { return NGX_ERROR; } - if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) { - return NGX_ERROR; - } - - r->cache = c; - c->file.log = r->connection->log; - if (u->create_key(r) != NGX_OK) { return NGX_ERROR; } @@ -670,6 +668,8 @@ ngx_http_upstream_cache(ngx_http_request u->cacheable = 1; + c = r->cache; + c->min_uses = u->conf->cache_min_uses; c->body_start = u->conf->buffer_size; c->file_cache = u->conf->cache->data; @@ -2098,6 +2098,47 @@ ngx_http_upstream_send_response(ngx_http r->cache->file.fd = NGX_INVALID_FILE; } + switch (ngx_http_test_predicates(r, u->conf->no_cache)) { + + case NGX_ERROR: + ngx_http_upstream_finalize_request(r, u, 0); + return; + + case NGX_DECLINED: + u->cacheable = 0; + break; + + default: /* NGX_OK */ + + if (u->cache_status == NGX_HTTP_CACHE_BYPASS) { + + if (ngx_http_file_cache_new(r) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (u->create_key(r) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + /* TODO: add keys */ + + r->cache->min_uses = u->conf->cache_min_uses; + r->cache->body_start = u->conf->buffer_size; + r->cache->file_cache = u->conf->cache->data; + + if (ngx_http_file_cache_create(r) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + u->cacheable = 1; + } + + break; + } + if (u->cacheable) { time_t now, valid; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -163,7 +163,8 @@ typedef struct { ngx_uint_t cache_methods; ngx_array_t *cache_valid; - ngx_array_t *no_cache; /* ngx_http_complex_value_t */ + ngx_array_t *cache_bypass; + ngx_array_t *no_cache; #endif ngx_array_t *store_lengths;