]> git.kaiwu.me - nginx.git/commitdiff
Limit req: use complex value in limit_req_zone.
authorValentin Bartenev <vbart@nginx.com>
Wed, 24 Sep 2014 17:55:19 +0000 (21:55 +0400)
committerValentin Bartenev <vbart@nginx.com>
Wed, 24 Sep 2014 17:55:19 +0000 (21:55 +0400)
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
with nginx configuration practice for positional parameters.

src/http/modules/ngx_http_limit_req_module.c

index 27d7b3092ec46c63639cf3c3c2a03f0f21468e27..746e96957074ca07e38407f5d92263603ff115d5 100644 (file)
@@ -35,8 +35,7 @@ typedef struct {
     ngx_slab_pool_t             *shpool;
     /* integer value, 1 corresponds to 0.001 r/s */
     ngx_uint_t                   rate;
-    ngx_int_t                    index;
-    ngx_str_t                    var;
+    ngx_http_complex_value_t     key;
     ngx_http_limit_req_node_t   *node;
 } ngx_http_limit_req_ctx_t;
 
@@ -158,12 +157,11 @@ ngx_module_t  ngx_http_limit_req_module = {
 static ngx_int_t
 ngx_http_limit_req_handler(ngx_http_request_t *r)
 {
-    size_t                       len;
     uint32_t                     hash;
+    ngx_str_t                    key;
     ngx_int_t                    rc;
     ngx_uint_t                   n, excess;
     ngx_msec_t                   delay;
-    ngx_http_variable_value_t   *vv;
     ngx_http_limit_req_ctx_t    *ctx;
     ngx_http_limit_req_conf_t   *lrcf;
     ngx_http_limit_req_limit_t  *limit, *limits;
@@ -189,31 +187,27 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
 
         ctx = limit->shm_zone->data;
 
-        vv = ngx_http_get_indexed_variable(r, ctx->index);
-
-        if (vv == NULL || vv->not_found) {
-            continue;
+        if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        len = vv->len;
-
-        if (len == 0) {
+        if (key.len == 0) {
             continue;
         }
 
-        if (len > 65535) {
+        if (key.len > 65535) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "the value of the \"%V\" variable "
-                          "is more than 65535 bytes: \"%v\"",
-                          &ctx->var, vv);
+                          "the value of the \"%V\" key "
+                          "is more than 65535 bytes: \"%V\"",
+                          &ctx->key.value, &key);
             continue;
         }
 
-        hash = ngx_crc32_short(vv->data, len);
+        hash = ngx_crc32_short(key.data, key.len);
 
         ngx_shmtx_lock(&ctx->shpool->mutex);
 
-        rc = ngx_http_limit_req_lookup(limit, hash, vv->data, len, &excess,
+        rc = ngx_http_limit_req_lookup(limit, hash, key.data, key.len, &excess,
                                        (n == lrcf->limits.nelts - 1));
 
         ngx_shmtx_unlock(&ctx->shpool->mutex);
@@ -632,11 +626,16 @@ ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data)
     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_req \"%V\" uses the \"%V\" variable "
-                          "while previously it used the \"%V\" variable",
-                          &shm_zone->shm.name, &ctx->var, &octx->var);
+                          "limit_req \"%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;
         }
 
@@ -731,24 +730,39 @@ ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child)
 static char *
 ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    u_char                    *p;
-    size_t                     len;
-    ssize_t                    size;
-    ngx_str_t                 *value, name, s;
-    ngx_int_t                  rate, scale;
-    ngx_uint_t                 i;
-    ngx_shm_zone_t            *shm_zone;
-    ngx_http_limit_req_ctx_t  *ctx;
+    u_char                            *p;
+    size_t                             len;
+    ssize_t                            size;
+    ngx_str_t                         *value, name, s;
+    ngx_int_t                          rate, scale;
+    ngx_uint_t                         i;
+    ngx_shm_zone_t                    *shm_zone;
+    ngx_http_limit_req_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_req_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;
     rate = 1;
     scale = 1;
     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) {
 
@@ -808,26 +822,6 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
             continue;
         }
 
-        if (value[i].data[0] == '$') {
-
-            value[i].len--;
-            value[i].data++;
-
-            ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_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;
@@ -840,13 +834,6 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         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;
-    }
-
     ctx->rate = rate * 1000 / scale;
 
     shm_zone = ngx_shared_memory_add(cf, &name, size,
@@ -859,8 +846,8 @@ ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         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;
     }