From d28a070469220c901d160928cf4ee737df1fceca Mon Sep 17 00:00:00 2001 From: Roman Arutyunyan Date: Fri, 30 Jan 2026 21:15:04 +0400 Subject: [PATCH] Added ngx_http_eval_module. The module allows to evaluate nginx directive at runtime. A new location is created for the directives. The directives can be read from file or specified literally. In the latter case, the "data:" prefix should be used. Only the directives that have the NGX_DYNAMIC_CONF flag are allowed to appear in an eval location. The followup changes will take care of modifying the existing directives for this puspose. Modules need to follow the strict hierarchy rules to make their directives eligible for eval locations: - modules should not access main configurations - modules should not access server configurations - modules should not modify parent location configurations - modules should not access other modules' configurations except core module location condiguration It should be noted that while it's allowed to use variables inside dynamic locations, these variables remain unindexed and are accessed by name. Example: server { listen 8000; resolver 1.1.1.1; eval "data:proxy_pass http://example.com"; } --- auto/modules | 13 + auto/options | 3 + src/core/ngx_conf_file.c | 5 +- src/core/ngx_conf_file.h | 6 +- src/http/modules/ngx_http_eval_module.c | 534 ++++++++++++++++++++++++ src/http/ngx_http_core_module.h | 1 + src/http/ngx_http_script.c | 95 +++++ src/http/ngx_http_script.h | 9 + 8 files changed, 662 insertions(+), 4 deletions(-) create mode 100644 src/http/modules/ngx_http_eval_module.c diff --git a/auto/modules b/auto/modules index c199d89bf..14c569389 100644 --- a/auto/modules +++ b/auto/modules @@ -710,6 +710,19 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_EVAL = YES ]; then + have=NGX_HTTP_EVAL . auto/have + + ngx_module_name=ngx_http_eval_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_eval_module.c + ngx_module_libs= + ngx_module_link=$HTTP_EVAL + + . auto/module + fi + if [ $HTTP_SSL = YES ]; then USE_OPENSSL=YES have=NGX_HTTP_SSL . auto/have diff --git a/auto/options b/auto/options index 6a6e990a0..26aeefcc2 100644 --- a/auto/options +++ b/auto/options @@ -84,6 +84,7 @@ HTTP_MAP=YES HTTP_SPLIT_CLIENTS=YES HTTP_REFERER=YES HTTP_REWRITE=YES +HTTP_EVAL=YES HTTP_PROXY=YES HTTP_FASTCGI=YES HTTP_UWSGI=YES @@ -274,6 +275,7 @@ $0: warning: the \"--with-ipv6\" option is deprecated" --without-http_split_clients_module) HTTP_SPLIT_CLIENTS=NO ;; --without-http_referer_module) HTTP_REFERER=NO ;; --without-http_rewrite_module) HTTP_REWRITE=NO ;; + --without-http_eval_module) HTTP_EVAL=NO ;; --without-http_proxy_module) HTTP_PROXY=NO ;; --without-http_fastcgi_module) HTTP_FASTCGI=NO ;; --without-http_uwsgi_module) HTTP_UWSGI=NO ;; @@ -494,6 +496,7 @@ cat << END --without-http_split_clients_module disable ngx_http_split_clients_module --without-http_referer_module disable ngx_http_referer_module --without-http_rewrite_module disable ngx_http_rewrite_module + --without-http_eval_module disable ngx_http_eval_module --without-http_proxy_module disable ngx_http_proxy_module --without-http_fastcgi_module disable ngx_http_fastcgi_module --without-http_uwsgi_module disable ngx_http_uwsgi_module diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index 197704b0f..e4e22d538 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -12,7 +12,6 @@ static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename); static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); -static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); static void ngx_conf_flush_files(ngx_cycle_t *cycle); @@ -47,7 +46,7 @@ ngx_module_t ngx_conf_module = { /* The eight fixed arguments */ -static ngx_uint_t argument_number[] = { +ngx_uint_t argument_number[] = { NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_TAKE2, @@ -499,7 +498,7 @@ invalid: } -static ngx_int_t +ngx_int_t ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index ed2d2ba9d..5d74b400f 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -48,6 +48,8 @@ #define NGX_DIRECT_CONF 0x00010000 +#define NGX_DYNAMIC_CONF 0x00020000 + #define NGX_MAIN_CONF 0x01000000 #define NGX_ANY_CONF 0xFF000000 @@ -268,7 +270,7 @@ char *ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data); char *ngx_conf_param(ngx_conf_t *cf); char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename); char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - +ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix); @@ -291,5 +293,7 @@ char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +extern ngx_uint_t argument_number[]; + #endif /* _NGX_CONF_FILE_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_eval_module.c b/src/http/modules/ngx_http_eval_module.c new file mode 100644 index 000000000..12294cacf --- /dev/null +++ b/src/http/modules/ngx_http_eval_module.c @@ -0,0 +1,534 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_http_complex_value_t *value; +} ngx_http_eval_loc_conf_t; + + +static ngx_int_t ngx_http_eval_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_eval_read(ngx_http_request_t *r, + ngx_str_t *name, ngx_buf_t *buf); +static void **ngx_http_eval_create_location(ngx_http_request_t *r, + ngx_buf_t *buf); +static ngx_int_t ngx_http_eval_init(ngx_conf_t *cf); +static void *ngx_http_eval_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_eval_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); + + +static ngx_command_t ngx_http_eval_commands[] = { + + { ngx_string("eval"), + NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_http_set_complex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_eval_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_eval_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_eval_create_loc_conf, /* create location configuration */ + ngx_http_eval_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_eval_module = { + NGX_MODULE_V1, + &ngx_http_eval_module_ctx, /* module context */ + ngx_http_eval_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_eval_handler(ngx_http_request_t *r) +{ + void **loc_conf; + ngx_buf_t buf; + ngx_str_t name; + ngx_http_eval_loc_conf_t *elcf; + + elcf = ngx_http_get_module_loc_conf(r, ngx_http_eval_module); + + if (elcf->value == NULL) { + return NGX_DECLINED; + } + + if (ngx_http_complex_value(r, elcf->value, &name) != NGX_OK) { + return NGX_ERROR; + } + + if (name.len == 0) { + return NGX_DECLINED; + } + + if (ngx_http_eval_read(r, &name, &buf) != NGX_OK) { + return NGX_ERROR; + } + + loc_conf = ngx_http_eval_create_location(r, &buf); + if (loc_conf == NULL) { + return NGX_ERROR; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "eval using location"); + + r->loc_conf = loc_conf; + + ngx_http_update_location_config(r); + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_eval_read(ngx_http_request_t *r, ngx_str_t *name, ngx_buf_t *buf) +{ + u_char *p; + size_t size; + ssize_t n; + ngx_fd_t fd; + ngx_pool_t *pool; + ngx_file_t file; + ngx_file_info_t fi; + + ngx_memzero(buf, sizeof(ngx_buf_t)); + + if (name->len >= 5 && ngx_strncmp(name->data, "data:", 5) == 0) { + + buf->pos = name->data + 5; + buf->last = name->data + name->len; + buf->start = buf->pos; + buf->end = buf->last; + buf->memory = 1; + + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "eval read location from \"%V\"", name); + + pool = r->pool; + + ngx_memzero(&file, sizeof(ngx_file_t)); + + file.log = r->connection->log; + + if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, name) + != NGX_OK) + { + return NGX_ERROR; + } + + file.name.len = name->len; + file.name.data = name->data; + + fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", name->data); + return NGX_ERROR; + } + + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", name->data); + + (void) ngx_close_file(fd); + return NGX_ERROR; + } + + size = (size_t) ngx_file_size(&fi); + + p = ngx_pnalloc(pool, size); + if (p == NULL) { + (void) ngx_close_file(fd); + return NGX_ERROR; + } + + file.fd = fd; + + n = ngx_read_file(&file, p, size, 0); + + if (n == NGX_ERROR) { + (void) ngx_close_file(fd); + return NGX_ERROR; + } + + if (n != (ssize_t) size) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_read_file_n " returned " + "only %z bytes instead of %z", n, size); + (void) ngx_close_file(fd); + return NGX_ERROR; + } + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_file_n " %s failed", name->data); + return NGX_ERROR; + } + + buf->pos = p; + buf->last = p + size; + buf->start = buf->pos; + buf->end = buf->last; + buf->temporary = 1; + + return NGX_OK; +} + + +static void ** +ngx_http_eval_create_location(ngx_http_request_t *r, ngx_buf_t *buf) +{ + void **loc_conf; + char *rv; + ngx_str_t *name; + ngx_int_t rc; + ngx_log_t *log; + ngx_pool_t *pool; + ngx_uint_t i, found, ctx_index; + ngx_conf_t conf; + ngx_array_t args; + ngx_module_t **modules; + ngx_command_t *cmd; + ngx_conf_file_t conf_file; + ngx_http_module_t *module; + ngx_http_conf_ctx_t ctx; + ngx_http_core_loc_conf_t *clcf; + + pool = r->connection->pool; + log = r->connection->log; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "eval location n:%z", buf->last - buf->pos); + + if (ngx_array_init(&args, pool, 10, sizeof(ngx_str_t)) != NGX_OK) { + return NULL; + } + + ngx_memzero(&ctx, sizeof(ngx_http_conf_ctx_t)); + + ngx_memzero(&conf_file, sizeof(ngx_conf_file_t)); + conf_file.file.log = log; + conf_file.line = 1; + conf_file.file.fd = NGX_INVALID_FILE; + conf_file.buffer = buf; + + ngx_memzero(&conf, sizeof(ngx_conf_t)); + conf.ctx = &ctx; + conf.temp_pool = pool; + conf.cycle = (ngx_cycle_t *) ngx_cycle; + conf.pool = pool; + conf.log = log; + conf.module_type = NGX_CORE_MODULE; + conf.cmd_type = NGX_MAIN_CONF; + conf.conf_file = &conf_file; + conf.args = &args; + + modules = ngx_cycle->modules; + + loc_conf = ngx_pcalloc(pool, sizeof(void *) * ngx_http_max_module); + if (loc_conf == NULL) { + return NULL; + } + + ctx.loc_conf = loc_conf; + + module = ngx_http_core_module.ctx; + + clcf = module->create_loc_conf(&conf); + if (clcf == NULL) { + goto failed; + } + + clcf->eval = 1; + + loc_conf[ngx_http_core_module.ctx_index] = clcf; + + for ( ;; ) { + rc = ngx_conf_read_token(&conf); + + name = conf.args->elts; + + /* + * ngx_conf_read_token() may return + * + * NGX_ERROR there is error + * NGX_OK the token terminated by ";" was found + * NGX_CONF_BLOCK_START the token terminated by "{" was found + * NGX_CONF_BLOCK_DONE the "}" was found + * NGX_CONF_FILE_DONE the configuration file is done + */ + + if (rc == NGX_ERROR) { + goto failed; + } + + if (rc == NGX_CONF_BLOCK_DONE) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "unexpected \"}\""); + goto failed; + } + + if (rc == NGX_CONF_FILE_DONE) { + goto done; + } + + /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ + + found = 0; + + /* TODO optimize search */ + + for (i = 0; modules[i]; i++) { + + if (modules[i]->type != NGX_HTTP_MODULE) { + continue; + } + + ctx_index = modules[i]->ctx_index; + module = modules[i]->ctx; + + cmd = modules[i]->commands; + if (cmd == NULL) { + continue; + } + + for ( /* void */ ; cmd->name.len; cmd++) { + + if (name->len != cmd->name.len) { + continue; + } + + if (ngx_strcmp(name->data, cmd->name.data) != 0) { + continue; + } + + found = 1; + + if (!(cmd->type & NGX_DYNAMIC_CONF)) { + continue; + } + + if (!(cmd->type & NGX_HTTP_LOC_CONF)) { + continue; + } + + if (!(cmd->type & NGX_CONF_BLOCK) && rc != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "directive \"%s\" is not " + "terminated by \";\"", name->data); + goto invalid; + } + + if ((cmd->type & NGX_CONF_BLOCK) + && rc != NGX_CONF_BLOCK_START) + { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "directive \"%s\" has no opening \"{\"", + name->data); + goto invalid; + } + + /* is the directive's argument count right ? */ + + if (!(cmd->type & NGX_CONF_ANY)) { + + if (cmd->type & NGX_CONF_FLAG) { + + if (conf.args->nelts != 2) { + goto invalid; + } + + } else if (cmd->type & NGX_CONF_1MORE) { + + if (conf.args->nelts < 2) { + goto invalid; + } + + } else if (cmd->type & NGX_CONF_2MORE) { + + if (conf.args->nelts < 3) { + goto invalid; + } + + } else if (conf.args->nelts > NGX_CONF_MAX_ARGS) { + + goto invalid; + + } else if (!(cmd->type + & argument_number[conf.args->nelts - 1])) + { + goto invalid; + } + } + + if (cmd->conf != NGX_HTTP_LOC_CONF_OFFSET) { + goto invalid; + } + + if (loc_conf[ctx_index] == NULL) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "eval create %s conf", modules[i]->name); + + if (module->create_loc_conf == NULL) { + goto failed; + } + + loc_conf[ctx_index] = module->create_loc_conf(&conf); + if (loc_conf[ctx_index] == NULL) { + goto failed; + } + } + + rv = cmd->set(&conf, cmd, loc_conf[ctx_index]); + + if (rv == NGX_CONF_ERROR) { + goto failed; + } + + if (rv != NGX_CONF_OK) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "\"%s\" directive %s", name->data, rv); + goto failed; + } + + goto next; + } + } + + if (found) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "\"%s\" directive is not allowed here", name->data); + goto failed; + } + + ngx_log_error(NGX_LOG_ALERT, log, 0, + "unknown directive \"%s\"", name->data); + + goto failed; + + next: + + continue; + } + +invalid: + + ngx_log_error(NGX_LOG_ALERT, log, 0, + "invalid number of arguments in \"%s\" directive", + name->data); + +failed: + + return NULL; + +done: + + for (i = 0; modules[i]; i++) { + + if (modules[i]->type != NGX_HTTP_MODULE) { + continue; + } + + ctx_index = modules[i]->ctx_index; + module = modules[i]->ctx; + + if (loc_conf[ctx_index] == NULL) { + loc_conf[ctx_index] = r->loc_conf[ctx_index]; + continue; + } + + if (module->merge_loc_conf) { + rv = module->merge_loc_conf(&conf, r->loc_conf[ctx_index], + loc_conf[ctx_index]); + if (rv != NGX_CONF_OK) { + goto failed; + } + } + } + + return loc_conf; +} + + +static ngx_int_t +ngx_http_eval_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_eval_handler; + + return NGX_OK; +} + + +static void * +ngx_http_eval_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_eval_loc_conf_t *elcf; + + elcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_eval_loc_conf_t)); + if (elcf == NULL) { + return NULL; + } + + elcf->value = NGX_CONF_UNSET_PTR; + + return elcf; +} + + +static char * +ngx_http_eval_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_eval_loc_conf_t *prev = parent; + ngx_http_eval_loc_conf_t *conf = child; + + ngx_conf_merge_ptr_value(conf->value, prev->value, NULL); + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 9be565373..93578930c 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -326,6 +326,7 @@ struct ngx_http_core_loc_conf_s { unsigned gzip_disable_msie6:2; unsigned gzip_disable_degradation:2; #endif + unsigned eval:1; ngx_http_location_tree_node_t *static_locations; #if (NGX_PCRE) diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index a2b9f1b7b..96bca8d31 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -16,6 +16,8 @@ static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last); static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name); +static ngx_int_t ngx_http_script_add_named_var_code( + ngx_http_script_compile_t *sc, ngx_str_t *name); static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc); #if (NGX_PCRE) static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, @@ -891,6 +893,10 @@ ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name) ngx_int_t index, *p; ngx_http_script_var_code_t *code; + if (((ngx_http_conf_ctx_t *) sc->cf->ctx)->main_conf == NULL) { + return ngx_http_script_add_named_var_code(sc, name); + } + index = ngx_http_get_variable_index(sc->cf, name); if (index == NGX_ERROR) { @@ -987,6 +993,95 @@ ngx_http_script_copy_var_code(ngx_http_script_engine_t *e) } +static ngx_int_t +ngx_http_script_add_named_var_code(ngx_http_script_compile_t *sc, + ngx_str_t *name) +{ + ngx_uint_t key; + ngx_http_script_named_var_code_t *code; + + key = ngx_hash_strlow(name->data, name->data, name->len); + + code = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_named_var_code_t) + name->len, + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_script_code_pt) (void *) + ngx_http_script_copy_named_var_len_code; + code->key = (uintptr_t) key; + code->name.len = name->len; + code->name.data = (u_char *) code + + sizeof(ngx_http_script_named_var_code_t); + ngx_memcpy(code->name.data, name->data, name->len); + + code = ngx_http_script_add_code(*sc->values, + sizeof(ngx_http_script_named_var_code_t) + name->len, + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_http_script_copy_named_var_code; + code->key = (uintptr_t) key; + code->name.len = name->len; + code->name.data = (u_char *) code + + sizeof(ngx_http_script_named_var_code_t); + ngx_memcpy(code->name.data, name->data, name->len); + + return NGX_OK; +} + + +size_t +ngx_http_script_copy_named_var_len_code(ngx_http_script_engine_t *e) +{ + ngx_http_variable_value_t *value; + ngx_http_script_named_var_code_t *code; + + code = (ngx_http_script_named_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_named_var_code_t) + code->name.len; + + value = ngx_http_get_variable(e->request, &code->name, code->key); + + if (value && !value->not_found) { + return value->len; + } + + return 0; +} + + +void +ngx_http_script_copy_named_var_code(ngx_http_script_engine_t *e) +{ + u_char *p; + ngx_http_variable_value_t *value; + ngx_http_script_named_var_code_t *code; + + code = (ngx_http_script_named_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_named_var_code_t) + code->name.len; + + if (!e->skip) { + + value = ngx_http_get_variable(e->request, &code->name, code->key); + + if (value && !value->not_found) { + p = e->pos; + e->pos = ngx_copy(p, value->data, value->len); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + e->request->connection->log, 0, + "http script named var: \"%*s\"", e->pos - p, p); + } + } +} + + static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h index 43600383c..54b8eef7d 100644 --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -102,6 +102,13 @@ typedef struct { } ngx_http_script_var_code_t; +typedef struct { + ngx_http_script_code_pt code; + uintptr_t key; + ngx_str_t name; +} ngx_http_script_named_var_code_t; + + typedef struct { ngx_http_script_code_pt code; ngx_http_set_variable_pt handler; @@ -244,6 +251,8 @@ size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_code(ngx_http_script_engine_t *e); size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e); +size_t ngx_http_script_copy_named_var_len_code(ngx_http_script_engine_t *e); +void ngx_http_script_copy_named_var_code(ngx_http_script_engine_t *e); size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e); size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e);