[nginx] Stream: variables and script.
Vladimir Homutov
vl at nginx.com
Mon Jul 4 14:50:14 UTC 2016
details: http://hg.nginx.org/nginx/rev/c70b7f4537e1
branches:
changeset: 6607:c70b7f4537e1
user: Vladimir Homutov <vl at nginx.com>
date: Mon Jul 04 16:37:36 2016 +0300
description:
Stream: variables and script.
This is a port of corresponding http code with unrelated features excluded.
diffstat:
auto/modules | 4 +
src/stream/ngx_stream.c | 4 +
src/stream/ngx_stream.h | 139 +++--
src/stream/ngx_stream_core_module.c | 49 +-
src/stream/ngx_stream_handler.c | 9 +
src/stream/ngx_stream_script.c | 852 ++++++++++++++++++++++++++++++++++++
src/stream/ngx_stream_script.h | 123 +++++
src/stream/ngx_stream_variables.c | 621 ++++++++++++++++++++++++++
src/stream/ngx_stream_variables.h | 109 ++++
9 files changed, 1851 insertions(+), 59 deletions(-)
diffs (truncated from 2092 to 1000 lines):
diff -r 2f41d383c9c7 -r c70b7f4537e1 auto/modules
--- a/auto/modules Wed Jun 15 15:10:24 2016 +0300
+++ b/auto/modules Mon Jul 04 16:37:36 2016 +0300
@@ -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 \
diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream.c
--- a/src/stream/ngx_stream.c Wed Jun 15 15:10:24 2016 +0300
+++ b/src/stream/ngx_stream.c Mon Jul 04 16:37:36 2016 +0300
@@ -230,6 +230,10 @@ ngx_stream_block(ngx_conf_t *cf, ngx_com
}
}
+ if (ngx_stream_variables_init_vars(cf) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
*cf = pcf;
diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream.h
--- a/src/stream/ngx_stream.h Wed Jun 15 15:10:24 2016 +0300
+++ b/src/stream/ngx_stream.h Mon Jul 04 16:37:36 2016 +0300
@@ -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
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)(ng
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" */
-
- ngx_connection_t *connection;
-
- off_t received;
+ uint32_t signature; /* "STRM" */
- ngx_log_handler_pt log_handler;
+ ngx_connection_t *connection;
- void **ctx;
- void **main_conf;
- void **srv_conf;
+ off_t received;
- ngx_stream_upstream_t *upstream;
+ ngx_log_handler_pt log_handler;
+
+ void **ctx;
+ void **main_conf;
+ void **srv_conf;
+
+ 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;
diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream_core_module.c
--- a/src/stream/ngx_stream_core_module.c Wed Jun 15 15:10:24 2016 +0300
+++ b/src/stream/ngx_stream_core_module.c Mon Jul 04 16:37:36 2016 +0300
@@ -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_
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_co
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_con
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)
{
diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream_handler.c
--- a/src/stream/ngx_stream_handler.c Wed Jun 15 15:10:24 2016 +0300
+++ b/src/stream/ngx_stream_handler.c Mon Jul 04 16:37:36 2016 +0300
@@ -149,6 +149,15 @@ ngx_stream_init_connection(ngx_connectio
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);
diff -r 2f41d383c9c7 -r c70b7f4537e1 src/stream/ngx_stream_script.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stream/ngx_stream_script.c Mon Jul 04 16:37:36 2016 +0300
@@ -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;
More information about the nginx-devel
mailing list