# HG changeset patch # User Igor Sysoev # Date 1283371200 -14400 # Node ID 6c96fdd2dfc3419755a0337ab50dd32123745ace # Parent 57dcc025db4fe59b77a1f5a68a2bc8a002ad8bd2 nginx 0.8.50 *) Feature: the "secure_link", "secure_link_md5", and "secure_link_expires" directives of the ngx_http_secure_link_module. *) Feature: the -q switch. Thanks to Gena Makhomed. *) Bugfix: worker processes may got caught in an endless loop during reconfiguration, if a caching was used; the bug had appeared in 0.8.48. *) Bugfix: in the "gzip_disable" directive. Thanks to Derrick Petzold. *) Bugfix: nginx/Windows could not send stop, quit, reopen, and reload signals to a process run in other session. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,23 @@ +Changes with nginx 0.8.50 02 Sep 2010 + + *) Feature: the "secure_link", "secure_link_md5", and + "secure_link_expires" directives of the ngx_http_secure_link_module. + + *) Feature: the -q switch. + Thanks to Gena Makhomed. + + *) Bugfix: worker processes may got caught in an endless loop during + reconfiguration, if a caching was used; the bug had appeared in + 0.8.48. + + *) Bugfix: in the "gzip_disable" directive. + Thanks to Derrick Petzold. + + *) Bugfix: nginx/Windows could not send stop, quit, reopen, and reload + signals to a process run in other session. + + Changes with nginx 0.8.49 09 Aug 2010 *) Feature: the "image_filter_jpeg_quality" directive supports @@ -51,8 +70,8 @@ Changes with nginx 0.8.47 *) Bugfix: errors intercepted by error_page could not be cached. - *) Bugfix: a cache manager process my got caught in an endless loop, if - max_size parameter was used; the bug had appeared in 0.8.46. + *) Bugfix: a cache manager process may got caught in an endless loop, + if max_size parameter was used; the bug had appeared in 0.8.46. Changes with nginx 0.8.46 19 Jul 2010 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,22 @@ +Изменения в nginx 0.8.50 02.09.2010 + + *) Добавление: директивы secure_link, secure_link_md5 и + secure_link_expires модуля ngx_http_secure_link_module. + + *) Добавление: ключ -q. + Спасибо Геннадию Махомеду. + + *) Исправление: при использовании кэширования рабочие процессы и могли + зациклиться во время переконфигурации; ошибка появилась в 0.8.48. + + *) Исправление: в директиве gzip_disable. + Спасибо Derrick Petzold. + + *) Исправление: nginx/Windows не мог посылать сигналы stop, quit, + reopen, reload процессу, запущенному в другой сессии. + + Изменения в nginx 0.8.49 09.08.2010 *) Добавление: директива image_filter_jpeg_quality поддерживает diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -212,7 +212,7 @@ main(int argc, char *const *argv) if (ngx_show_help) { ngx_log_stderr(0, - "Usage: nginx [-?hvVt] [-s signal] [-c filename] " + "Usage: nginx [-?hvVtq] [-s signal] [-c filename] " "[-p prefix] [-g directives]" CRLF CRLF "Options:" CRLF " -?,-h : this help" CRLF @@ -220,6 +220,8 @@ main(int argc, char *const *argv) " -V : show version and configure options then exit" CRLF " -t : test configuration and exit" CRLF + " -q : suppress non-error messages " + "during configuration testing" CRLF " -s signal : send signal to a master process: " "stop, quit, reopen, reload" CRLF #ifdef NGX_PREFIX @@ -332,8 +334,11 @@ main(int argc, char *const *argv) } if (ngx_test_config) { - ngx_log_stderr(0, "configuration file %s test is successful", - cycle->conf_file.data); + if (!ngx_quiet_mode) { + ngx_log_stderr(0, "configuration file %s test is successful", + cycle->conf_file.data); + } + return 0; } @@ -685,6 +690,10 @@ ngx_get_options(int argc, char *const *a ngx_test_config = 1; break; + case 'q': + ngx_quiet_mode = 1; + break; + case 'p': if (*p) { ngx_prefix = p; 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 8049 -#define NGINX_VERSION "0.8.49" +#define nginx_version 8050 +#define NGINX_VERSION "0.8.50" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -24,6 +24,7 @@ static ngx_pool_t *ngx_temp_pool; static ngx_event_t ngx_cleaner_event; ngx_uint_t ngx_test_config; +ngx_uint_t ngx_quiet_mode; #if (NGX_THREADS) ngx_tls_key_t ngx_core_tls_key; @@ -266,7 +267,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) return NULL; } - if (ngx_test_config) { + if (ngx_test_config && !ngx_quiet_mode) { ngx_log_stderr(0, "the configuration file %s syntax is ok", cycle->conf_file.data); } diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -130,6 +130,7 @@ extern volatile ngx_cycle_t *ngx_cycle; extern ngx_array_t ngx_old_cycles; extern ngx_module_t ngx_core_module; extern ngx_uint_t ngx_test_config; +extern ngx_uint_t ngx_quiet_mode; #if (NGX_THREADS) extern ngx_tls_key_t ngx_core_tls_key; #endif diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -10,6 +10,8 @@ static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width); +static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, + const u_char *basis); void @@ -1095,8 +1097,6 @@ ngx_encode_base64(ngx_str_t *dst, ngx_st ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src) { - size_t len; - u_char *d, *s; static u_char basis64[] = { 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, @@ -1117,12 +1117,49 @@ ngx_decode_base64(ngx_str_t *dst, ngx_st 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 }; + return ngx_decode_base64_internal(dst, src, basis64); +} + + +ngx_int_t +ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src) +{ + static u_char basis64[] = { + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77, + 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63, + 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77, + + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77 + }; + + return ngx_decode_base64_internal(dst, src, basis64); +} + + +static ngx_int_t +ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis) +{ + size_t len; + u_char *d, *s; + for (len = 0; len < src->len; len++) { if (src->data[len] == '=') { break; } - if (basis64[src->data[len]] == 77) { + if (basis[src->data[len]] == 77) { return NGX_ERROR; } } @@ -1135,20 +1172,20 @@ ngx_decode_base64(ngx_str_t *dst, ngx_st d = dst->data; while (len > 3) { - *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4); - *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2); - *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]); + *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4); + *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2); + *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]); s += 4; len -= 4; } if (len > 1) { - *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4); + *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4); } if (len > 2) { - *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2); + *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2); } dst->len = d - dst->data; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -178,6 +178,7 @@ u_char *ngx_hex_dump(u_char *dst, u_char void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src); ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src); +ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src); uint32_t ngx_utf8_decode(u_char **p, size_t n); size_t ngx_utf8_length(u_char *p, size_t n); diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -11,10 +11,23 @@ typedef struct { - ngx_str_t secret; + ngx_http_complex_value_t *variable; + ngx_http_complex_value_t *md5; + ngx_str_t secret; + ngx_flag_t expires; } ngx_http_secure_link_conf_t; +typedef struct { + ngx_str_t expires; +} ngx_http_secure_link_ctx_t; + + +static ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r, + ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v, + uintptr_t data); +static ngx_int_t ngx_http_secure_link_expires_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static void *ngx_http_secure_link_create_conf(ngx_conf_t *cf); static char *ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -23,6 +36,27 @@ static ngx_int_t ngx_http_secure_link_ad static ngx_command_t ngx_http_secure_link_commands[] = { + { ngx_string("secure_link"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_set_comlex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_secure_link_conf_t, variable), + NULL }, + + { ngx_string("secure_link_md5"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_set_comlex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_secure_link_conf_t, md5), + NULL }, + + { ngx_string("secure_link_expires"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_secure_link_conf_t, expires), + NULL }, + { ngx_string("secure_link_secret"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -65,27 +99,124 @@ ngx_module_t ngx_http_secure_link_modul }; -static ngx_str_t ngx_http_secure_link = ngx_string("secure_link"); +static ngx_str_t ngx_http_secure_link_name = ngx_string("secure_link"); +static ngx_str_t ngx_http_secure_link_expires_name = + ngx_string("secure_link_expires"); static ngx_int_t ngx_http_secure_link_variable(ngx_http_request_t *r, - ngx_http_variable_value_t *v, uintptr_t data) + ngx_http_variable_value_t *v, uintptr_t data) { - u_char *p, *start, *end, *last; - size_t len; - ngx_int_t n; - ngx_uint_t i; - ngx_md5_t md5; + u_char *p, *last; + ngx_str_t val, hash; + time_t expires; + ngx_md5_t md5; + ngx_http_secure_link_ctx_t *ctx; ngx_http_secure_link_conf_t *conf; - u_char hash[16]; + u_char hash_buf[16], md5_buf[16]; conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module); - if (conf->secret.len == 0) { + if (conf->secret.len) { + return ngx_http_secure_link_old_variable(r, conf, v, data); + } + + if (conf->variable == NULL || conf->md5 == NULL) { + goto not_found; + } + + if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "secure link: \"%V\"", &val); + + last = val.data + val.len; + + p = ngx_strlchr(val.data, last, ','); + expires = 0; + + if (p) { + val.len = p++ - val.data; + + if (conf->expires) { + expires = ngx_atotm(p, last - p); + if (expires <= 0) { + goto not_found; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module); + + ctx->expires.len = last - p; + ctx->expires.data = p; + } + } + + if (val.len > 24) { goto not_found; } + hash.len = 16; + hash.data = hash_buf; + + if (ngx_decode_base64url(&hash, &val) != NGX_OK) { + goto not_found; + } + + if (hash.len != 16) { + goto not_found; + } + + if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "secure link md5: \"%V\"", &val); + + ngx_md5_init(&md5); + ngx_md5_update(&md5, val.data, val.len); + ngx_md5_final(md5_buf, &md5); + + if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) { + goto not_found; + } + + v->data = (u_char *) ((expires && expires < ngx_time()) ? "0" : "1"); + v->len = 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_secure_link_old_variable(ngx_http_request_t *r, + ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v, + uintptr_t data) +{ + u_char *p, *start, *end, *last; + size_t len; + ngx_int_t n; + ngx_uint_t i; + ngx_md5_t md5; + u_char hash[16]; + p = &r->unparsed_uri.data[1]; last = r->unparsed_uri.data + r->unparsed_uri.len; @@ -145,6 +276,29 @@ not_found: } +static ngx_int_t +ngx_http_secure_link_expires_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_secure_link_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_secure_link_module); + + if (ctx) { + v->len = ctx->expires.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ctx->expires.data; + + } else { + v->not_found = 1; + } + + return NGX_OK; +} + + static void * ngx_http_secure_link_create_conf(ngx_conf_t *cf) { @@ -158,9 +312,13 @@ ngx_http_secure_link_create_conf(ngx_con /* * set by ngx_pcalloc(): * - * conf->secret = { 0, NULL } + * conf->variable = NULL; + * conf->md5 = NULL; + * conf->secret = { 0, NULL }; */ + conf->expires = NGX_CONF_UNSET; + return conf; } @@ -173,6 +331,16 @@ ngx_http_secure_link_merge_conf(ngx_conf ngx_conf_merge_str_value(conf->secret, prev->secret, ""); + if (conf->variable == NULL) { + conf->variable = prev->variable; + } + + if (conf->md5 == NULL) { + conf->md5 = prev->md5; + } + + ngx_conf_merge_value(conf->expires, prev->expires, 0); + return NGX_CONF_OK; } @@ -182,12 +350,19 @@ ngx_http_secure_link_add_variables(ngx_c { ngx_http_variable_t *var; - var = ngx_http_add_variable(cf, &ngx_http_secure_link, NGX_HTTP_VAR_NOHASH); + var = ngx_http_add_variable(cf, &ngx_http_secure_link_name, 0); if (var == NULL) { return NGX_ERROR; } var->get_handler = ngx_http_secure_link_variable; + var = ngx_http_add_variable(cf, &ngx_http_secure_link_expires_name, 0); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = ngx_http_secure_link_expires_variable; + return NGX_OK; } 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.49'; +our $VERSION = '0.8.50'; 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 @@ -43,7 +43,8 @@ typedef struct { unsigned error:10; unsigned exists:1; unsigned updating:1; - /* 12 unused bits */ + unsigned deleting:1; + /* 11 unused bits */ ngx_file_uniq_t uniq; time_t expire; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -3111,9 +3111,9 @@ ngx_http_core_create_loc_conf(ngx_conf_t clcf->gzip_http_version = NGX_CONF_UNSET_UINT; #if (NGX_PCRE) clcf->gzip_disable = NGX_CONF_UNSET_PTR; +#endif clcf->gzip_disable_msie6 = 3; #endif -#endif return clcf; } @@ -3788,13 +3788,19 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c n = ngx_http_script_variables_count(&clcf->root); ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + sc.variables = n; + +#if (NGX_PCRE) + if (alias && clcf->regex) { + n = 1; + } +#endif if (n) { sc.cf = cf; sc.source = &clcf->root; sc.lengths = &clcf->root_lengths; sc.values = &clcf->root_values; - sc.variables = n; sc.complete_lengths = 1; sc.complete_values = 1; @@ -4384,7 +4390,7 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng for (i = 1; i < cf->args->nelts; i++) { - if (ngx_strcmp(value[1].data, "msie6") == 0) { + if (ngx_strcmp(value[i].data, "msie6") == 0) { clcf->gzip_disable_msie6 = 1; continue; } @@ -4394,7 +4400,7 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng return NGX_CONF_ERROR; } - rc.pattern = value[1]; + rc.pattern = value[i]; rc.options = NGX_REGEX_CASELESS; if (ngx_regex_compile(&rc) != NGX_OK) { 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 @@ -582,6 +582,7 @@ ngx_http_file_cache_exists(ngx_http_file fcn->uses = 1; fcn->count = 1; fcn->updating = 0; + fcn->deleting = 0; renew: @@ -1102,6 +1103,10 @@ ngx_http_file_cache_expire(ngx_http_file continue; } + if (fcn->deleting) { + continue; + } + p = ngx_hex_dump(key, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); @@ -1153,6 +1158,7 @@ ngx_http_file_cache_delete(ngx_http_file *p = '\0'; fcn->count++; + fcn->deleting = 1; ngx_shmtx_unlock(&cache->shpool->mutex); len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; @@ -1168,6 +1174,7 @@ ngx_http_file_cache_delete(ngx_http_file ngx_shmtx_lock(&cache->shpool->mutex); fcn->count--; + fcn->deleting = 0; } if (fcn->count == 0) { @@ -1431,6 +1438,7 @@ ngx_http_file_cache_add(ngx_http_file_ca fcn->error = 0; fcn->exists = 1; fcn->updating = 0; + fcn->deleting = 0; fcn->uniq = c->uniq; fcn->valid_sec = c->valid_sec; fcn->body_start = c->body_start; 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,42 @@ ngx_http_compile_complex_value(ngx_http_ } +char * +ngx_http_set_comlex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_http_complex_value_t **cv; + ngx_http_compile_complex_value_t ccv; + + cv = (ngx_http_complex_value_t **) (p + cmd->offset); + + if (*cv != NULL) { + return "duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates) { 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 @@ -207,6 +207,9 @@ void ngx_http_script_flush_complex_value ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, 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); +char * ngx_http_set_comlex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates);