mirror of
https://github.com/nginx/nginx.git
synced 2024-12-02 20:09:01 +08:00
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.
This commit is contained in:
parent
1866f15d7d
commit
dd1ae4348a
@ -26,8 +26,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ngx_rbtree_t *rbtree;
|
ngx_rbtree_t *rbtree;
|
||||||
ngx_int_t index;
|
ngx_http_complex_value_t key;
|
||||||
ngx_str_t var;
|
|
||||||
} ngx_http_limit_conn_ctx_t;
|
} 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,
|
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 void ngx_http_limit_conn_cleanup(void *data);
|
||||||
static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
|
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
|
static ngx_int_t
|
||||||
ngx_http_limit_conn_handler(ngx_http_request_t *r)
|
ngx_http_limit_conn_handler(ngx_http_request_t *r)
|
||||||
{
|
{
|
||||||
size_t len, n;
|
size_t n;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
ngx_str_t key;
|
||||||
ngx_uint_t i;
|
ngx_uint_t i;
|
||||||
ngx_slab_pool_t *shpool;
|
ngx_slab_pool_t *shpool;
|
||||||
ngx_rbtree_node_t *node;
|
ngx_rbtree_node_t *node;
|
||||||
ngx_pool_cleanup_t *cln;
|
ngx_pool_cleanup_t *cln;
|
||||||
ngx_http_variable_value_t *vv;
|
|
||||||
ngx_http_limit_conn_ctx_t *ctx;
|
ngx_http_limit_conn_ctx_t *ctx;
|
||||||
ngx_http_limit_conn_node_t *lc;
|
ngx_http_limit_conn_node_t *lc;
|
||||||
ngx_http_limit_conn_conf_t *lccf;
|
ngx_http_limit_conn_conf_t *lccf;
|
||||||
@ -164,41 +163,37 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
|
|||||||
for (i = 0; i < lccf->limits.nelts; i++) {
|
for (i = 0; i < lccf->limits.nelts; i++) {
|
||||||
ctx = limits[i].shm_zone->data;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = vv->len;
|
if (key.len > 255) {
|
||||||
|
|
||||||
if (len == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len > 255) {
|
|
||||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||||
"the value of the \"%V\" variable "
|
"the value of the \"%V\" key "
|
||||||
"is more than 255 bytes: \"%v\"",
|
"is more than 255 bytes: \"%V\"",
|
||||||
&ctx->var, vv);
|
&ctx->key.value, &key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->main->limit_conn_set = 1;
|
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;
|
shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
|
||||||
|
|
||||||
ngx_shmtx_lock(&shpool->mutex);
|
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) {
|
if (node == NULL) {
|
||||||
|
|
||||||
n = offsetof(ngx_rbtree_node_t, color)
|
n = offsetof(ngx_rbtree_node_t, color)
|
||||||
+ offsetof(ngx_http_limit_conn_node_t, data)
|
+ offsetof(ngx_http_limit_conn_node_t, data)
|
||||||
+ len;
|
+ key.len;
|
||||||
|
|
||||||
node = ngx_slab_alloc_locked(shpool, n);
|
node = ngx_slab_alloc_locked(shpool, n);
|
||||||
|
|
||||||
@ -211,9 +206,9 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
|
|||||||
lc = (ngx_http_limit_conn_node_t *) &node->color;
|
lc = (ngx_http_limit_conn_node_t *) &node->color;
|
||||||
|
|
||||||
node->key = hash;
|
node->key = hash;
|
||||||
lc->len = (u_char) len;
|
lc->len = (u_char) key.len;
|
||||||
lc->conn = 1;
|
lc->conn = 1;
|
||||||
ngx_memcpy(lc->data, vv->data, len);
|
ngx_memcpy(lc->data, key.data, key.len);
|
||||||
|
|
||||||
ngx_rbtree_insert(ctx->rbtree, node);
|
ngx_rbtree_insert(ctx->rbtree, node);
|
||||||
|
|
||||||
@ -300,8 +295,7 @@ ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp,
|
|||||||
|
|
||||||
|
|
||||||
static ngx_rbtree_node_t *
|
static ngx_rbtree_node_t *
|
||||||
ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv,
|
ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash)
|
||||||
uint32_t hash)
|
|
||||||
{
|
{
|
||||||
ngx_int_t rc;
|
ngx_int_t rc;
|
||||||
ngx_rbtree_node_t *node, *sentinel;
|
ngx_rbtree_node_t *node, *sentinel;
|
||||||
@ -326,8 +320,8 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv,
|
|||||||
|
|
||||||
lcn = (ngx_http_limit_conn_node_t *) &node->color;
|
lcn = (ngx_http_limit_conn_node_t *) &node->color;
|
||||||
|
|
||||||
rc = ngx_memn2cmp(vv->data, lcn->data,
|
rc = ngx_memn2cmp(key->data, lcn->data, key->len, (size_t) lcn->len);
|
||||||
(size_t) vv->len, (size_t) lcn->len);
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -399,11 +393,16 @@ ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
|
|||||||
ctx = shm_zone->data;
|
ctx = shm_zone->data;
|
||||||
|
|
||||||
if (octx) {
|
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,
|
ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
|
||||||
"limit_conn_zone \"%V\" uses the \"%V\" variable "
|
"limit_conn_zone \"%V\" uses the \"%V\" key "
|
||||||
"while previously it used the \"%V\" variable",
|
"while previously it used the \"%V\" key",
|
||||||
&shm_zone->shm.name, &ctx->var, &octx->var);
|
&shm_zone->shm.name, &ctx->key.value,
|
||||||
|
&octx->key.value);
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,14 +498,29 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||||||
ngx_uint_t i;
|
ngx_uint_t i;
|
||||||
ngx_shm_zone_t *shm_zone;
|
ngx_shm_zone_t *shm_zone;
|
||||||
ngx_http_limit_conn_ctx_t *ctx;
|
ngx_http_limit_conn_ctx_t *ctx;
|
||||||
|
ngx_http_compile_complex_value_t ccv;
|
||||||
|
|
||||||
value = cf->args->elts;
|
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;
|
size = 0;
|
||||||
name.len = 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) {
|
if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
|
||||||
|
|
||||||
@ -542,26 +556,6 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||||||
continue;
|
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,
|
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||||
"invalid parameter \"%V\"", &value[i]);
|
"invalid parameter \"%V\"", &value[i]);
|
||||||
return NGX_CONF_ERROR;
|
return NGX_CONF_ERROR;
|
||||||
@ -574,13 +568,6 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||||||
return NGX_CONF_ERROR;
|
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,
|
shm_zone = ngx_shared_memory_add(cf, &name, size,
|
||||||
&ngx_http_limit_conn_module);
|
&ngx_http_limit_conn_module);
|
||||||
if (shm_zone == NULL) {
|
if (shm_zone == NULL) {
|
||||||
@ -591,8 +578,8 @@ ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
|||||||
ctx = shm_zone->data;
|
ctx = shm_zone->data;
|
||||||
|
|
||||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||||
"%V \"%V\" is already bound to variable \"%V\"",
|
"%V \"%V\" is already bound to key \"%V\"",
|
||||||
&cmd->name, &name, &ctx->var);
|
&cmd->name, &name, &ctx->key.value);
|
||||||
return NGX_CONF_ERROR;
|
return NGX_CONF_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user