diff options
author | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
---|---|---|
committer | kaiwu <kaiwu2004@gmail.com> | 2025-03-01 12:42:23 +0800 |
commit | 3f33461e4948bf05e60bdff35ec6c57a649c7860 (patch) | |
tree | 284c2ba95a41536ae1bff6bea710db0709a64739 /array-var-nginx-module-0.06/src/ngx_http_array_var_module.c | |
download | openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.tar.gz openresty-3f33461e4948bf05e60bdff35ec6c57a649c7860.zip |
openresty bundle
Diffstat (limited to 'array-var-nginx-module-0.06/src/ngx_http_array_var_module.c')
-rw-r--r-- | array-var-nginx-module-0.06/src/ngx_http_array_var_module.c | 756 |
1 files changed, 756 insertions, 0 deletions
diff --git a/array-var-nginx-module-0.06/src/ngx_http_array_var_module.c b/array-var-nginx-module-0.06/src/ngx_http_array_var_module.c new file mode 100644 index 0000000..76c4df7 --- /dev/null +++ b/array-var-nginx-module-0.06/src/ngx_http_array_var_module.c @@ -0,0 +1,756 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_array_var_util.h" +#include <ndk.h> + + +static ngx_str_t ngx_http_array_it_key = ngx_string("array_it"); + + +typedef struct { + ngx_uint_t nargs; +} ngx_http_array_split_data_t; + + +typedef struct { + unsigned in_place; + ngx_http_complex_value_t *template; + ngx_int_t array_it_index; +} ngx_http_array_map_data_t; + + +typedef struct { + unsigned in_place; +} ngx_http_array_map_op_data_t; + + +static char *ngx_http_array_split(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_array_map(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_array_map_op(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_array_join(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_array_var_split(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v, void *data); +static ngx_int_t ngx_http_array_var_map(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v, void *data); +static ngx_int_t ngx_http_array_var_map_op(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v, void *data); +static ngx_int_t ngx_http_array_var_join(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v); + + +static ngx_command_t ngx_http_array_var_commands[] = { + { + ngx_string ("array_split"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE, + ngx_http_array_split, + 0, + 0, + NULL + }, + { + ngx_string ("array_map"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE23, + ngx_http_array_map, + 0, + 0, + NULL + }, + { + ngx_string ("array_map_op"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE23, + ngx_http_array_map_op, + 0, + 0, + (void *) ngx_http_array_var_map_op + }, + { + ngx_string("array_join"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE23, + ngx_http_array_join, + 0, + 0, + (void *) ngx_http_array_var_join + }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_array_var_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL, /* merge location configuration */ +}; + + +ngx_module_t ngx_http_array_var_module = { + NGX_MODULE_V1, + &ngx_http_array_var_module_ctx, /* module context */ + ngx_http_array_var_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 char * +ngx_http_array_split(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ndk_set_var_t filter; + ngx_str_t target; + ngx_str_t *value; + ngx_str_t *bad_arg; + ngx_http_array_split_data_t *data = NULL; + + data = ngx_palloc(cf->pool, sizeof(ngx_http_array_split_data_t)); + if (data == NULL) { + return NGX_CONF_ERROR; + } + + filter.type = NDK_SET_VAR_MULTI_VALUE_DATA; + filter.func = (void *) ngx_http_array_var_split; + filter.data = data; + + value = cf->args->elts; + + if (cf->args->nelts == 2 + 1) { + dd("array_split $sep $var"); + data->nargs = filter.size = 2; + target = value[2]; + return ndk_set_var_multi_value_core(cf, &target, &value[1], &filter); + } + + /* cf->args->nelts >= 3 + 1 */ + + if (value[3].len >= sizeof("to=") - 1 + && ngx_str3cmp(value[3].data, 't', 'o', '=')) + { + dd("array_split $sep $str to=$array"); + data->nargs = filter.size = 2; + + target.data = value[3].data + sizeof("to=") - 1; + target.len = value[3].len - (sizeof("to=") - 1); + dd("split target: %.*s", (int) target.len, target.data); + + if (cf->args->nelts > 3 + 1) { + bad_arg = &value[4]; + goto unexpected_arg; + } + + return ndk_set_var_multi_value_core(cf, &target, &value[1], &filter); + } + + /* the 3rd argument is max_items */ + + if (cf->args->nelts > 4 + 1) { + bad_arg = &value[5]; + goto unexpected_arg; + } + + if (cf->args->nelts == 4 + 1) { + /* array_split $sep $str $max to=$array */ + + if (value[4].len < sizeof("to=") - 1 + || ! (ngx_str3cmp(value[4].data, 't', 'o', '='))) + { + ngx_conf_log_error(NGX_LOG_ERR, cf, 0, + "%V: expecting the \"to\" option at the " + "4th argument: \"%V\"", + &cmd->name, &value[4]); + + return NGX_CONF_ERROR; + } + + data->nargs = filter.size = 3; + + target.data = value[4].data + sizeof("to=") - 1; + target.len = value[4].len - (sizeof("to=") - 1); + + return ndk_set_var_multi_value_core(cf, &target, &value[1], &filter); + } + + /* cf->args->nelts == 3 + 1 */ + + /* array_split $sep $var $max */ + + target = value[2]; + data->nargs = filter.size = 3; + + return ndk_set_var_multi_value_core(cf, &target, &value[1], &filter); + +unexpected_arg: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: unexpected argument \"%V\"", + &cmd->name, bad_arg); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_array_map(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ndk_set_var_t filter; + ngx_str_t target; + ngx_str_t *value; + ngx_http_array_map_data_t *data; + ngx_http_compile_complex_value_t ccv; + + data = ngx_palloc(cf->pool, sizeof(ngx_http_array_map_data_t)); + if (data == NULL) { + return NGX_CONF_ERROR; + } + + data->template = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (data->template == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + if (value[1].len == 0) { + ngx_memzero(data->template, sizeof(ngx_http_complex_value_t)); + + } else { + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = data->template; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + filter.type = NDK_SET_VAR_VALUE_DATA; + filter.func = (void *) ngx_http_array_var_map; + filter.data = data; + filter.size = 1; + + data->array_it_index = ngx_http_array_var_add_variable(cf, + &ngx_http_array_it_key); + + if (data->array_it_index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 2 + 1) { + /* array_map $template $array */ + data->in_place = 1; + target = value[2]; + + } else { + /* cf->args->nelts == 3 + 1 */ + + if (value[3].len < sizeof("to=") - 1 + || ! (ngx_str3cmp(value[3].data, 't', 'o', '='))) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%V: expecting the \"to\" option at " + "the 3rd argument: \"%V\"", + &cmd->name, &value[3]); + + return NGX_CONF_ERROR; + } + + target.data = value[3].data + sizeof("to=") - 1; + target.len = value[3].len - (sizeof("to=") - 1); + data->in_place = 0; + } + + return ndk_set_var_value_core(cf, &target, &value[2], &filter); +} + + +static char * +ngx_http_array_map_op(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_array_map_op_data_t *data; + ndk_set_var_t filter; + ngx_str_t target; + ngx_str_t *value; + ngx_str_t *bad_arg; + + data = ngx_palloc(cf->pool, sizeof(ngx_http_array_map_op_data_t)); + if (data == NULL) { + return NGX_CONF_ERROR; + } + + filter.type = NDK_SET_VAR_MULTI_VALUE_DATA; + filter.func = cmd->post; + filter.data = data; + + value = cf->args->elts; + + if (cf->args->nelts == 2 + 1) { + dd("array_join $sep $var"); + + filter.size = 2; + data->in_place = 1; + + target = value[2]; + + dd("array join target: %.*s", (int) target.len, target.data); + + return ndk_set_var_multi_value_core(cf, &target, &value[1], &filter); + } + + /* cf->args->nelts == 3 + 1 */ + + if (value[3].len >= sizeof("to=") - 1 + && ngx_str3cmp(value[3].data, 't', 'o', '=')) + { + /* array_join $sep $str to=$array */ + filter.size = 2; + data->in_place = 0; + + target.data = value[3].data + sizeof("to=") - 1; + target.len = value[3].len - (sizeof("to=") - 1); + + if (cf->args->nelts > 3 + 1) { + bad_arg = &value[4]; + + } else { + return ndk_set_var_multi_value_core(cf, &target, &value[1], + &filter); + } + + } else { + bad_arg = &value[3]; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%V: unexpected argument \"%V\"", + &cmd->name, bad_arg); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_array_join(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ndk_set_var_t filter; + ngx_str_t target; + ngx_str_t *value; + ngx_str_t *bad_arg; + + filter.type = NDK_SET_VAR_MULTI_VALUE; + filter.func = cmd->post; + + value = cf->args->elts; + + if (cf->args->nelts == 2 + 1) { + dd("array_join $sep $var"); + + filter.size = 2; + target = value[2]; + + dd("array join target: %.*s", (int) target.len, target.data); + + return ndk_set_var_multi_value_core(cf, &target, &value[1], &filter); + } + + /* cf->args->nelts == 3 + 1 */ + + if (value[3].len >= sizeof("to=") - 1 + && ngx_str3cmp(value[3].data, 't', 'o', '=')) + { + /* array_join $sep $str to=$array */ + filter.size = 2; + + target.data = value[3].data + sizeof("to=") - 1; + target.len = value[3].len - (sizeof("to=") - 1); + + if (cf->args->nelts > 3 + 1) { + bad_arg = &value[4]; + } else { + return ndk_set_var_multi_value_core(cf, &target, &value[1], + &filter); + } + + } else { + bad_arg = &value[3]; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%V: unexpected argument \"%V\"", + &cmd->name, bad_arg); + + return NGX_CONF_ERROR; +} + + +static ngx_int_t +ngx_http_array_var_split(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v, void *data) +{ + ngx_http_array_split_data_t *conf = data; + ngx_http_variable_value_t *sep, *str; + ngx_str_t *s; + u_char *pos, *end, *last = NULL; + ssize_t max, i, len = 4; + ngx_array_t *array; + + if (conf->nargs == 3) { + max = ngx_atosz(v[2].data, v[2].len); + if (max == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "array_split: invalid max items: \"%V\"", + &v[2]); + + return NGX_ERROR; + } + } else { + max = 0; + } + + if (max) { + len = max; + } + + array = ngx_array_create(r->pool, len, sizeof(ngx_str_t)); + if (array == NULL) { + return NGX_ERROR; + } + + sep = &v[0]; + str = &v[1]; + + pos = str->data; + end = str->data + str->len; + + i = 0; + + if (sep->len == 0) { + /* split each char into an array elem */ + + while (i != max - 1 && pos < end - 1) { + s = ngx_array_push(array); + if (s == NULL) { + return NGX_ERROR; + } + + s->data = pos; + s->len = 1; + + pos++; + i++; + } + + goto done; + } + + while (i != max - 1) { + last = ngx_http_array_var_strlstrn(pos, end, sep->data, + sep->len - 1); + if (last == NULL) { + break; + } + + s = ngx_array_push(array); + if (s == NULL) { + return NGX_ERROR; + } + + s->data = pos; + s->len = last - pos; + + dd("split item %.*s", (int) s->len, s->data); + + pos = last + sep->len; + i++; + } + +done: + + dd("pos %p, last %p, end %p", pos, last, end); + + s = ngx_array_push(array); + if (s == NULL) { + return NGX_ERROR; + } + + s->data = pos; + s->len = end - pos; + + dd("split item %.*s", (int) s->len, s->data); + + dd("split: array size: %d", (int) array->nelts); + dd("split array ptr: %p", array); + + res->data = (u_char *) array; + res->len = sizeof(ngx_array_t); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_array_var_map(ngx_http_request_t *r, ngx_str_t *res, + ngx_http_variable_value_t *v, void *data) +{ + ngx_http_array_map_data_t *conf = data; + ngx_http_variable_value_t *array_it; + ngx_uint_t i; + ngx_str_t *value, *new_value; + ngx_array_t *array, *new_array; + + dd("entered array var map"); + + if (conf->template == NULL) { + dd("template empty"); + + return NGX_OK; + } + + if (v[0].len != sizeof(ngx_array_t)) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "array_join: invalid array variable value in the 2nd " + "argument: \"%.*s\"", &v[0]); + + return NGX_ERROR; + } + + array = (ngx_array_t *) v[0].data; + + value = array->elts; + + array_it = ngx_http_get_indexed_variable(r, conf->array_it_index); + if (array_it == NULL) { + return NGX_ERROR; + } + + if (conf->in_place) { + new_array = array; + + } else { + new_array = ngx_array_create(r->pool, array->nelts, + sizeof(ngx_str_t)); + if (new_array == NULL) { + return NGX_ERROR; + } + } + + dd("array var map: array size: %d", (int) array->nelts); + + array_it->not_found = 0; + array_it->valid = 1; + + for (i = 0; i < array->nelts; i++) { + array_it->data = value[i].data; + array_it->len = value[i].len; + + dd("array it: %.*s", array_it->len, array_it->data); + + if (conf->in_place) { + new_value = &value[i]; + + } else { + new_value = ngx_array_push(new_array); + if (new_value == NULL) { + return NGX_ERROR; + } + } + + if (ngx_http_complex_value(r, conf->template, new_value) != NGX_OK) { + return NGX_ERROR; + } + + dd("array var map: new item: %.*s", (int) new_value->len, + new_value->data); + } + + array_it->not_found = 1; + array_it->valid = 0; + + res->data = (u_char *) new_array; + res->len = sizeof(ngx_array_t); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_array_var_map_op(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v, void *data) +{ + ngx_http_variable_value_t arg; + ngx_http_array_map_op_data_t *conf = data; + ndk_set_var_value_pt func; + ngx_int_t rc; + ngx_uint_t i; + ngx_str_t *value; + ngx_str_t *new_value; + ngx_array_t *array; + ngx_array_t *new_array; + + func = ngx_http_array_var_get_func_from_cmd(v[0].data, v[0].len); + + if (func == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "array_map_op: directive \"%v\" not found " + "or does not use ndk_set_var_value", + &v[0]); + + return NGX_ERROR; + } + + if (v[1].len != sizeof(ngx_array_t)) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "array_map_op: invalid array variable value in the 2nd " + "argument: \"%.*s\"", &v[0]); + + return NGX_ERROR; + } + + array = (ngx_array_t *) v[1].data; + + value = array->elts; + + if (conf->in_place) { + new_array = array; + + } else { + new_array = ngx_array_create(r->pool, array->nelts, + sizeof(ngx_str_t)); + if (new_array == NULL) { + return NGX_ERROR; + } + } + + for (i = 0; i < array->nelts; i++) { + arg.data = value[i].data; + arg.len = value[i].len; + arg.valid = 1; + arg.not_found = 0; + + if (conf->in_place) { + new_value = &value[i]; + + } else { + new_value = ngx_array_push(new_array); + if (new_value == NULL) { + return NGX_ERROR; + } + } + + rc = func(r, new_value, &arg); + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + + res->data = (u_char *) new_array; + res->len = sizeof(ngx_array_t); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_array_var_join(ngx_http_request_t *r, + ngx_str_t *res, ngx_http_variable_value_t *v) +{ + ngx_http_variable_value_t *sep; + ngx_array_t *array; + size_t len; + ngx_str_t *value; + ngx_uint_t i; + u_char *p; + + sep = &v[0]; + + dd("sep %.*s", sep->len, sep->data); + + if (v[1].len != sizeof(ngx_array_t)) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "array_join: invalid array variable value in the " + "2nd argument: \"%V\"", &v[1]); + + return NGX_ERROR; + } + + array = (ngx_array_t *) v[1].data; + + dd("join array ptr %p", array); + dd("array->nelts: %d", (int) array->nelts); + + if (array->nelts == 0) { + res->data = NULL; + res->len = 0; + return NGX_OK; + } + + value = array->elts; + + len = sep->len * (array->nelts - 1); + + for (i = 0; i < array->nelts; i++) { + len += value[i].len; + } + + dd("buf len %d", (int) len); + + res->data = ngx_palloc(r->pool, len); + if (res->data == NULL) { + return NGX_ERROR; + } + + res->len = len; + + p = res->data; + + for (i = 0; i < array->nelts; i++) { + dd("copying elem of size %d", (int) value[i].len); + p = ngx_copy(p, value[i].data, value[i].len); + if (i < array->nelts - 1) { + p = ngx_copy(p, sep->data, sep->len); + } + } + + if (p != res->data + res->len) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "array_join: buffer error"); + + return NGX_ERROR; + } + + return NGX_OK; +} |