mirror of
https://github.com/nginx/nginx.git
synced 2025-02-25 18:55:26 -06:00
Stream: variables and script.
This is a port of corresponding http code with unrelated features excluded.
This commit is contained in:
parent
db5a15d2f9
commit
c31773ea60
@ -976,9 +976,13 @@ if [ $STREAM != NO ]; then
|
||||
ngx_stream_upstream_module"
|
||||
ngx_module_incs="src/stream"
|
||||
ngx_module_deps="src/stream/ngx_stream.h \
|
||||
src/stream/ngx_stream_variables.h \
|
||||
src/stream/ngx_stream_script.h \
|
||||
src/stream/ngx_stream_upstream.h \
|
||||
src/stream/ngx_stream_upstream_round_robin.h"
|
||||
ngx_module_srcs="src/stream/ngx_stream.c \
|
||||
src/stream/ngx_stream_variables.c \
|
||||
src/stream/ngx_stream_script.c \
|
||||
src/stream/ngx_stream_handler.c \
|
||||
src/stream/ngx_stream_core_module.c \
|
||||
src/stream/ngx_stream_proxy_module.c \
|
||||
|
@ -230,6 +230,10 @@ ngx_stream_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_stream_variables_init_vars(cf) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*cf = pcf;
|
||||
|
||||
|
||||
|
@ -20,64 +20,66 @@
|
||||
typedef struct ngx_stream_session_s ngx_stream_session_t;
|
||||
|
||||
|
||||
#include <ngx_stream_variables.h>
|
||||
#include <ngx_stream_script.h>
|
||||
#include <ngx_stream_upstream.h>
|
||||
#include <ngx_stream_upstream_round_robin.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
void **main_conf;
|
||||
void **srv_conf;
|
||||
void **main_conf;
|
||||
void **srv_conf;
|
||||
} ngx_stream_conf_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_sockaddr_t sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_sockaddr_t sockaddr;
|
||||
socklen_t socklen;
|
||||
|
||||
/* server ctx */
|
||||
ngx_stream_conf_ctx_t *ctx;
|
||||
ngx_stream_conf_ctx_t *ctx;
|
||||
|
||||
unsigned bind:1;
|
||||
unsigned wildcard:1;
|
||||
unsigned bind:1;
|
||||
unsigned wildcard:1;
|
||||
#if (NGX_STREAM_SSL)
|
||||
unsigned ssl:1;
|
||||
unsigned ssl:1;
|
||||
#endif
|
||||
#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
|
||||
unsigned ipv6only:1;
|
||||
unsigned ipv6only:1;
|
||||
#endif
|
||||
#if (NGX_HAVE_REUSEPORT)
|
||||
unsigned reuseport:1;
|
||||
unsigned reuseport:1;
|
||||
#endif
|
||||
unsigned so_keepalive:2;
|
||||
unsigned so_keepalive:2;
|
||||
#if (NGX_HAVE_KEEPALIVE_TUNABLE)
|
||||
int tcp_keepidle;
|
||||
int tcp_keepintvl;
|
||||
int tcp_keepcnt;
|
||||
int tcp_keepidle;
|
||||
int tcp_keepintvl;
|
||||
int tcp_keepcnt;
|
||||
#endif
|
||||
int backlog;
|
||||
int type;
|
||||
int backlog;
|
||||
int type;
|
||||
} ngx_stream_listen_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_conf_ctx_t *ctx;
|
||||
ngx_str_t addr_text;
|
||||
ngx_stream_conf_ctx_t *ctx;
|
||||
ngx_str_t addr_text;
|
||||
#if (NGX_STREAM_SSL)
|
||||
ngx_uint_t ssl; /* unsigned ssl:1; */
|
||||
ngx_uint_t ssl; /* unsigned ssl:1; */
|
||||
#endif
|
||||
} ngx_stream_addr_conf_t;
|
||||
|
||||
typedef struct {
|
||||
in_addr_t addr;
|
||||
ngx_stream_addr_conf_t conf;
|
||||
in_addr_t addr;
|
||||
ngx_stream_addr_conf_t conf;
|
||||
} ngx_stream_in_addr_t;
|
||||
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
typedef struct {
|
||||
struct in6_addr addr6;
|
||||
ngx_stream_addr_conf_t conf;
|
||||
struct in6_addr addr6;
|
||||
ngx_stream_addr_conf_t conf;
|
||||
} ngx_stream_in6_addr_t;
|
||||
|
||||
#endif
|
||||
@ -85,21 +87,21 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
/* ngx_stream_in_addr_t or ngx_stream_in6_addr_t */
|
||||
void *addrs;
|
||||
ngx_uint_t naddrs;
|
||||
void *addrs;
|
||||
ngx_uint_t naddrs;
|
||||
} ngx_stream_port_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int family;
|
||||
int type;
|
||||
in_port_t port;
|
||||
ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */
|
||||
int family;
|
||||
int type;
|
||||
in_port_t port;
|
||||
ngx_array_t addrs; /* array of ngx_stream_conf_addr_t */
|
||||
} ngx_stream_conf_port_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_listen_t opt;
|
||||
ngx_stream_listen_t opt;
|
||||
} ngx_stream_conf_addr_t;
|
||||
|
||||
|
||||
@ -107,10 +109,21 @@ typedef ngx_int_t (*ngx_stream_access_pt)(ngx_stream_session_t *s);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_array_t servers; /* ngx_stream_core_srv_conf_t */
|
||||
ngx_array_t listen; /* ngx_stream_listen_t */
|
||||
ngx_stream_access_pt limit_conn_handler;
|
||||
ngx_stream_access_pt access_handler;
|
||||
ngx_array_t servers; /* ngx_stream_core_srv_conf_t */
|
||||
ngx_array_t listen; /* ngx_stream_listen_t */
|
||||
|
||||
ngx_stream_access_pt limit_conn_handler;
|
||||
ngx_stream_access_pt access_handler;
|
||||
|
||||
ngx_hash_t variables_hash;
|
||||
|
||||
ngx_array_t variables; /* ngx_stream_variable_t */
|
||||
ngx_uint_t ncaptures;
|
||||
|
||||
ngx_uint_t variables_hash_max_size;
|
||||
ngx_uint_t variables_hash_bucket_size;
|
||||
|
||||
ngx_hash_keys_arrays_t *variables_keys;
|
||||
} ngx_stream_core_main_conf_t;
|
||||
|
||||
|
||||
@ -118,42 +131,54 @@ typedef void (*ngx_stream_handler_pt)(ngx_stream_session_t *s);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_handler_pt handler;
|
||||
ngx_stream_conf_ctx_t *ctx;
|
||||
u_char *file_name;
|
||||
ngx_int_t line;
|
||||
ngx_log_t *error_log;
|
||||
ngx_flag_t tcp_nodelay;
|
||||
ngx_stream_handler_pt handler;
|
||||
|
||||
ngx_stream_conf_ctx_t *ctx;
|
||||
|
||||
u_char *file_name;
|
||||
ngx_int_t line;
|
||||
|
||||
ngx_flag_t tcp_nodelay;
|
||||
|
||||
ngx_log_t *error_log;
|
||||
} ngx_stream_core_srv_conf_t;
|
||||
|
||||
|
||||
struct ngx_stream_session_s {
|
||||
uint32_t signature; /* "STRM" */
|
||||
uint32_t signature; /* "STRM" */
|
||||
|
||||
ngx_connection_t *connection;
|
||||
ngx_connection_t *connection;
|
||||
|
||||
off_t received;
|
||||
off_t received;
|
||||
|
||||
ngx_log_handler_pt log_handler;
|
||||
ngx_log_handler_pt log_handler;
|
||||
|
||||
void **ctx;
|
||||
void **main_conf;
|
||||
void **srv_conf;
|
||||
void **ctx;
|
||||
void **main_conf;
|
||||
void **srv_conf;
|
||||
|
||||
ngx_stream_upstream_t *upstream;
|
||||
ngx_stream_upstream_t *upstream;
|
||||
|
||||
ngx_stream_variable_value_t *variables;
|
||||
|
||||
#if (NGX_PCRE)
|
||||
ngx_uint_t ncaptures;
|
||||
int *captures;
|
||||
u_char *captures_data;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
|
||||
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
|
||||
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
|
||||
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
|
||||
|
||||
void *(*create_main_conf)(ngx_conf_t *cf);
|
||||
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
|
||||
void *(*create_main_conf)(ngx_conf_t *cf);
|
||||
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
|
||||
|
||||
void *(*create_srv_conf)(ngx_conf_t *cf);
|
||||
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
|
||||
void *conf);
|
||||
void *(*create_srv_conf)(ngx_conf_t *cf);
|
||||
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
|
||||
void *conf);
|
||||
} ngx_stream_module_t;
|
||||
|
||||
|
||||
|
@ -10,7 +10,9 @@
|
||||
#include <ngx_stream.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_core_preconfiguration(ngx_conf_t *cf);
|
||||
static void *ngx_stream_core_create_main_conf(ngx_conf_t *cf);
|
||||
static char *ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf);
|
||||
static void *ngx_stream_core_create_srv_conf(ngx_conf_t *cf);
|
||||
static char *ngx_stream_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
|
||||
void *child);
|
||||
@ -24,6 +26,20 @@ static char *ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
|
||||
static ngx_command_t ngx_stream_core_commands[] = {
|
||||
|
||||
{ ngx_string("variables_hash_max_size"),
|
||||
NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
NGX_STREAM_MAIN_CONF_OFFSET,
|
||||
offsetof(ngx_stream_core_main_conf_t, variables_hash_max_size),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("variables_hash_bucket_size"),
|
||||
NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_num_slot,
|
||||
NGX_STREAM_MAIN_CONF_OFFSET,
|
||||
offsetof(ngx_stream_core_main_conf_t, variables_hash_bucket_size),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("server"),
|
||||
NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
|
||||
ngx_stream_core_server,
|
||||
@ -57,11 +73,11 @@ static ngx_command_t ngx_stream_core_commands[] = {
|
||||
|
||||
|
||||
static ngx_stream_module_t ngx_stream_core_module_ctx = {
|
||||
NULL, /* preconfiguration */
|
||||
ngx_stream_core_preconfiguration, /* preconfiguration */
|
||||
NULL, /* postconfiguration */
|
||||
|
||||
ngx_stream_core_create_main_conf, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
ngx_stream_core_init_main_conf, /* init main configuration */
|
||||
|
||||
ngx_stream_core_create_srv_conf, /* create server configuration */
|
||||
ngx_stream_core_merge_srv_conf /* merge server configuration */
|
||||
@ -84,6 +100,13 @@ ngx_module_t ngx_stream_core_module = {
|
||||
};
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_core_preconfiguration(ngx_conf_t *cf)
|
||||
{
|
||||
return ngx_stream_variables_add_core_vars(cf);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_stream_core_create_main_conf(ngx_conf_t *cf)
|
||||
{
|
||||
@ -107,10 +130,32 @@ ngx_stream_core_create_main_conf(ngx_conf_t *cf)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmcf->variables_hash_max_size = NGX_CONF_UNSET_UINT;
|
||||
cmcf->variables_hash_bucket_size = NGX_CONF_UNSET_UINT;
|
||||
|
||||
return cmcf;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_stream_core_init_main_conf(ngx_conf_t *cf, void *conf)
|
||||
{
|
||||
ngx_stream_core_main_conf_t *cmcf = conf;
|
||||
|
||||
ngx_conf_init_uint_value(cmcf->variables_hash_max_size, 1024);
|
||||
ngx_conf_init_uint_value(cmcf->variables_hash_bucket_size, 64);
|
||||
|
||||
cmcf->variables_hash_bucket_size =
|
||||
ngx_align(cmcf->variables_hash_bucket_size, ngx_cacheline_size);
|
||||
|
||||
if (cmcf->ncaptures) {
|
||||
cmcf->ncaptures = (cmcf->ncaptures + 1) * 3;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_stream_core_create_srv_conf(ngx_conf_t *cf)
|
||||
{
|
||||
|
@ -149,6 +149,15 @@ ngx_stream_init_connection(ngx_connection_t *c)
|
||||
|
||||
cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
|
||||
|
||||
s->variables = ngx_pcalloc(s->connection->pool,
|
||||
cmcf->variables.nelts
|
||||
* sizeof(ngx_stream_variable_value_t));
|
||||
|
||||
if (s->variables == NULL) {
|
||||
ngx_stream_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmcf->limit_conn_handler) {
|
||||
rc = cmcf->limit_conn_handler(s);
|
||||
|
||||
|
852
src/stream/ngx_stream_script.c
Normal file
852
src/stream/ngx_stream_script.c
Normal file
@ -0,0 +1,852 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_stream.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_script_init_arrays(
|
||||
ngx_stream_script_compile_t *sc);
|
||||
static ngx_int_t ngx_stream_script_done(ngx_stream_script_compile_t *sc);
|
||||
static ngx_int_t ngx_stream_script_add_copy_code(
|
||||
ngx_stream_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last);
|
||||
static ngx_int_t ngx_stream_script_add_var_code(
|
||||
ngx_stream_script_compile_t *sc, ngx_str_t *name);
|
||||
#if (NGX_PCRE)
|
||||
static ngx_int_t ngx_stream_script_add_capture_code(
|
||||
ngx_stream_script_compile_t *sc, ngx_uint_t n);
|
||||
#endif
|
||||
static ngx_int_t ngx_stream_script_add_full_name_code(
|
||||
ngx_stream_script_compile_t *sc);
|
||||
static size_t ngx_stream_script_full_name_len_code(
|
||||
ngx_stream_script_engine_t *e);
|
||||
static void ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e);
|
||||
|
||||
|
||||
#define ngx_stream_script_exit (u_char *) &ngx_stream_script_exit_code
|
||||
|
||||
static uintptr_t ngx_stream_script_exit_code = (uintptr_t) NULL;
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_script_flush_complex_value(ngx_stream_session_t *s,
|
||||
ngx_stream_complex_value_t *val)
|
||||
{
|
||||
ngx_uint_t *index;
|
||||
|
||||
index = val->flushes;
|
||||
|
||||
if (index) {
|
||||
while (*index != (ngx_uint_t) -1) {
|
||||
|
||||
if (s->variables[*index].no_cacheable) {
|
||||
s->variables[*index].valid = 0;
|
||||
s->variables[*index].not_found = 0;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_complex_value(ngx_stream_session_t *s,
|
||||
ngx_stream_complex_value_t *val, ngx_str_t *value)
|
||||
{
|
||||
size_t len;
|
||||
ngx_stream_script_code_pt code;
|
||||
ngx_stream_script_engine_t e;
|
||||
ngx_stream_script_len_code_pt lcode;
|
||||
|
||||
if (val->lengths == NULL) {
|
||||
*value = val->value;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_stream_script_flush_complex_value(s, val);
|
||||
|
||||
ngx_memzero(&e, sizeof(ngx_stream_script_engine_t));
|
||||
|
||||
e.ip = val->lengths;
|
||||
e.session = s;
|
||||
e.flushed = 1;
|
||||
|
||||
len = 0;
|
||||
|
||||
while (*(uintptr_t *) e.ip) {
|
||||
lcode = *(ngx_stream_script_len_code_pt *) e.ip;
|
||||
len += lcode(&e);
|
||||
}
|
||||
|
||||
value->len = len;
|
||||
value->data = ngx_pnalloc(s->connection->pool, len);
|
||||
if (value->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
e.ip = val->values;
|
||||
e.pos = value->data;
|
||||
e.buf = *value;
|
||||
|
||||
while (*(uintptr_t *) e.ip) {
|
||||
code = *(ngx_stream_script_code_pt *) e.ip;
|
||||
code((ngx_stream_script_engine_t *) &e);
|
||||
}
|
||||
|
||||
*value = e.buf;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_compile_complex_value(ngx_stream_compile_complex_value_t *ccv)
|
||||
{
|
||||
ngx_str_t *v;
|
||||
ngx_uint_t i, n, nv, nc;
|
||||
ngx_array_t flushes, lengths, values, *pf, *pl, *pv;
|
||||
ngx_stream_script_compile_t sc;
|
||||
|
||||
v = ccv->value;
|
||||
|
||||
nv = 0;
|
||||
nc = 0;
|
||||
|
||||
for (i = 0; i < v->len; i++) {
|
||||
if (v->data[i] == '$') {
|
||||
if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') {
|
||||
nc++;
|
||||
|
||||
} else {
|
||||
nv++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((v->len == 0 || v->data[0] != '$')
|
||||
&& (ccv->conf_prefix || ccv->root_prefix))
|
||||
{
|
||||
if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ccv->conf_prefix = 0;
|
||||
ccv->root_prefix = 0;
|
||||
}
|
||||
|
||||
ccv->complex_value->value = *v;
|
||||
ccv->complex_value->flushes = NULL;
|
||||
ccv->complex_value->lengths = NULL;
|
||||
ccv->complex_value->values = NULL;
|
||||
|
||||
if (nv == 0 && nc == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
n = nv + 1;
|
||||
|
||||
if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
n = nv * (2 * sizeof(ngx_stream_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_script_var_code_t))
|
||||
+ sizeof(uintptr_t);
|
||||
|
||||
if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
n = (nv * (2 * sizeof(ngx_stream_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_script_var_code_t))
|
||||
+ sizeof(uintptr_t)
|
||||
+ v->len
|
||||
+ sizeof(uintptr_t) - 1)
|
||||
& ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pf = &flushes;
|
||||
pl = &lengths;
|
||||
pv = &values;
|
||||
|
||||
ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t));
|
||||
|
||||
sc.cf = ccv->cf;
|
||||
sc.source = v;
|
||||
sc.flushes = &pf;
|
||||
sc.lengths = &pl;
|
||||
sc.values = &pv;
|
||||
sc.complete_lengths = 1;
|
||||
sc.complete_values = 1;
|
||||
sc.zero = ccv->zero;
|
||||
sc.conf_prefix = ccv->conf_prefix;
|
||||
sc.root_prefix = ccv->root_prefix;
|
||||
|
||||
if (ngx_stream_script_compile(&sc) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (flushes.nelts) {
|
||||
ccv->complex_value->flushes = flushes.elts;
|
||||
ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
|
||||
}
|
||||
|
||||
ccv->complex_value->lengths = lengths.elts;
|
||||
ccv->complex_value->values = values.elts;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf)
|
||||
{
|
||||
char *p = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
ngx_stream_complex_value_t **cv;
|
||||
ngx_stream_compile_complex_value_t ccv;
|
||||
|
||||
cv = (ngx_stream_complex_value_t **) (p + cmd->offset);
|
||||
|
||||
if (*cv != NULL) {
|
||||
return "duplicate";
|
||||
}
|
||||
|
||||
*cv = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t));
|
||||
if (*cv == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
|
||||
|
||||
ccv.cf = cf;
|
||||
ccv.value = &value[1];
|
||||
ccv.complex_value = *cv;
|
||||
|
||||
if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_uint_t
|
||||
ngx_stream_script_variables_count(ngx_str_t *value)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
|
||||
for (n = 0, i = 0; i < value->len; i++) {
|
||||
if (value->data[i] == '$') {
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_script_compile(ngx_stream_script_compile_t *sc)
|
||||
{
|
||||
u_char ch;
|
||||
ngx_str_t name;
|
||||
ngx_uint_t i, bracket;
|
||||
|
||||
if (ngx_stream_script_init_arrays(sc) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->source->len; /* void */ ) {
|
||||
|
||||
name.len = 0;
|
||||
|
||||
if (sc->source->data[i] == '$') {
|
||||
|
||||
if (++i == sc->source->len) {
|
||||
goto invalid_variable;
|
||||
}
|
||||
|
||||
#if (NGX_PCRE)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
|
||||
if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
|
||||
|
||||
n = sc->source->data[i] - '0';
|
||||
|
||||
if (ngx_stream_script_add_capture_code(sc, n) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sc->source->data[i] == '{') {
|
||||
bracket = 1;
|
||||
|
||||
if (++i == sc->source->len) {
|
||||
goto invalid_variable;
|
||||
}
|
||||
|
||||
name.data = &sc->source->data[i];
|
||||
|
||||
} else {
|
||||
bracket = 0;
|
||||
name.data = &sc->source->data[i];
|
||||
}
|
||||
|
||||
for ( /* void */ ; i < sc->source->len; i++, name.len++) {
|
||||
ch = sc->source->data[i];
|
||||
|
||||
if (ch == '}' && bracket) {
|
||||
i++;
|
||||
bracket = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ch >= 'A' && ch <= 'Z')
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= '0' && ch <= '9')
|
||||
|| ch == '_')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (bracket) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
|
||||
"the closing bracket in \"%V\" "
|
||||
"variable is missing", &name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (name.len == 0) {
|
||||
goto invalid_variable;
|
||||
}
|
||||
|
||||
sc->variables++;
|
||||
|
||||
if (ngx_stream_script_add_var_code(sc, &name) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
name.data = &sc->source->data[i];
|
||||
|
||||
while (i < sc->source->len) {
|
||||
|
||||
if (sc->source->data[i] == '$') {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
name.len++;
|
||||
}
|
||||
|
||||
sc->size += name.len;
|
||||
|
||||
if (ngx_stream_script_add_copy_code(sc, &name, (i == sc->source->len))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_stream_script_done(sc);
|
||||
|
||||
invalid_variable:
|
||||
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_script_init_arrays(ngx_stream_script_compile_t *sc)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
|
||||
if (sc->flushes && *sc->flushes == NULL) {
|
||||
n = sc->variables ? sc->variables : 1;
|
||||
*sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t));
|
||||
if (*sc->flushes == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (*sc->lengths == NULL) {
|
||||
n = sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_script_var_code_t))
|
||||
+ sizeof(uintptr_t);
|
||||
|
||||
*sc->lengths = ngx_array_create(sc->cf->pool, n, 1);
|
||||
if (*sc->lengths == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (*sc->values == NULL) {
|
||||
n = (sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_script_var_code_t))
|
||||
+ sizeof(uintptr_t)
|
||||
+ sc->source->len
|
||||
+ sizeof(uintptr_t) - 1)
|
||||
& ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
*sc->values = ngx_array_create(sc->cf->pool, n, 1);
|
||||
if (*sc->values == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sc->variables = 0;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_script_done(ngx_stream_script_compile_t *sc)
|
||||
{
|
||||
ngx_str_t zero;
|
||||
uintptr_t *code;
|
||||
|
||||
if (sc->zero) {
|
||||
|
||||
zero.len = 1;
|
||||
zero.data = (u_char *) "\0";
|
||||
|
||||
if (ngx_stream_script_add_copy_code(sc, &zero, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (sc->conf_prefix || sc->root_prefix) {
|
||||
if (ngx_stream_script_add_full_name_code(sc) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (sc->complete_lengths) {
|
||||
code = ngx_stream_script_add_code(*sc->lengths, sizeof(uintptr_t),
|
||||
NULL);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*code = (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
if (sc->complete_values) {
|
||||
code = ngx_stream_script_add_code(*sc->values, sizeof(uintptr_t),
|
||||
&sc->main);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*code = (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_stream_script_add_code(ngx_array_t *codes, size_t size, void *code)
|
||||
{
|
||||
u_char *elts, **p;
|
||||
void *new;
|
||||
|
||||
elts = codes->elts;
|
||||
|
||||
new = ngx_array_push_n(codes, size);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (code) {
|
||||
if (elts != codes->elts) {
|
||||
p = code;
|
||||
*p += (u_char *) codes->elts - elts;
|
||||
}
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_script_add_copy_code(ngx_stream_script_compile_t *sc,
|
||||
ngx_str_t *value, ngx_uint_t last)
|
||||
{
|
||||
u_char *p;
|
||||
size_t size, len, zero;
|
||||
ngx_stream_script_copy_code_t *code;
|
||||
|
||||
zero = (sc->zero && last);
|
||||
len = value->len + zero;
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_stream_script_copy_code_t),
|
||||
NULL);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_stream_script_code_pt) ngx_stream_script_copy_len_code;
|
||||
code->len = len;
|
||||
|
||||
size = (sizeof(ngx_stream_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
|
||||
& ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->values, size, &sc->main);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_stream_script_copy_code;
|
||||
code->len = len;
|
||||
|
||||
p = ngx_cpymem((u_char *) code + sizeof(ngx_stream_script_copy_code_t),
|
||||
value->data, value->len);
|
||||
|
||||
if (zero) {
|
||||
*p = '\0';
|
||||
sc->zero = 0;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_script_copy_len_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
ngx_stream_script_copy_code_t *code;
|
||||
|
||||
code = (ngx_stream_script_copy_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_copy_code_t);
|
||||
|
||||
return code->len;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_script_copy_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_stream_script_copy_code_t *code;
|
||||
|
||||
code = (ngx_stream_script_copy_code_t *) e->ip;
|
||||
|
||||
p = e->pos;
|
||||
|
||||
if (!e->skip) {
|
||||
e->pos = ngx_copy(p, e->ip + sizeof(ngx_stream_script_copy_code_t),
|
||||
code->len);
|
||||
}
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_copy_code_t)
|
||||
+ ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
|
||||
"stream script copy: \"%*s\"", e->pos - p, p);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_script_add_var_code(ngx_stream_script_compile_t *sc, ngx_str_t *name)
|
||||
{
|
||||
ngx_int_t index, *p;
|
||||
ngx_stream_script_var_code_t *code;
|
||||
|
||||
index = ngx_stream_get_variable_index(sc->cf, name);
|
||||
|
||||
if (index == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (sc->flushes) {
|
||||
p = ngx_array_push(*sc->flushes);
|
||||
if (p == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*p = index;
|
||||
}
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_stream_script_var_code_t),
|
||||
NULL);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_stream_script_code_pt)
|
||||
ngx_stream_script_copy_var_len_code;
|
||||
code->index = (uintptr_t) index;
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->values,
|
||||
sizeof(ngx_stream_script_var_code_t),
|
||||
&sc->main);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_stream_script_copy_var_code;
|
||||
code->index = (uintptr_t) index;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_script_copy_var_len_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
ngx_stream_variable_value_t *value;
|
||||
ngx_stream_script_var_code_t *code;
|
||||
|
||||
code = (ngx_stream_script_var_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_var_code_t);
|
||||
|
||||
if (e->flushed) {
|
||||
value = ngx_stream_get_indexed_variable(e->session, code->index);
|
||||
|
||||
} else {
|
||||
value = ngx_stream_get_flushed_variable(e->session, code->index);
|
||||
}
|
||||
|
||||
if (value && !value->not_found) {
|
||||
return value->len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_script_copy_var_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_stream_variable_value_t *value;
|
||||
ngx_stream_script_var_code_t *code;
|
||||
|
||||
code = (ngx_stream_script_var_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_var_code_t);
|
||||
|
||||
if (!e->skip) {
|
||||
|
||||
if (e->flushed) {
|
||||
value = ngx_stream_get_indexed_variable(e->session, code->index);
|
||||
|
||||
} else {
|
||||
value = ngx_stream_get_flushed_variable(e->session, code->index);
|
||||
}
|
||||
|
||||
if (value && !value->not_found) {
|
||||
p = e->pos;
|
||||
e->pos = ngx_copy(p, value->data, value->len);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM,
|
||||
e->session->connection->log, 0,
|
||||
"stream script var: \"%*s\"", e->pos - p, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_script_add_capture_code(ngx_stream_script_compile_t *sc,
|
||||
ngx_uint_t n)
|
||||
{
|
||||
ngx_stream_script_copy_capture_code_t *code;
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_stream_script_copy_capture_code_t),
|
||||
NULL);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_stream_script_code_pt)
|
||||
ngx_stream_script_copy_capture_len_code;
|
||||
code->n = 2 * n;
|
||||
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->values,
|
||||
sizeof(ngx_stream_script_copy_capture_code_t),
|
||||
&sc->main);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_stream_script_copy_capture_code;
|
||||
code->n = 2 * n;
|
||||
|
||||
if (sc->ncaptures < n) {
|
||||
sc->ncaptures = n;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_script_copy_capture_len_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
int *cap;
|
||||
ngx_uint_t n;
|
||||
ngx_stream_session_t *s;
|
||||
ngx_stream_script_copy_capture_code_t *code;
|
||||
|
||||
s = e->session;
|
||||
|
||||
code = (ngx_stream_script_copy_capture_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_copy_capture_code_t);
|
||||
|
||||
n = code->n;
|
||||
|
||||
if (n < s->ncaptures) {
|
||||
cap = s->captures;
|
||||
return cap[n + 1] - cap[n];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_script_copy_capture_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
int *cap;
|
||||
u_char *p, *pos;
|
||||
ngx_uint_t n;
|
||||
ngx_stream_session_t *s;
|
||||
ngx_stream_script_copy_capture_code_t *code;
|
||||
|
||||
s = e->session;
|
||||
|
||||
code = (ngx_stream_script_copy_capture_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_copy_capture_code_t);
|
||||
|
||||
n = code->n;
|
||||
|
||||
pos = e->pos;
|
||||
|
||||
if (n < s->ncaptures) {
|
||||
cap = s->captures;
|
||||
p = s->captures_data;
|
||||
e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
|
||||
"stream script capture: \"%*s\"", e->pos - pos, pos);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_script_add_full_name_code(ngx_stream_script_compile_t *sc)
|
||||
{
|
||||
ngx_stream_script_full_name_code_t *code;
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_stream_script_full_name_code_t),
|
||||
NULL);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_stream_script_code_pt)
|
||||
ngx_stream_script_full_name_len_code;
|
||||
code->conf_prefix = sc->conf_prefix;
|
||||
|
||||
code = ngx_stream_script_add_code(*sc->values,
|
||||
sizeof(ngx_stream_script_full_name_code_t), &sc->main);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_stream_script_full_name_code;
|
||||
code->conf_prefix = sc->conf_prefix;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_stream_script_full_name_len_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
ngx_stream_script_full_name_code_t *code;
|
||||
|
||||
code = (ngx_stream_script_full_name_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_full_name_code_t);
|
||||
|
||||
return code->conf_prefix ? ngx_cycle->conf_prefix.len:
|
||||
ngx_cycle->prefix.len;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e)
|
||||
{
|
||||
ngx_stream_script_full_name_code_t *code;
|
||||
|
||||
ngx_str_t value, *prefix;
|
||||
|
||||
code = (ngx_stream_script_full_name_code_t *) e->ip;
|
||||
|
||||
value.data = e->buf.data;
|
||||
value.len = e->pos - e->buf.data;
|
||||
|
||||
prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix:
|
||||
(ngx_str_t *) &ngx_cycle->prefix;
|
||||
|
||||
if (ngx_get_full_name(e->session->connection->pool, prefix, &value)
|
||||
!= NGX_OK)
|
||||
{
|
||||
e->ip = ngx_stream_script_exit;
|
||||
return;
|
||||
}
|
||||
|
||||
e->buf = value;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0,
|
||||
"stream script fullname: \"%V\"", &value);
|
||||
|
||||
e->ip += sizeof(ngx_stream_script_full_name_code_t);
|
||||
}
|
123
src/stream/ngx_stream_script.h
Normal file
123
src/stream/ngx_stream_script.h
Normal file
@ -0,0 +1,123 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_SCRIPT_H_INCLUDED_
|
||||
#define _NGX_STREAM_SCRIPT_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_stream.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char *ip;
|
||||
u_char *pos;
|
||||
ngx_stream_variable_value_t *sp;
|
||||
|
||||
ngx_str_t buf;
|
||||
ngx_str_t line;
|
||||
|
||||
unsigned flushed:1;
|
||||
unsigned skip:1;
|
||||
|
||||
ngx_stream_session_t *session;
|
||||
} ngx_stream_script_engine_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_conf_t *cf;
|
||||
ngx_str_t *source;
|
||||
|
||||
ngx_array_t **flushes;
|
||||
ngx_array_t **lengths;
|
||||
ngx_array_t **values;
|
||||
|
||||
ngx_uint_t variables;
|
||||
ngx_uint_t ncaptures;
|
||||
ngx_uint_t size;
|
||||
|
||||
void *main;
|
||||
|
||||
unsigned complete_lengths:1;
|
||||
unsigned complete_values:1;
|
||||
unsigned zero:1;
|
||||
unsigned conf_prefix:1;
|
||||
unsigned root_prefix:1;
|
||||
} ngx_stream_script_compile_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t value;
|
||||
ngx_uint_t *flushes;
|
||||
void *lengths;
|
||||
void *values;
|
||||
} ngx_stream_complex_value_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_conf_t *cf;
|
||||
ngx_str_t *value;
|
||||
ngx_stream_complex_value_t *complex_value;
|
||||
|
||||
unsigned zero:1;
|
||||
unsigned conf_prefix:1;
|
||||
unsigned root_prefix:1;
|
||||
} ngx_stream_compile_complex_value_t;
|
||||
|
||||
|
||||
typedef void (*ngx_stream_script_code_pt) (ngx_stream_script_engine_t *e);
|
||||
typedef size_t (*ngx_stream_script_len_code_pt) (ngx_stream_script_engine_t *e);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_script_code_pt code;
|
||||
uintptr_t len;
|
||||
} ngx_stream_script_copy_code_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_script_code_pt code;
|
||||
uintptr_t index;
|
||||
} ngx_stream_script_var_code_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_script_code_pt code;
|
||||
uintptr_t n;
|
||||
} ngx_stream_script_copy_capture_code_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_script_code_pt code;
|
||||
uintptr_t conf_prefix;
|
||||
} ngx_stream_script_full_name_code_t;
|
||||
|
||||
|
||||
void ngx_stream_script_flush_complex_value(ngx_stream_session_t *s,
|
||||
ngx_stream_complex_value_t *val);
|
||||
ngx_int_t ngx_stream_complex_value(ngx_stream_session_t *s,
|
||||
ngx_stream_complex_value_t *val, ngx_str_t *value);
|
||||
ngx_int_t ngx_stream_compile_complex_value(
|
||||
ngx_stream_compile_complex_value_t *ccv);
|
||||
char *ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
ngx_uint_t ngx_stream_script_variables_count(ngx_str_t *value);
|
||||
ngx_int_t ngx_stream_script_compile(ngx_stream_script_compile_t *sc);
|
||||
|
||||
void *ngx_stream_script_add_code(ngx_array_t *codes, size_t size, void *code);
|
||||
|
||||
size_t ngx_stream_script_copy_len_code(ngx_stream_script_engine_t *e);
|
||||
void ngx_stream_script_copy_code(ngx_stream_script_engine_t *e);
|
||||
size_t ngx_stream_script_copy_var_len_code(ngx_stream_script_engine_t *e);
|
||||
void ngx_stream_script_copy_var_code(ngx_stream_script_engine_t *e);
|
||||
size_t ngx_stream_script_copy_capture_len_code(ngx_stream_script_engine_t *e);
|
||||
void ngx_stream_script_copy_capture_code(ngx_stream_script_engine_t *e);
|
||||
|
||||
#endif /* _NGX_STREAM_SCRIPT_H_INCLUDED_ */
|
621
src/stream/ngx_stream_variables.c
Normal file
621
src/stream/ngx_stream_variables.c
Normal file
@ -0,0 +1,621 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_stream.h>
|
||||
#include <nginx.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
|
||||
ngx_stream_variable_value_t *v, uintptr_t data);
|
||||
|
||||
|
||||
static ngx_stream_variable_t ngx_stream_core_variables[] = {
|
||||
|
||||
{ ngx_string("nginx_version"), NULL, ngx_stream_variable_nginx_version,
|
||||
0, 0, 0 },
|
||||
|
||||
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
ngx_stream_variable_value_t ngx_stream_variable_null_value =
|
||||
ngx_stream_variable("");
|
||||
ngx_stream_variable_value_t ngx_stream_variable_true_value =
|
||||
ngx_stream_variable("1");
|
||||
|
||||
|
||||
ngx_stream_variable_t *
|
||||
ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t i;
|
||||
ngx_hash_key_t *key;
|
||||
ngx_stream_variable_t *v;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
if (name->len == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid variable name \"$\"");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
|
||||
|
||||
key = cmcf->variables_keys->keys.elts;
|
||||
for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
|
||||
if (name->len != key[i].key.len
|
||||
|| ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
v = key[i].value;
|
||||
|
||||
if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"the duplicate \"%V\" variable", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t));
|
||||
if (v == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v->name.len = name->len;
|
||||
v->name.data = ngx_pnalloc(cf->pool, name->len);
|
||||
if (v->name.data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_strlow(v->name.data, name->data, name->len);
|
||||
|
||||
v->set_handler = NULL;
|
||||
v->get_handler = NULL;
|
||||
v->data = 0;
|
||||
v->flags = flags;
|
||||
v->index = 0;
|
||||
|
||||
rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rc == NGX_BUSY) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"conflicting variable name \"%V\"", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_stream_variable_t *v;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
if (name->len == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"invalid variable name \"$\"");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
|
||||
|
||||
v = cmcf->variables.elts;
|
||||
|
||||
if (v == NULL) {
|
||||
if (ngx_array_init(&cmcf->variables, cf->pool, 4,
|
||||
sizeof(ngx_stream_variable_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
for (i = 0; i < cmcf->variables.nelts; i++) {
|
||||
if (name->len != v[i].name.len
|
||||
|| ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
v = ngx_array_push(&cmcf->variables);
|
||||
if (v == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
v->name.len = name->len;
|
||||
v->name.data = ngx_pnalloc(cf->pool, name->len);
|
||||
if (v->name.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_strlow(v->name.data, name->data, name->len);
|
||||
|
||||
v->set_handler = NULL;
|
||||
v->get_handler = NULL;
|
||||
v->data = 0;
|
||||
v->flags = 0;
|
||||
v->index = cmcf->variables.nelts - 1;
|
||||
|
||||
return v->index;
|
||||
}
|
||||
|
||||
|
||||
ngx_stream_variable_value_t *
|
||||
ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
|
||||
{
|
||||
ngx_stream_variable_t *v;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
|
||||
|
||||
if (cmcf->variables.nelts <= index) {
|
||||
ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
|
||||
"unknown variable index: %ui", index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (s->variables[index].not_found || s->variables[index].valid) {
|
||||
return &s->variables[index];
|
||||
}
|
||||
|
||||
v = cmcf->variables.elts;
|
||||
|
||||
if (v[index].get_handler(s, &s->variables[index], v[index].data)
|
||||
== NGX_OK)
|
||||
{
|
||||
if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
|
||||
s->variables[index].no_cacheable = 1;
|
||||
}
|
||||
|
||||
return &s->variables[index];
|
||||
}
|
||||
|
||||
s->variables[index].valid = 0;
|
||||
s->variables[index].not_found = 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
ngx_stream_variable_value_t *
|
||||
ngx_stream_get_flushed_variable(ngx_stream_session_t *s, ngx_uint_t index)
|
||||
{
|
||||
ngx_stream_variable_value_t *v;
|
||||
|
||||
v = &s->variables[index];
|
||||
|
||||
if (v->valid || v->not_found) {
|
||||
if (!v->no_cacheable) {
|
||||
return v;
|
||||
}
|
||||
|
||||
v->valid = 0;
|
||||
v->not_found = 0;
|
||||
}
|
||||
|
||||
return ngx_stream_get_indexed_variable(s, index);
|
||||
}
|
||||
|
||||
|
||||
ngx_stream_variable_value_t *
|
||||
ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
|
||||
ngx_uint_t key)
|
||||
{
|
||||
ngx_stream_variable_t *v;
|
||||
ngx_stream_variable_value_t *vv;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
|
||||
|
||||
v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
|
||||
|
||||
if (v) {
|
||||
if (v->flags & NGX_STREAM_VAR_INDEXED) {
|
||||
return ngx_stream_get_flushed_variable(s, v->index);
|
||||
|
||||
} else {
|
||||
|
||||
vv = ngx_palloc(s->connection->pool,
|
||||
sizeof(ngx_stream_variable_value_t));
|
||||
|
||||
if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
|
||||
return vv;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));
|
||||
if (vv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vv->not_found = 1;
|
||||
|
||||
return vv;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
|
||||
ngx_stream_variable_value_t *v, uintptr_t data)
|
||||
{
|
||||
v->len = sizeof(NGINX_VERSION) - 1;
|
||||
v->valid = 1;
|
||||
v->no_cacheable = 0;
|
||||
v->not_found = 0;
|
||||
v->data = (u_char *) NGINX_VERSION;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map,
|
||||
ngx_str_t *match)
|
||||
{
|
||||
void *value;
|
||||
u_char *low;
|
||||
size_t len;
|
||||
ngx_uint_t key;
|
||||
|
||||
len = match->len;
|
||||
|
||||
if (len) {
|
||||
low = ngx_pnalloc(s->connection->pool, len);
|
||||
if (low == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
low = NULL;
|
||||
}
|
||||
|
||||
key = ngx_hash_strlow(low, match->data, len);
|
||||
|
||||
value = ngx_hash_find_combined(&map->hash, key, low, len);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
if (len && map->nregex) {
|
||||
ngx_int_t n;
|
||||
ngx_uint_t i;
|
||||
ngx_stream_map_regex_t *reg;
|
||||
|
||||
reg = map->regex;
|
||||
|
||||
for (i = 0; i < map->nregex; i++) {
|
||||
|
||||
n = ngx_stream_regex_exec(s, reg[i].regex, match);
|
||||
|
||||
if (n == NGX_OK) {
|
||||
return reg[i].value;
|
||||
}
|
||||
|
||||
if (n == NGX_DECLINED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* NGX_ERROR */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_variable_not_found(ngx_stream_session_t *s,
|
||||
ngx_stream_variable_value_t *v, uintptr_t data)
|
||||
{
|
||||
v->not_found = 1;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_stream_regex_t *
|
||||
ngx_stream_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
|
||||
{
|
||||
u_char *p;
|
||||
size_t size;
|
||||
ngx_str_t name;
|
||||
ngx_uint_t i, n;
|
||||
ngx_stream_variable_t *v;
|
||||
ngx_stream_regex_t *re;
|
||||
ngx_stream_regex_variable_t *rv;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
rc->pool = cf->pool;
|
||||
|
||||
if (ngx_regex_compile(rc) != NGX_OK) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
re = ngx_pcalloc(cf->pool, sizeof(ngx_stream_regex_t));
|
||||
if (re == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
re->regex = rc->regex;
|
||||
re->ncaptures = rc->captures;
|
||||
re->name = rc->pattern;
|
||||
|
||||
cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
|
||||
cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
|
||||
|
||||
n = (ngx_uint_t) rc->named_captures;
|
||||
|
||||
if (n == 0) {
|
||||
return re;
|
||||
}
|
||||
|
||||
rv = ngx_palloc(rc->pool, n * sizeof(ngx_stream_regex_variable_t));
|
||||
if (rv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
re->variables = rv;
|
||||
re->nvariables = n;
|
||||
|
||||
size = rc->name_size;
|
||||
p = rc->names;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
rv[i].capture = 2 * ((p[0] << 8) + p[1]);
|
||||
|
||||
name.data = &p[2];
|
||||
name.len = ngx_strlen(name.data);
|
||||
|
||||
v = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
|
||||
if (v == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rv[i].index = ngx_stream_get_variable_index(cf, &name);
|
||||
if (rv[i].index == NGX_ERROR) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
v->get_handler = ngx_stream_variable_not_found;
|
||||
|
||||
p += size;
|
||||
}
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re,
|
||||
ngx_str_t *str)
|
||||
{
|
||||
ngx_int_t rc, index;
|
||||
ngx_uint_t i, n, len;
|
||||
ngx_stream_variable_value_t *vv;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
|
||||
|
||||
if (re->ncaptures) {
|
||||
len = cmcf->ncaptures;
|
||||
|
||||
if (s->captures == NULL) {
|
||||
s->captures = ngx_palloc(s->connection->pool, len * sizeof(int));
|
||||
if (s->captures == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
rc = ngx_regex_exec(re->regex, str, s->captures, len);
|
||||
|
||||
if (rc == NGX_REGEX_NO_MATCHED) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
|
||||
ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
|
||||
rc, str, &re->name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < re->nvariables; i++) {
|
||||
|
||||
n = re->variables[i].capture;
|
||||
index = re->variables[i].index;
|
||||
vv = &s->variables[index];
|
||||
|
||||
vv->len = s->captures[n + 1] - s->captures[n];
|
||||
vv->valid = 1;
|
||||
vv->no_cacheable = 0;
|
||||
vv->not_found = 0;
|
||||
vv->data = &str->data[s->captures[n]];
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
{
|
||||
ngx_stream_variable_t *v;
|
||||
|
||||
v = cmcf->variables.elts;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
|
||||
"stream regex set $%V to \"%v\"", &v[index].name, vv);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
s->ncaptures = rc * 2;
|
||||
s->captures_data = str->data;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_variables_add_core_vars(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_stream_variable_t *cv, *v;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
|
||||
|
||||
cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
|
||||
sizeof(ngx_hash_keys_arrays_t));
|
||||
if (cmcf->variables_keys == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cmcf->variables_keys->pool = cf->pool;
|
||||
cmcf->variables_keys->temp_pool = cf->pool;
|
||||
|
||||
if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (cv = ngx_stream_core_variables; cv->name.len; cv++) {
|
||||
v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t));
|
||||
if (v == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*v = *cv;
|
||||
|
||||
rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v,
|
||||
NGX_HASH_READONLY_KEY);
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc == NGX_BUSY) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"conflicting variable name \"%V\"", &v->name);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_variables_init_vars(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
ngx_hash_key_t *key;
|
||||
ngx_hash_init_t hash;
|
||||
ngx_stream_variable_t *v, *av;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
/* set the handlers for the indexed stream variables */
|
||||
|
||||
cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
|
||||
|
||||
v = cmcf->variables.elts;
|
||||
key = cmcf->variables_keys->keys.elts;
|
||||
|
||||
for (i = 0; i < cmcf->variables.nelts; i++) {
|
||||
|
||||
for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
|
||||
|
||||
av = key[n].value;
|
||||
|
||||
if (v[i].name.len == key[n].key.len
|
||||
&& ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
|
||||
== 0)
|
||||
{
|
||||
v[i].get_handler = av->get_handler;
|
||||
v[i].data = av->data;
|
||||
|
||||
av->flags |= NGX_STREAM_VAR_INDEXED;
|
||||
v[i].flags = av->flags;
|
||||
|
||||
av->index = i;
|
||||
|
||||
if (av->get_handler == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||||
"unknown \"%V\" variable", &v[i].name);
|
||||
|
||||
return NGX_ERROR;
|
||||
|
||||
next:
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
|
||||
av = key[n].value;
|
||||
|
||||
if (av->flags & NGX_STREAM_VAR_NOHASH) {
|
||||
key[n].key.data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
hash.hash = &cmcf->variables_hash;
|
||||
hash.key = ngx_hash_key;
|
||||
hash.max_size = cmcf->variables_hash_max_size;
|
||||
hash.bucket_size = cmcf->variables_hash_bucket_size;
|
||||
hash.name = "variables_hash";
|
||||
hash.pool = cf->pool;
|
||||
hash.temp_pool = NULL;
|
||||
|
||||
if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
|
||||
cmcf->variables_keys->keys.nelts)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cmcf->variables_keys = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
109
src/stream/ngx_stream_variables.h
Normal file
109
src/stream/ngx_stream_variables.h
Normal file
@ -0,0 +1,109 @@
|
||||
|
||||
/*
|
||||
* Copyright (C) Igor Sysoev
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_VARIABLES_H_INCLUDED_
|
||||
#define _NGX_STREAM_VARIABLES_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_stream.h>
|
||||
|
||||
|
||||
typedef ngx_variable_value_t ngx_stream_variable_value_t;
|
||||
|
||||
#define ngx_stream_variable(v) { sizeof(v) - 1, 1, 0, 0, 0, (u_char *) v }
|
||||
|
||||
typedef struct ngx_stream_variable_s ngx_stream_variable_t;
|
||||
|
||||
typedef void (*ngx_stream_set_variable_pt) (ngx_stream_session_t *s,
|
||||
ngx_stream_variable_value_t *v, uintptr_t data);
|
||||
typedef ngx_int_t (*ngx_stream_get_variable_pt) (ngx_stream_session_t *s,
|
||||
ngx_stream_variable_value_t *v, uintptr_t data);
|
||||
|
||||
|
||||
#define NGX_STREAM_VAR_CHANGEABLE 1
|
||||
#define NGX_STREAM_VAR_NOCACHEABLE 2
|
||||
#define NGX_STREAM_VAR_INDEXED 4
|
||||
#define NGX_STREAM_VAR_NOHASH 8
|
||||
|
||||
|
||||
struct ngx_stream_variable_s {
|
||||
ngx_str_t name; /* must be first to build the hash */
|
||||
ngx_stream_set_variable_pt set_handler;
|
||||
ngx_stream_get_variable_pt get_handler;
|
||||
uintptr_t data;
|
||||
ngx_uint_t flags;
|
||||
ngx_uint_t index;
|
||||
};
|
||||
|
||||
|
||||
ngx_stream_variable_t *ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name,
|
||||
ngx_uint_t flags);
|
||||
ngx_int_t ngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name);
|
||||
ngx_stream_variable_value_t *ngx_stream_get_indexed_variable(
|
||||
ngx_stream_session_t *s, ngx_uint_t index);
|
||||
ngx_stream_variable_value_t *ngx_stream_get_flushed_variable(
|
||||
ngx_stream_session_t *s, ngx_uint_t index);
|
||||
|
||||
ngx_stream_variable_value_t *ngx_stream_get_variable(ngx_stream_session_t *s,
|
||||
ngx_str_t *name, ngx_uint_t key);
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t capture;
|
||||
ngx_int_t index;
|
||||
} ngx_stream_regex_variable_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_regex_t *regex;
|
||||
ngx_uint_t ncaptures;
|
||||
ngx_stream_regex_variable_t *variables;
|
||||
ngx_uint_t nvariables;
|
||||
ngx_str_t name;
|
||||
} ngx_stream_regex_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_regex_t *regex;
|
||||
void *value;
|
||||
} ngx_stream_map_regex_t;
|
||||
|
||||
|
||||
ngx_stream_regex_t *ngx_stream_regex_compile(ngx_conf_t *cf,
|
||||
ngx_regex_compile_t *rc);
|
||||
ngx_int_t ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re,
|
||||
ngx_str_t *str);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_hash_combined_t hash;
|
||||
#if (NGX_PCRE)
|
||||
ngx_stream_map_regex_t *regex;
|
||||
ngx_uint_t nregex;
|
||||
#endif
|
||||
} ngx_stream_map_t;
|
||||
|
||||
|
||||
void *ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map,
|
||||
ngx_str_t *match);
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_variables_add_core_vars(ngx_conf_t *cf);
|
||||
ngx_int_t ngx_stream_variables_init_vars(ngx_conf_t *cf);
|
||||
|
||||
|
||||
extern ngx_stream_variable_value_t ngx_stream_variable_null_value;
|
||||
extern ngx_stream_variable_value_t ngx_stream_variable_true_value;
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_VARIABLES_H_INCLUDED_ */
|
Loading…
Reference in New Issue
Block a user