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);