summaryrefslogtreecommitdiff
path: root/array-var-nginx-module-0.06/src/ngx_http_array_var_module.c
diff options
context:
space:
mode:
authorkaiwu <kaiwu2004@gmail.com>2025-03-01 12:42:23 +0800
committerkaiwu <kaiwu2004@gmail.com>2025-03-01 12:42:23 +0800
commit3f33461e4948bf05e60bdff35ec6c57a649c7860 (patch)
tree284c2ba95a41536ae1bff6bea710db0709a64739 /array-var-nginx-module-0.06/src/ngx_http_array_var_module.c
downloadopenresty-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.c756
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;
+}