Mercurial > hg > nginx-vendor-current
comparison src/http/modules/ngx_http_limit_req_module.c @ 480:549994537f15 NGINX_0_7_52
nginx 0.7.52
*) Feature: the first native Windows binary release.
*) Bugfix: in processing HEAD method while caching.
*) Bugfix: in processing the "If-Modified-Since", "If-Range", etc.
client request header lines while caching.
*) Bugfix: now the "Set-Cookie" and "P3P" header lines are hidden in
cacheable responses.
*) Bugfix: if nginx was built with the ngx_http_perl_module and with a
perl which supports threads, then during a master process exit the
message "panic: MUTEX_LOCK" might be issued.
*) Bugfix: nginx could not be built --without-http-cache; the bug had
appeared in 0.7.48.
*) Bugfix: nginx could not be built on platforms different from i386,
amd64, sparc, and ppc; the bug had appeared in 0.7.42.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 20 Apr 2009 00:00:00 +0400 |
parents | 56baf312c1b5 |
children | f39b9e29530d |
comparison
equal
deleted
inserted
replaced
479:eb4fdebda673 | 480:549994537f15 |
---|---|
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_http.h> | 9 #include <ngx_http.h> |
10 | 10 |
11 | 11 |
12 typedef struct { | 12 typedef struct { |
13 u_char color; | 13 u_char color; |
14 u_char dummy; | 14 u_char dummy; |
15 u_short len; | 15 u_short len; |
16 ngx_queue_t queue; | 16 ngx_queue_t queue; |
17 ngx_msec_t last; | 17 ngx_msec_t last; |
18 ngx_uint_t excess; /* integer value, 1 corresponds to 0.001 r/s */ | 18 /* integer value, 1 corresponds to 0.001 r/s */ |
19 u_char data[1]; | 19 ngx_uint_t excess; |
20 u_char data[1]; | |
20 } ngx_http_limit_req_node_t; | 21 } ngx_http_limit_req_node_t; |
21 | 22 |
22 | 23 |
23 typedef struct { | 24 typedef struct { |
24 ngx_rbtree_t *rbtree; | 25 ngx_rbtree_t rbtree; |
25 ngx_queue_t *queue; | 26 ngx_rbtree_node_t sentinel; |
26 ngx_slab_pool_t *shpool; | 27 ngx_queue_t queue; |
27 ngx_uint_t rate; /* integer value, 1 corresponds to 0.001 r/s */ | 28 } ngx_http_limit_req_shctx_t; |
28 ngx_int_t index; | 29 |
29 ngx_str_t var; | 30 |
31 typedef struct { | |
32 ngx_http_limit_req_shctx_t *sh; | |
33 ngx_slab_pool_t *shpool; | |
34 /* integer value, 1 corresponds to 0.001 r/s */ | |
35 ngx_uint_t rate; | |
36 ngx_int_t index; | |
37 ngx_str_t var; | |
30 } ngx_http_limit_req_ctx_t; | 38 } ngx_http_limit_req_ctx_t; |
31 | 39 |
32 | 40 |
33 typedef struct { | 41 typedef struct { |
34 ngx_shm_zone_t *shm_zone; | 42 ngx_shm_zone_t *shm_zone; |
35 ngx_uint_t burst; /* integer value, 1 corresponds to 0.001 r/s */ | 43 /* integer value, 1 corresponds to 0.001 r/s */ |
36 ngx_uint_t nodelay;/* unsigned nodelay:1 */ | 44 ngx_uint_t burst; |
45 ngx_uint_t nodelay;/* unsigned nodelay:1 */ | |
37 } ngx_http_limit_req_conf_t; | 46 } ngx_http_limit_req_conf_t; |
38 | 47 |
39 | 48 |
40 static void ngx_http_limit_req_delay(ngx_http_request_t *r); | 49 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
41 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, | 50 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, |
161 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &lr); | 170 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &lr); |
162 | 171 |
163 if (lr) { | 172 if (lr) { |
164 ngx_queue_remove(&lr->queue); | 173 ngx_queue_remove(&lr->queue); |
165 | 174 |
166 ngx_queue_insert_head(ctx->queue, &lr->queue); | 175 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
167 | 176 |
168 excess = lr->excess; | 177 excess = lr->excess; |
169 | 178 |
170 } else { | 179 } else { |
171 excess = 0; | 180 excess = 0; |
177 if (rc == NGX_BUSY) { | 186 if (rc == NGX_BUSY) { |
178 ngx_shmtx_unlock(&ctx->shpool->mutex); | 187 ngx_shmtx_unlock(&ctx->shpool->mutex); |
179 | 188 |
180 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 189 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
181 "limiting requests, excess: %ui.%03ui by zone \"%V\"", | 190 "limiting requests, excess: %ui.%03ui by zone \"%V\"", |
182 excess / 1000, excess % 1000, &lrcf->shm_zone->name); | 191 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
183 | 192 |
184 return NGX_HTTP_SERVICE_UNAVAILABLE; | 193 return NGX_HTTP_SERVICE_UNAVAILABLE; |
185 } | 194 } |
186 | 195 |
187 if (rc == NGX_AGAIN) { | 196 if (rc == NGX_AGAIN) { |
191 return NGX_DECLINED; | 200 return NGX_DECLINED; |
192 } | 201 } |
193 | 202 |
194 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, | 203 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, |
195 "delaying request, excess: %ui.%03ui, by zone \"%V\"", | 204 "delaying request, excess: %ui.%03ui, by zone \"%V\"", |
196 excess / 1000, excess % 1000, &lrcf->shm_zone->name); | 205 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
197 | 206 |
198 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { | 207 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
199 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 208 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
200 } | 209 } |
201 | 210 |
237 lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | 246 lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
238 | 247 |
239 lr->excess = 0; | 248 lr->excess = 0; |
240 ngx_memcpy(lr->data, vv->data, len); | 249 ngx_memcpy(lr->data, vv->data, len); |
241 | 250 |
242 ngx_rbtree_insert(ctx->rbtree, node); | 251 ngx_rbtree_insert(&ctx->sh->rbtree, node); |
243 | 252 |
244 ngx_queue_insert_head(ctx->queue, &lr->queue); | 253 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
245 | 254 |
246 done: | 255 done: |
247 | 256 |
248 ngx_shmtx_unlock(&ctx->shpool->mutex); | 257 ngx_shmtx_unlock(&ctx->shpool->mutex); |
249 | 258 |
322 ngx_http_limit_req_ctx_t *ctx; | 331 ngx_http_limit_req_ctx_t *ctx; |
323 ngx_http_limit_req_node_t *lr; | 332 ngx_http_limit_req_node_t *lr; |
324 | 333 |
325 ctx = lrcf->shm_zone->data; | 334 ctx = lrcf->shm_zone->data; |
326 | 335 |
327 node = ctx->rbtree->root; | 336 node = ctx->sh->rbtree.root; |
328 sentinel = ctx->rbtree->sentinel; | 337 sentinel = ctx->sh->rbtree.sentinel; |
329 | 338 |
330 while (node != sentinel) { | 339 while (node != sentinel) { |
331 | 340 |
332 if (hash < node->key) { | 341 if (hash < node->key) { |
333 node = node->left; | 342 node = node->left; |
409 * and one or two zero rate entries | 418 * and one or two zero rate entries |
410 */ | 419 */ |
411 | 420 |
412 while (n < 3) { | 421 while (n < 3) { |
413 | 422 |
414 if (ngx_queue_empty(ctx->queue)) { | 423 if (ngx_queue_empty(&ctx->sh->queue)) { |
415 return; | 424 return; |
416 } | 425 } |
417 | 426 |
418 q = ngx_queue_last(ctx->queue); | 427 q = ngx_queue_last(&ctx->sh->queue); |
419 | 428 |
420 lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue); | 429 lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue); |
421 | 430 |
422 if (n++ != 0) { | 431 if (n++ != 0) { |
423 | 432 |
438 ngx_queue_remove(q); | 447 ngx_queue_remove(q); |
439 | 448 |
440 node = (ngx_rbtree_node_t *) | 449 node = (ngx_rbtree_node_t *) |
441 ((u_char *) lr - offsetof(ngx_rbtree_node_t, color)); | 450 ((u_char *) lr - offsetof(ngx_rbtree_node_t, color)); |
442 | 451 |
443 ngx_rbtree_delete(ctx->rbtree, node); | 452 ngx_rbtree_delete(&ctx->sh->rbtree, node); |
444 | 453 |
445 ngx_slab_free_locked(ctx->shpool, node); | 454 ngx_slab_free_locked(ctx->shpool, node); |
446 } | 455 } |
447 } | 456 } |
448 | 457 |
451 ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data) | 460 ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data) |
452 { | 461 { |
453 ngx_http_limit_req_ctx_t *octx = data; | 462 ngx_http_limit_req_ctx_t *octx = data; |
454 | 463 |
455 size_t len; | 464 size_t len; |
456 ngx_rbtree_node_t *sentinel; | |
457 ngx_http_limit_req_ctx_t *ctx; | 465 ngx_http_limit_req_ctx_t *ctx; |
458 | 466 |
459 ctx = shm_zone->data; | 467 ctx = shm_zone->data; |
460 | 468 |
461 if (octx) { | 469 if (octx) { |
462 if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { | 470 if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { |
463 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, | 471 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, |
464 "limit_req \"%V\" uses the \"%V\" variable " | 472 "limit_req \"%V\" uses the \"%V\" variable " |
465 "while previously it used the \"%V\" variable", | 473 "while previously it used the \"%V\" variable", |
466 &shm_zone->name, &ctx->var, &octx->var); | 474 &shm_zone->shm.name, &ctx->var, &octx->var); |
467 return NGX_ERROR; | 475 return NGX_ERROR; |
468 } | 476 } |
469 | 477 |
470 ctx->rbtree = octx->rbtree; | 478 ctx->sh = octx->sh; |
471 ctx->queue = octx->queue; | |
472 ctx->shpool = octx->shpool; | 479 ctx->shpool = octx->shpool; |
473 | 480 |
474 return NGX_OK; | 481 return NGX_OK; |
475 } | 482 } |
476 | 483 |
477 ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | 484 ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
478 | 485 |
479 ctx->rbtree = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_t)); | 486 if (shm_zone->shm.exists) { |
480 if (ctx->rbtree == NULL) { | 487 ctx->sh = ctx->shpool->data; |
488 | |
489 return NGX_OK; | |
490 } | |
491 | |
492 ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_shctx_t)); | |
493 if (ctx->sh == NULL) { | |
481 return NGX_ERROR; | 494 return NGX_ERROR; |
482 } | 495 } |
483 | 496 |
484 sentinel = ngx_slab_alloc(ctx->shpool, sizeof(ngx_rbtree_node_t)); | 497 ctx->shpool->data = ctx->sh; |
485 if (sentinel == NULL) { | 498 |
486 return NGX_ERROR; | 499 ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, |
487 } | |
488 | |
489 ngx_rbtree_init(ctx->rbtree, sentinel, | |
490 ngx_http_limit_req_rbtree_insert_value); | 500 ngx_http_limit_req_rbtree_insert_value); |
491 | 501 |
492 ctx->queue = ngx_slab_alloc(ctx->shpool, sizeof(ngx_queue_t)); | 502 ngx_queue_init(&ctx->sh->queue); |
493 if (ctx->queue == NULL) { | 503 |
494 return NGX_ERROR; | 504 len = sizeof(" in limit_req zone \"\"") + shm_zone->shm.name.len; |
495 } | |
496 | |
497 ngx_queue_init(ctx->queue); | |
498 | |
499 len = sizeof(" in limit_req zone \"\"") + shm_zone->name.len; | |
500 | 505 |
501 ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); | 506 ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); |
502 if (ctx->shpool->log_ctx == NULL) { | 507 if (ctx->shpool->log_ctx == NULL) { |
503 return NGX_ERROR; | 508 return NGX_ERROR; |
504 } | 509 } |
505 | 510 |
506 ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z", | 511 ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z", |
507 &shm_zone->name); | 512 &shm_zone->shm.name); |
508 | 513 |
509 return NGX_OK; | 514 return NGX_OK; |
510 } | 515 } |
511 | 516 |
512 | 517 |
572 name.data = value[i].data + 5; | 577 name.data = value[i].data + 5; |
573 | 578 |
574 p = (u_char *) ngx_strchr(name.data, ':'); | 579 p = (u_char *) ngx_strchr(name.data, ':'); |
575 | 580 |
576 if (p) { | 581 if (p) { |
582 *p = '\0'; | |
583 | |
577 name.len = p - name.data; | 584 name.len = p - name.data; |
578 | 585 |
579 p++; | 586 p++; |
580 | 587 |
581 s.len = value[i].data + value[i].len - p; | 588 s.len = value[i].data + value[i].len - p; |
742 } | 749 } |
743 | 750 |
744 if (lrcf->shm_zone->data == NULL) { | 751 if (lrcf->shm_zone->data == NULL) { |
745 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 752 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
746 "unknown limit_req_zone \"%V\"", | 753 "unknown limit_req_zone \"%V\"", |
747 &lrcf->shm_zone->name); | 754 &lrcf->shm_zone->shm.name); |
748 return NGX_CONF_ERROR; | 755 return NGX_CONF_ERROR; |
749 } | 756 } |
750 | 757 |
751 lrcf->burst = burst * 1000; | 758 lrcf->burst = burst * 1000; |
752 | 759 |