diff src/http/modules/ngx_http_limit_zone_module.c @ 274:052a7b1d40e5 NGINX_0_5_7

nginx 0.5.7 *) Feature: the ssl_session_cache storage optimization. *) Bugfixes in the "ssl_session_cache" and "limit_zone" directives. *) Bugfix: the segmentation fault was occurred on start or while reconfiguration if the "ssl_session_cache" or "limit_zone" directives were used on 64-bit platforms. *) Bugfix: a segmentation fault occurred if the "add_before_body" or "add_after_body" directives were used and there was no "Content-Type" header line in response. *) Bugfix: the OpenSSL library was always built with the threads support. Thanks to Den Ivanov. *) Bugfix: the PCRE-6.5+ library and the icc compiler compatibility.
author Igor Sysoev <http://sysoev.ru>
date Mon, 15 Jan 2007 00:00:00 +0300
parents 29a6403156b0
children c5c2b2883984
line wrap: on
line diff
--- a/src/http/modules/ngx_http_limit_zone_module.c
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -104,6 +104,7 @@ ngx_http_limit_zone_handler(ngx_http_req
 {
     size_t                          len, n;
     uint32_t                        hash;
+    ngx_int_t                       rc;
     ngx_slab_pool_t                *shpool;
     ngx_rbtree_node_t              *node, *sentinel;
     ngx_pool_cleanup_t             *cln;
@@ -131,9 +132,21 @@ ngx_http_limit_zone_handler(ngx_http_req
         return NGX_DECLINED;
     }
 
-    r->limit_zone_set = 1;
+    len = vv->len;
+
+    if (len == 0) {
+        return NGX_DECLINED;
+    }
 
-    len = vv->len;
+    if (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);
+        return NGX_DECLINED;
+    }
+
+    r->main->limit_zone_set = 1;
 
     hash = ngx_crc32_short(vv->data, len);
 
@@ -161,12 +174,14 @@ ngx_http_limit_zone_handler(ngx_http_req
             continue;
         }
 
-        if (hash == node->key ){
+        /* hash == node->key */
+
+        do {
             lz = (ngx_http_limit_zone_node_t *) &node->color;
 
-            if (len == (size_t) lz->len
-                && ngx_strncmp(lz->data, vv->data, len) == 0)
-            {
+            rc = ngx_memn2cmp(lz->data, vv->data, (size_t) lz->len, len);
+
+            if (rc == 0) {
                 if ((ngx_uint_t) lz->conn < lzcf->conn) {
                     lz->conn++;
                     goto done;
@@ -176,7 +191,12 @@ ngx_http_limit_zone_handler(ngx_http_req
 
                 return NGX_HTTP_SERVICE_UNAVAILABLE;
             }
-        }
+
+            node = (rc < 0) ? node->left : node->right;
+
+        } while (node != sentinel && hash == node->key);
+
+        break;
     }
 
     n = offsetof(ngx_rbtree_node_t, color)
@@ -216,6 +236,65 @@ done:
 
 
 static void
+ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp,
+    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+    ngx_http_limit_zone_node_t  *lzn, *lznt;
+
+    for ( ;; ) {
+
+        if (node->key < temp->key) {
+
+            if (temp->left == sentinel) {
+                temp->left = node;
+                break;
+            }
+
+            temp = temp->left;
+
+        } else if (node->key > temp->key) {
+
+            if (temp->right == sentinel) {
+                temp->right = node;
+                break;
+            }
+
+            temp = temp->right;
+
+        } else { /* node->key == temp->key */
+
+            lzn = (ngx_http_limit_zone_node_t *) &node->color;
+            lznt = (ngx_http_limit_zone_node_t *) &temp->color;
+
+            if (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) {
+
+                if (temp->left == sentinel) {
+                    temp->left = node;
+                    break;
+                }
+
+                temp = temp->left;
+
+            } else {
+
+                if (temp->right == sentinel) {
+                    temp->right = node;
+                    break;
+                }
+
+                temp = temp->right;
+            }
+        }
+    }
+
+    node->parent = temp;
+    node->left = sentinel;
+    node->right = sentinel;
+    ngx_rbt_red(node);
+}
+
+
+static void
 ngx_http_limit_zone_cleanup(void *data)
 {
     ngx_http_limit_zone_cleanup_t  *lzcln = data;
@@ -260,7 +339,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo
     if (octx) {
         if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
-                          "limit_zone \"%V\" use the \"%V\" variable "
+                          "limit_zone \"%V\" uses the \"%V\" variable "
                           "while previously it used the \"%V\" variable",
                           &shm_zone->name, &ctx->var, &octx->var);
             return NGX_ERROR;
@@ -287,7 +366,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo
 
     ctx->rbtree->root = sentinel;
     ctx->rbtree->sentinel = sentinel;
-    ctx->rbtree->insert = ngx_rbtree_insert_value;
+    ctx->rbtree->insert = ngx_http_limit_zone_rbtree_insert_value;
 
     return NGX_OK;
 }
@@ -419,6 +498,12 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_
         return NGX_CONF_ERROR;
     }
 
+    if (n > 65535) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "connection limit must be less 65536");
+        return NGX_CONF_ERROR;
+    }
+
     lzcf->conn = n;
 
     return NGX_CONF_OK;