diff --git a/README.md b/README.md index 7e403e4..4bf9b99 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,12 @@ in the key-value database. The database is stored in shared memory or Redis as specified by the zone parameter. +In `key`, you can use a mix of variables and text or just variables. + +> For example: +> - `$remote_addr:$http_user_agent` +> - `'$remote_addr $http_user_agent $host "a random text"'` + ``` Syntax: keyval_zone zone=name:size; Default: - diff --git a/src/ngx_http_keyval_module.c b/src/ngx_http_keyval_module.c index 933fdba..7c1c622 100644 --- a/src/ngx_http_keyval_module.c +++ b/src/ngx_http_keyval_module.c @@ -121,30 +121,10 @@ ngx_http_keyval_conf_set_variable(ngx_conf_t *cf, return NGX_CONF_OK; } -static ngx_int_t -ngx_http_keyval_variable_get_key(ngx_http_request_t *r, - ngx_keyval_variable_t *var, ngx_str_t *key) +static ngx_variable_value_t * +ngx_http_keyval_get_indexed_variable(void *data, ngx_uint_t index) { - if (!key || !var) { - return NGX_ERROR; - } - - if (var->key_index != NGX_CONF_UNSET) { - ngx_http_variable_value_t *v; - v = ngx_http_get_indexed_variable(r, var->key_index); - if (v == NULL || v->not_found) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "keyval: variable specified was not provided"); - return NGX_ERROR; - } else { - key->data = v->data; - key->len = v->len; - } - } else { - *key = var->key_string; - } - - return NGX_OK; + return ngx_http_get_indexed_variable((ngx_http_request_t *) data, index); } static ngx_int_t @@ -169,7 +149,9 @@ ngx_http_keyval_variable_init(ngx_http_request_t *r, uintptr_t data, var = (ngx_keyval_variable_t *) data; - if (ngx_http_keyval_variable_get_key(r, var, key) != NGX_OK) { + if (ngx_keyval_variable_get_key(r->connection, var, key, + ngx_http_keyval_get_indexed_variable, + (void *) r) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "keyval: rejected due to not found variable key"); return NGX_ERROR; diff --git a/src/ngx_keyval.c b/src/ngx_keyval.c index 947597a..e0f4a6e 100644 --- a/src/ngx_keyval.c +++ b/src/ngx_keyval.c @@ -413,6 +413,11 @@ ngx_keyval_conf_set_variable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf, ngx_keyval_get_variable_index get_variable_index) { ngx_str_t *value; + int final_pos = 0; + int num_vars = 0; + size_t size_buffer_variable_name = 0, size_buffer_intermediate_string = 0; + u_char *string = NULL, *variable_name = NULL; + ngx_array_t *indexes = NULL; if (!config || !tag) { return "missing required parameter"; @@ -420,6 +425,9 @@ ngx_keyval_conf_set_variable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf, value = cf->args->elts; + size_buffer_variable_name = value[1].len; + size_buffer_intermediate_string = value[1].len; + if (value[1].len == 0) { return "is empty"; } @@ -449,14 +457,78 @@ ngx_keyval_conf_set_variable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf, return "failed to allocate iteam"; } - if (value[1].data[0] == '$') { - value[1].data++; - value[1].len--; - (*var)->key_index = get_variable_index(cf, &value[1]); - ngx_str_null(&((*var)->key_string)); - } else { - (*var)->key_index = NGX_CONF_UNSET; + if (config->indexes == NULL) { + config->indexes = ngx_array_create(cf->pool, 4, sizeof(ngx_array_t)); + if (config->indexes == NULL) { + return "failed to allocate"; + } + } + indexes = ngx_array_push(config->indexes); + if (indexes == NULL) { + return "failed to allocate item"; + } + (*var)->indexes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t)); + if ((*var)->indexes == NULL) { + return "failed to allocate"; + } + + string = value[1].data; + + (*var)->key_string.len = 0; + (*var)->key_string.data = ngx_pnalloc(cf->pool, + size_buffer_intermediate_string); + if ((*var)->key_string.data == NULL) { + return "failed to allocate memory for intermediate string"; + } + + variable_name = ngx_pnalloc(cf->pool, size_buffer_variable_name); + if (variable_name == NULL) { + return "failed to allocate memory for variable name buffer"; + } + + while (*string != '\0') { + if (*string == '$') { + int variable_name_str_index = 0; + ngx_int_t *index; + ngx_str_t str; + + (*var)->key_string.data[final_pos++] = '$'; + (*var)->key_string.len++; + string++; + + while (*string != '\0' + && ((*string >= 'A' && *string <= 'Z') + || (*string >= 'a' && *string <= 'z') + || (*string >= '0' && *string <= '9') + || *string == '_')) { + variable_name[variable_name_str_index] = *string; + variable_name_str_index++; + string++; + } + + variable_name[variable_name_str_index] = '\0'; + + str.data = variable_name; + str.len = ngx_strlen(variable_name); + + index = ngx_array_push((*var)->indexes); + if (index == NULL) { + return "failed to allocate item"; + } + *index = get_variable_index(cf, &str); + + num_vars++; + } else { + (*var)->key_string.len++; + (*var)->key_string.data[final_pos++] = *string; + string++; + } + } + + if (num_vars == 0) { (*var)->key_string = value[1]; + } else { + (*var)->key_string.data[final_pos] = '\0'; } (*var)->variable = value[2]; @@ -478,6 +550,83 @@ ngx_keyval_conf_set_variable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf, return NGX_CONF_OK; } +ngx_int_t +ngx_keyval_variable_get_key(ngx_connection_t *connection, + ngx_keyval_variable_t *var, ngx_str_t *key, + ngx_keyval_get_index_variable get_index_variable, + void *data) +{ + if (!key || !var || !connection || !data) { + return NGX_ERROR; + } + + if (var->indexes->nelts != 0) { + ngx_variable_value_t **v; + ngx_int_t current_index = 0; + ngx_str_t string_var = var->key_string; + ngx_uint_t size_string = 0; + u_char *last_space_available; + + v = ngx_palloc(connection->pool, + sizeof(ngx_variable_value_t *) * var->indexes->nelts); + + if (v == NULL) { + ngx_log_error(NGX_LOG_ERR, connection->log, 0, + "keyval: failed to allocate memory " + "for variable values array"); + return NGX_ERROR; + } + + ngx_int_t *indexes = var->indexes->elts; + + for (ngx_uint_t i = 0 ; i < var->indexes->nelts ; i++) { + v[i] = get_index_variable(data, indexes[i]); + + if (v[i] == NULL || v[i]-> not_found) { + ngx_log_error(NGX_LOG_INFO, connection->log, 0, + "keyval: variable specified was not provided"); + return NGX_ERROR; + } + + size_string += v[i]->len; + } + + key->data = (u_char *) ngx_pnalloc(connection->pool, + size_string + + (string_var.len - var->indexes->nelts) + + 1); + + if (key->data == NULL) { + ngx_log_error(NGX_LOG_ERR, connection->log, 0, + "keyval: error allocating memory for key string"); + return NGX_ERROR; + } + + key->len = 0; + + last_space_available = key->data; + + for ( ; *(string_var.data) != '\0' ; string_var.data++) { + if (*(string_var.data) == '$') { + last_space_available = ngx_cpystrn(last_space_available, + v[current_index]->data, + v[current_index]->len + 1); + key->len += v[current_index++]->len; + } else { + *last_space_available = *(string_var.data); + last_space_available += sizeof(u_char); + key->len++; + } + } + + *last_space_available = '\0'; + } else { + *key = var->key_string; + } + + return NGX_OK; +} + void * ngx_keyval_create_main_conf(ngx_conf_t *cf) { diff --git a/src/ngx_keyval.h b/src/ngx_keyval.h index 5d04b51..9dd4f15 100644 --- a/src/ngx_keyval.h +++ b/src/ngx_keyval.h @@ -13,6 +13,7 @@ typedef enum { } ngx_keyval_zone_type_t; typedef struct { + ngx_array_t *indexes; ngx_array_t *variables; ngx_array_t *zones; } ngx_keyval_conf_t; @@ -50,7 +51,7 @@ typedef struct { } ngx_keyval_zone_t; typedef struct { - ngx_int_t key_index; + ngx_array_t *indexes; ngx_str_t key_string; ngx_str_t variable; ngx_keyval_zone_t *zone; @@ -63,12 +64,14 @@ typedef struct { #endif typedef ngx_int_t (*ngx_keyval_get_variable_index)(ngx_conf_t *cf, ngx_str_t *name); +typedef ngx_variable_value_t *(*ngx_keyval_get_index_variable)(void *data, ngx_uint_t index); char *ngx_keyval_conf_set_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf, ngx_keyval_conf_t *config, void *tag); #if (NGX_HAVE_KEYVAL_ZONE_REDIS) char *ngx_keyval_conf_set_zone_redis(ngx_conf_t *cf, ngx_command_t *cmd, void *conf, ngx_keyval_conf_t *config, void *tag); #endif char *ngx_keyval_conf_set_variable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf, ngx_keyval_conf_t *config, void *tag, ngx_keyval_variable_t **var, ngx_keyval_get_variable_index get_variable_index); +ngx_int_t ngx_keyval_variable_get_key(ngx_connection_t *connection, ngx_keyval_variable_t *var, ngx_str_t *key, ngx_keyval_get_index_variable get_index_variable, void *data); void *ngx_keyval_create_main_conf(ngx_conf_t *cf); diff --git a/src/ngx_stream_keyval_module.c b/src/ngx_stream_keyval_module.c index 820145b..3bbfb38 100644 --- a/src/ngx_stream_keyval_module.c +++ b/src/ngx_stream_keyval_module.c @@ -119,30 +119,10 @@ ngx_stream_keyval_conf_set_variable(ngx_conf_t *cf, return NGX_CONF_OK; } -static ngx_int_t -ngx_stream_keyval_variable_get_key(ngx_stream_session_t *s, - ngx_keyval_variable_t *var, ngx_str_t *key) +static ngx_variable_value_t * +ngx_stream_keyval_get_indexed_variable(void *data, ngx_uint_t index) { - if (!key || !var) { - return NGX_ERROR; - } - - if (var->key_index != NGX_CONF_UNSET) { - ngx_stream_variable_value_t *v; - v = ngx_stream_get_indexed_variable(s, var->key_index); - if (v == NULL || v->not_found) { - ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, - "keyval: variable specified was not provided"); - return NGX_ERROR; - } else { - key->data = v->data; - key->len = v->len; - } - } else { - *key = var->key_string; - } - - return NGX_OK; + return ngx_stream_get_indexed_variable((ngx_stream_session_t *) data, index); } static ngx_int_t @@ -167,7 +147,9 @@ ngx_stream_keyval_variable_init(ngx_stream_session_t *s, uintptr_t data, var = (ngx_keyval_variable_t *) data; - if (ngx_stream_keyval_variable_get_key(s, var, key) != NGX_OK) { + if (ngx_keyval_variable_get_key(s->connection, var, key, + ngx_stream_keyval_get_indexed_variable, + (void *) s) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "keyval: rejected due to not found variable key"); return NGX_ERROR; diff --git a/t/keyval_multivar.t b/t/keyval_multivar.t new file mode 100644 index 0000000..fd4b6aa --- /dev/null +++ b/t/keyval_multivar.t @@ -0,0 +1,226 @@ +use Test::Nginx::Socket 'no_plan'; + +no_root_location(); +no_shuffle(); + +run_tests(); + +__DATA__ + +=== Same host but different UA +--- http_config +keyval_zone zone=test:1M; +keyval $remote_addr:$http_user_agent $keyval_data zone=test; +--- config +location = /get { + return 200 "get($http_user_agent): $keyval_data\n"; +} +location = /set { + set $keyval_data "test $http_user_agent"; + return 200 "$keyval_data\n"; +} +--- request eval +[ + "GET /get", + "GET /get", + "GET /set", + "GET /set", + "GET /get", + "GET /get" +] +--- more_headers eval +[ + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" +] +--- response_body eval +[ + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): \n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): \n", + "test Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n", + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): test Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n" +] + +=== Two vars with different UAs +--- http_config +keyval_zone zone=test:5M; +keyval "$remote_addr:$http_user_agent" $keyval_data1 zone=test; +keyval "$remote_addr:$http_user_agent" $keyval_data2 zone=test; +--- config +location = /get { + return 200 "get($http_user_agent): $keyval_data1 $keyval_data2\n"; +} +location = /set1 { + set $keyval_data1 "test1 $http_user_agent"; + return 200 "$keyval_data1\n"; +} +location = /set2 { + set $keyval_data2 "test2 $http_user_agent"; + return 200 "$keyval_data2\n"; +} +--- request eval +[ + "GET /get", + "GET /get", + "GET /set1", + "GET /set1", + "GET /set2", + "GET /set2", + "GET /get", + "GET /get" +] +--- more_headers eval +[ + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" +] +--- response_body eval +[ + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): \n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): \n", + "test1 Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "test1 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n", + "test2 Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "test2 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n", + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): test2 Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0 test2 Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): test2 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 test2 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n" +] + +=== Same host but different UA and other chars in string +--- http_config +keyval_zone zone=test:1M; +keyval "$remote_addr $http_user_agent random string random number 123456 test" $keyval_data zone=test; +--- config +location = /get { + return 200 "get($http_user_agent): $keyval_data\n"; +} +location = /set { + set $keyval_data "test $http_user_agent"; + return 200 "$keyval_data\n"; +} +--- request eval +[ + "GET /get", + "GET /get", + "GET /set", + "GET /set", + "GET /get", + "GET /get" +] +--- more_headers eval +[ + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" +] +--- response_body eval +[ + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): \n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): \n", + "test Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n", + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): test Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n" +] + +=== Variables that exist and one that doesn't +--- http_config +keyval_zone zone=test:1M; +keyval "$remote_addr $http_user_agent random string random number 123456 $hosst $request" $keyval_data zone=test; +--- config +--- must_die + +=== Pure text is still functional +--- http_config +keyval_zone zone=test:1M; +keyval "text1 text2" $keyval_data zone=test; +--- config +location = /get { + return 200 "get($http_user_agent): $keyval_data\n"; +} +location = /set { + set $keyval_data "test $http_user_agent"; + return 200 "$keyval_data\n"; +} +--- request eval +[ + "GET /get", + "GET /get", + "GET /set", + "GET /set", + "GET /get", + "GET /get" +] +--- more_headers eval +[ + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" +] +--- response_body eval +[ + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): \n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): \n", + "test Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\n", + "test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n", + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\n" +] + +=== many variable keys +--- http_config +keyval_zone zone=test:1M; +keyval $remote_addr:$http_user_agent:$cookie_key1:$cookie_key2:$cookie_key3:$cookie_key4:$cookie_key5:$cookie_key6:$cookie_key7:$cookie_key8:$cookie_key9:$cookie_key10:$cookie_key11:$cookie_key12:$cookie_key13:$cookie_key14:$cookie_key15 $keyval_data zone=test; +--- config +location = /get { + return 200 "get($http_user_agent): $keyval_data\n"; +} +location = /set { + set $keyval_data "test $http_user_agent:$cookie_key1:$cookie_key2:$cookie_key3:$cookie_key4:$cookie_key5:$cookie_key6:$cookie_key7:$cookie_key8:$cookie_key9:$cookie_key10:$cookie_key11:$cookie_key12:$cookie_key13:$cookie_key14:$cookie_key15"; + return 200 "$keyval_data\n"; +} +--- request eval +[ + "GET /get", + "GET /get", + "GET /set", + "GET /set", + "GET /get", + "GET /get" +] +--- more_headers eval +[ + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\nCookie: key1=key1\nCookie: key2=key2\nCookie: key3=key3\nCookie: key4=key4\nCookie: key5=key5\nCookie: key6=key6\nCookie: key7=key7\nCookie: key8=key8\nCookie: key9=key9\nCookie: key10=key10\nCookie: key11=key11\nCookie: key12=key12\nCookie: key13=key13\nCookie: key14=key14\nCookie: key15=key15", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\nCookie: key1=key1\nCookie: key2=key2\nCookie: key3=key3\nCookie: key4=key4\nCookie: key5=key5\nCookie: key6=key6\nCookie: key7=key7\nCookie: key8=key8\nCookie: key9=key9\nCookie: key10=key10\nCookie: key11=key11\nCookie: key12=key12\nCookie: key13=key13\nCookie: key14=key14\nCookie: key15=key15", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\nCookie: key1=key1\nCookie: key2=key2\nCookie: key3=key3\nCookie: key4=key4\nCookie: key5=key5\nCookie: key6=key6\nCookie: key7=key7\nCookie: key8=key8\nCookie: key9=key9\nCookie: key10=key10\nCookie: key11=key11\nCookie: key12=key12\nCookie: key13=key13\nCookie: key14=key14\nCookie: key15=key15", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\nCookie: key1=key1\nCookie: key2=key2\nCookie: key3=key3\nCookie: key4=key4\nCookie: key5=key5\nCookie: key6=key6\nCookie: key7=key7\nCookie: key8=key8\nCookie: key9=key9\nCookie: key10=key10\nCookie: key11=key11\nCookie: key12=key12\nCookie: key13=key13\nCookie: key14=key14\nCookie: key15=key15", + "User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0\nCookie: key1=key1\nCookie: key2=key2\nCookie: key3=key3\nCookie: key4=key4\nCookie: key5=key5\nCookie: key6=key6\nCookie: key7=key7\nCookie: key8=key8\nCookie: key9=key9\nCookie: key10=key10\nCookie: key11=key11\nCookie: key12=key12\nCookie: key13=key13\nCookie: key14=key14\nCookie: key15=key15", + "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36\nCookie: key1=key1\nCookie: key2=key2\nCookie: key3=key3\nCookie: key4=key4\nCookie: key5=key5\nCookie: key6=key6\nCookie: key7=key7\nCookie: key8=key8\nCookie: key9=key9\nCookie: key10=key10\nCookie: key11=key11\nCookie: key12=key12\nCookie: key13=key13\nCookie: key14=key14\nCookie: key15=key15" +] +--- response_body eval +[ + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): \n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): \n", + "test Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0:key1:key2:key3:key4:key5:key6:key7:key8:key9:key10:key11:key12:key13:key14:key15\n", + "test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36:key1:key2:key3:key4:key5:key6:key7:key8:key9:key10:key11:key12:key13:key14:key15\n", + "get(Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0): test Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:123.0) Gecko/20100101 Firefox/123.0:key1:key2:key3:key4:key5:key6:key7:key8:key9:key10:key11:key12:key13:key14:key15\n", + "get(Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36): test Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36:key1:key2:key3:key4:key5:key6:key7:key8:key9:key10:key11:key12:key13:key14:key15\n" +]