[nginx] Limit conn: use complex value in limit_conn_zone (ticket...

Valentin Bartenev vbart at nginx.com
Wed Sep 24 17:56:04 UTC 2014


details:   http://hg.nginx.org/nginx/rev/c9787372f16d
branches:  
changeset: 5860:c9787372f16d
user:      Valentin Bartenev <vbart at nginx.com>
date:      Wed Sep 24 21:55:19 2014 +0400
description:
Limit conn: use complex value in limit_conn_zone (ticket #121).

One intentional side effect of this change is that key is allowed only
in the first position.  Previously, it was possible to specify the key
variable at any position, but that was never documented, and is contrary
to nginx configuration practice for positional parameters.

diffstat:

 src/http/modules/ngx_http_limit_conn_module.c |  123 +++++++++++--------------
 1 files changed, 55 insertions(+), 68 deletions(-)

diffs (243 lines):

diff -r ad9116427acf -r c9787372f16d src/http/modules/ngx_http_limit_conn_module.c
--- a/src/http/modules/ngx_http_limit_conn_module.c	Wed Sep 24 21:55:19 2014 +0400
+++ b/src/http/modules/ngx_http_limit_conn_module.c	Wed Sep 24 21:55:19 2014 +0400
@@ -25,9 +25,8 @@ typedef struct {
 
 
 typedef struct {
-    ngx_rbtree_t       *rbtree;
-    ngx_int_t           index;
-    ngx_str_t           var;
+    ngx_rbtree_t              *rbtree;
+    ngx_http_complex_value_t   key;
 } ngx_http_limit_conn_ctx_t;
 
 
@@ -45,7 +44,7 @@ typedef struct {
 
 
 static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
-    ngx_http_variable_value_t *vv, uint32_t hash);
+    ngx_str_t *key, uint32_t hash);
 static void ngx_http_limit_conn_cleanup(void *data);
 static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
 
@@ -141,13 +140,13 @@ ngx_module_t  ngx_http_limit_conn_module
 static ngx_int_t
 ngx_http_limit_conn_handler(ngx_http_request_t *r)
 {
-    size_t                          len, n;
+    size_t                          n;
     uint32_t                        hash;
+    ngx_str_t                       key;
     ngx_uint_t                      i;
     ngx_slab_pool_t                *shpool;
     ngx_rbtree_node_t              *node;
     ngx_pool_cleanup_t             *cln;
-    ngx_http_variable_value_t      *vv;
     ngx_http_limit_conn_ctx_t      *ctx;
     ngx_http_limit_conn_node_t     *lc;
     ngx_http_limit_conn_conf_t     *lccf;
@@ -164,41 +163,37 @@ ngx_http_limit_conn_handler(ngx_http_req
     for (i = 0; i < lccf->limits.nelts; i++) {
         ctx = limits[i].shm_zone->data;
 
-        vv = ngx_http_get_indexed_variable(r, ctx->index);
+        if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
 
-        if (vv == NULL || vv->not_found) {
+        if (key.len == 0) {
             continue;
         }
 
-        len = vv->len;
-
-        if (len == 0) {
-            continue;
-        }
-
-        if (len > 255) {
+        if (key.len > 255) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "the value of the \"%V\" variable "
-                          "is more than 255 bytes: \"%v\"",
-                          &ctx->var, vv);
+                          "the value of the \"%V\" key "
+                          "is more than 255 bytes: \"%V\"",
+                          &ctx->key.value, &key);
             continue;
         }
 
         r->main->limit_conn_set = 1;
 
-        hash = ngx_crc32_short(vv->data, len);
+        hash = ngx_crc32_short(key.data, key.len);
 
         shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
 
         ngx_shmtx_lock(&shpool->mutex);
 
-        node = ngx_http_limit_conn_lookup(ctx->rbtree, vv, hash);
+        node = ngx_http_limit_conn_lookup(ctx->rbtree, &key, hash);
 
         if (node == NULL) {
 
             n = offsetof(ngx_rbtree_node_t, color)
                 + offsetof(ngx_http_limit_conn_node_t, data)
-                + len;
+                + key.len;
 
             node = ngx_slab_alloc_locked(shpool, n);
 
@@ -211,9 +206,9 @@ ngx_http_limit_conn_handler(ngx_http_req
             lc = (ngx_http_limit_conn_node_t *) &node->color;
 
             node->key = hash;
-            lc->len = (u_char) len;
+            lc->len = (u_char) key.len;
             lc->conn = 1;
-            ngx_memcpy(lc->data, vv->data, len);
+            ngx_memcpy(lc->data, key.data, key.len);
 
             ngx_rbtree_insert(ctx->rbtree, node);
 
@@ -300,8 +295,7 @@ ngx_http_limit_conn_rbtree_insert_value(
 
 
 static ngx_rbtree_node_t *
-ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv,
-    uint32_t hash)
+ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash)
 {
     ngx_int_t                    rc;
     ngx_rbtree_node_t           *node, *sentinel;
@@ -326,8 +320,8 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t 
 
         lcn = (ngx_http_limit_conn_node_t *) &node->color;
 
-        rc = ngx_memn2cmp(vv->data, lcn->data,
-                          (size_t) vv->len, (size_t) lcn->len);
+        rc = ngx_memn2cmp(key->data, lcn->data, key->len, (size_t) lcn->len);
+
         if (rc == 0) {
             return node;
         }
@@ -399,11 +393,16 @@ ngx_http_limit_conn_init_zone(ngx_shm_zo
     ctx = shm_zone->data;
 
     if (octx) {
-        if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
+        if (ctx->key.value.len != octx->key.value.len
+            || ngx_strncmp(ctx->key.value.data, octx->key.value.data,
+                           ctx->key.value.len)
+               != 0)
+        {
             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
-                          "limit_conn_zone \"%V\" uses the \"%V\" variable "
-                          "while previously it used the \"%V\" variable",
-                          &shm_zone->shm.name, &ctx->var, &octx->var);
+                          "limit_conn_zone \"%V\" uses the \"%V\" key "
+                          "while previously it used the \"%V\" key",
+                          &shm_zone->shm.name, &ctx->key.value,
+                          &octx->key.value);
             return NGX_ERROR;
         }
 
@@ -493,20 +492,35 @@ ngx_http_limit_conn_merge_conf(ngx_conf_
 static char *
 ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    u_char                     *p;
-    ssize_t                     size;
-    ngx_str_t                  *value, name, s;
-    ngx_uint_t                  i;
-    ngx_shm_zone_t             *shm_zone;
-    ngx_http_limit_conn_ctx_t  *ctx;
+    u_char                            *p;
+    ssize_t                            size;
+    ngx_str_t                         *value, name, s;
+    ngx_uint_t                         i;
+    ngx_shm_zone_t                    *shm_zone;
+    ngx_http_limit_conn_ctx_t         *ctx;
+    ngx_http_compile_complex_value_t   ccv;
 
     value = cf->args->elts;
 
-    ctx = NULL;
+    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
+    if (ctx == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = &ctx->key;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
     size = 0;
     name.len = 0;
 
-    for (i = 1; i < cf->args->nelts; i++) {
+    for (i = 2; i < cf->args->nelts; i++) {
 
         if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
 
@@ -542,26 +556,6 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf,
             continue;
         }
 
-        if (value[i].data[0] == '$') {
-
-            value[i].len--;
-            value[i].data++;
-
-            ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
-            if (ctx == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            ctx->index = ngx_http_get_variable_index(cf, &value[i]);
-            if (ctx->index == NGX_ERROR) {
-                return NGX_CONF_ERROR;
-            }
-
-            ctx->var = value[i];
-
-            continue;
-        }
-
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                            "invalid parameter \"%V\"", &value[i]);
         return NGX_CONF_ERROR;
@@ -574,13 +568,6 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf,
         return NGX_CONF_ERROR;
     }
 
-    if (ctx == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "no variable is defined for %V \"%V\"",
-                           &cmd->name, &name);
-        return NGX_CONF_ERROR;
-    }
-
     shm_zone = ngx_shared_memory_add(cf, &name, size,
                                      &ngx_http_limit_conn_module);
     if (shm_zone == NULL) {
@@ -591,8 +578,8 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf,
         ctx = shm_zone->data;
 
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "%V \"%V\" is already bound to variable \"%V\"",
-                           &cmd->name, &name, &ctx->var);
+                           "%V \"%V\" is already bound to key \"%V\"",
+                           &cmd->name, &name, &ctx->key.value);
         return NGX_CONF_ERROR;
     }
 



More information about the nginx-devel mailing list