mirror of
https://github.com/nginx/nginx.git
synced 2026-02-03 20:29:27 -05:00
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";
}
This commit is contained in:
parent
3afd85e4b5
commit
d28a070469
8 changed files with 662 additions and 4 deletions
13
auto/modules
13
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
534
src/http/modules/ngx_http_eval_module.c
Normal file
534
src/http/modules/ngx_http_eval_module.c
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Roman Arutyunyan
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue