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