Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_limit_req_module.c @ 4420:9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Mon, 30 Jan 2012 10:17:56 +0000 |
parents | 7084faa7a4b4 |
children | aacd7356c197 |
comparison
equal
deleted
inserted
replaced
4419:7084faa7a4b4 | 4420:9ce48f9eb85b |
---|---|
16 u_short len; | 16 u_short len; |
17 ngx_queue_t queue; | 17 ngx_queue_t queue; |
18 ngx_msec_t last; | 18 ngx_msec_t last; |
19 /* integer value, 1 corresponds to 0.001 r/s */ | 19 /* integer value, 1 corresponds to 0.001 r/s */ |
20 ngx_uint_t excess; | 20 ngx_uint_t excess; |
21 ngx_uint_t count; | |
21 u_char data[1]; | 22 u_char data[1]; |
22 } ngx_http_limit_req_node_t; | 23 } ngx_http_limit_req_node_t; |
23 | 24 |
24 | 25 |
25 typedef struct { | 26 typedef struct { |
34 ngx_slab_pool_t *shpool; | 35 ngx_slab_pool_t *shpool; |
35 /* integer value, 1 corresponds to 0.001 r/s */ | 36 /* integer value, 1 corresponds to 0.001 r/s */ |
36 ngx_uint_t rate; | 37 ngx_uint_t rate; |
37 ngx_int_t index; | 38 ngx_int_t index; |
38 ngx_str_t var; | 39 ngx_str_t var; |
40 ngx_http_limit_req_node_t *node; | |
39 } ngx_http_limit_req_ctx_t; | 41 } ngx_http_limit_req_ctx_t; |
40 | 42 |
41 | 43 |
42 typedef struct { | 44 typedef struct { |
43 ngx_shm_zone_t *shm_zone; | 45 ngx_shm_zone_t *shm_zone; |
44 /* integer value, 1 corresponds to 0.001 r/s */ | 46 /* integer value, 1 corresponds to 0.001 r/s */ |
45 ngx_uint_t burst; | 47 ngx_uint_t burst; |
48 ngx_uint_t nodelay; /* unsigned nodelay:1 */ | |
49 } ngx_http_limit_req_limit_t; | |
50 | |
51 | |
52 typedef struct { | |
53 ngx_array_t limits; | |
46 ngx_uint_t limit_log_level; | 54 ngx_uint_t limit_log_level; |
47 ngx_uint_t delay_log_level; | 55 ngx_uint_t delay_log_level; |
48 | |
49 ngx_uint_t nodelay; /* unsigned nodelay:1 */ | |
50 } ngx_http_limit_req_conf_t; | 56 } ngx_http_limit_req_conf_t; |
51 | 57 |
52 | 58 |
53 static void ngx_http_limit_req_delay(ngx_http_request_t *r); | 59 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
54 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, | 60 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, |
55 ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep); | 61 ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep, |
62 ngx_uint_t account); | |
63 static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, | |
64 ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit); | |
56 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, | 65 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, |
57 ngx_uint_t n); | 66 ngx_uint_t n); |
58 | 67 |
59 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); | 68 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); |
60 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, | 69 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, |
134 | 143 |
135 | 144 |
136 static ngx_int_t | 145 static ngx_int_t |
137 ngx_http_limit_req_handler(ngx_http_request_t *r) | 146 ngx_http_limit_req_handler(ngx_http_request_t *r) |
138 { | 147 { |
139 size_t len; | 148 size_t len; |
140 uint32_t hash; | 149 uint32_t hash; |
141 ngx_int_t rc; | 150 ngx_int_t rc; |
142 ngx_uint_t excess; | 151 ngx_uint_t n, excess; |
143 ngx_http_variable_value_t *vv; | 152 ngx_msec_t delay; |
144 ngx_http_limit_req_ctx_t *ctx; | 153 ngx_http_variable_value_t *vv; |
145 ngx_http_limit_req_conf_t *lrcf; | 154 ngx_http_limit_req_ctx_t *ctx; |
155 ngx_http_limit_req_conf_t *lrcf; | |
156 ngx_http_limit_req_limit_t *limit, *limits; | |
146 | 157 |
147 if (r->main->limit_req_set) { | 158 if (r->main->limit_req_set) { |
148 return NGX_DECLINED; | 159 return NGX_DECLINED; |
149 } | 160 } |
150 | 161 |
151 lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); | 162 lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); |
152 | 163 limits = lrcf->limits.elts; |
153 if (lrcf->shm_zone == NULL) { | 164 |
165 excess = 0; | |
166 | |
167 rc = NGX_DECLINED; | |
168 | |
169 for (n = 0; n < lrcf->limits.nelts; n++) { | |
170 | |
171 limit = &limits[n]; | |
172 | |
173 ctx = limit->shm_zone->data; | |
174 | |
175 vv = ngx_http_get_indexed_variable(r, ctx->index); | |
176 | |
177 if (vv == NULL || vv->not_found) { | |
178 continue; | |
179 } | |
180 | |
181 len = vv->len; | |
182 | |
183 if (len == 0) { | |
184 continue; | |
185 } | |
186 | |
187 if (len > 65535) { | |
188 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
189 "the value of the \"%V\" variable " | |
190 "is more than 65535 bytes: \"%v\"", | |
191 &ctx->var, vv); | |
192 continue; | |
193 } | |
194 | |
195 hash = ngx_crc32_short(vv->data, len); | |
196 | |
197 ngx_shmtx_lock(&ctx->shpool->mutex); | |
198 | |
199 rc = ngx_http_limit_req_lookup(limit, hash, vv->data, len, &excess, | |
200 (n == lrcf->limits.nelts - 1)); | |
201 | |
202 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
203 | |
204 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
205 "limit_req[%ui]: %i %ui.%03ui", | |
206 n, rc, excess / 1000, excess % 1000); | |
207 | |
208 if (rc != NGX_AGAIN) { | |
209 break; | |
210 } | |
211 } | |
212 | |
213 if (rc == NGX_DECLINED) { | |
154 return NGX_DECLINED; | 214 return NGX_DECLINED; |
155 } | 215 } |
156 | 216 |
157 ctx = lrcf->shm_zone->data; | |
158 | |
159 vv = ngx_http_get_indexed_variable(r, ctx->index); | |
160 | |
161 if (vv == NULL || vv->not_found) { | |
162 return NGX_DECLINED; | |
163 } | |
164 | |
165 len = vv->len; | |
166 | |
167 if (len == 0) { | |
168 return NGX_DECLINED; | |
169 } | |
170 | |
171 if (len > 65535) { | |
172 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
173 "the value of the \"%V\" variable " | |
174 "is more than 65535 bytes: \"%v\"", | |
175 &ctx->var, vv); | |
176 return NGX_DECLINED; | |
177 } | |
178 | |
179 r->main->limit_req_set = 1; | 217 r->main->limit_req_set = 1; |
180 | |
181 hash = ngx_crc32_short(vv->data, len); | |
182 | |
183 ngx_shmtx_lock(&ctx->shpool->mutex); | |
184 | |
185 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &excess); | |
186 | |
187 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
188 | |
189 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
190 "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); | |
191 | |
192 if (rc == NGX_OK) { | |
193 return NGX_DECLINED; | |
194 } | |
195 | 218 |
196 if (rc == NGX_BUSY || rc == NGX_ERROR) { | 219 if (rc == NGX_BUSY || rc == NGX_ERROR) { |
197 | 220 |
198 if (rc == NGX_BUSY) { | 221 if (rc == NGX_BUSY) { |
199 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, | 222 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, |
200 "limiting requests, excess: %ui.%03ui by zone \"%V\"", | 223 "limiting requests, excess: %ui.%03ui by zone \"%V\"", |
201 excess / 1000, excess % 1000, | 224 excess / 1000, excess % 1000, |
202 &lrcf->shm_zone->shm.name); | 225 &limit->shm_zone->shm.name); |
226 } | |
227 | |
228 while (n--) { | |
229 ctx = limits[n].shm_zone->data; | |
230 | |
231 if (ctx->node == NULL) { | |
232 continue; | |
233 } | |
234 | |
235 ngx_shmtx_lock(&ctx->shpool->mutex); | |
236 | |
237 ctx->node->count--; | |
238 | |
239 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
240 | |
241 ctx->node = NULL; | |
203 } | 242 } |
204 | 243 |
205 return NGX_HTTP_SERVICE_UNAVAILABLE; | 244 return NGX_HTTP_SERVICE_UNAVAILABLE; |
206 } | 245 } |
207 | 246 |
208 /* rc == NGX_AGAIN */ | 247 /* rc == NGX_AGAIN || rc == NGX_OK */ |
209 | 248 |
210 if (lrcf->nodelay) { | 249 if (rc == NGX_AGAIN) { |
250 excess = 0; | |
251 } | |
252 | |
253 delay = ngx_http_limit_req_account(limits, n, &excess, &limit); | |
254 | |
255 if (!delay) { | |
211 return NGX_DECLINED; | 256 return NGX_DECLINED; |
212 } | 257 } |
213 | 258 |
214 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, | 259 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, |
215 "delaying request, excess: %ui.%03ui, by zone \"%V\"", | 260 "delaying request, excess: %ui.%03ui, by zone \"%V\"", |
216 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); | 261 excess / 1000, excess % 1000, &limit->shm_zone->shm.name); |
217 | 262 |
218 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { | 263 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
219 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 264 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
220 } | 265 } |
221 | 266 |
222 r->read_event_handler = ngx_http_test_reading; | 267 r->read_event_handler = ngx_http_test_reading; |
223 r->write_event_handler = ngx_http_limit_req_delay; | 268 r->write_event_handler = ngx_http_limit_req_delay; |
224 ngx_add_timer(r->connection->write, | 269 ngx_add_timer(r->connection->write, delay); |
225 (ngx_msec_t) excess * 1000 / ctx->rate); | |
226 | 270 |
227 return NGX_AGAIN; | 271 return NGX_AGAIN; |
228 } | 272 } |
229 | 273 |
230 | 274 |
301 ngx_rbt_red(node); | 345 ngx_rbt_red(node); |
302 } | 346 } |
303 | 347 |
304 | 348 |
305 static ngx_int_t | 349 static ngx_int_t |
306 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash, | 350 ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, |
307 u_char *data, size_t len, ngx_uint_t *ep) | 351 u_char *data, size_t len, ngx_uint_t *ep, ngx_uint_t account) |
308 { | 352 { |
309 size_t size; | 353 size_t size; |
310 ngx_int_t rc, excess; | 354 ngx_int_t rc, excess; |
311 ngx_time_t *tp; | 355 ngx_time_t *tp; |
312 ngx_msec_t now; | 356 ngx_msec_t now; |
316 ngx_http_limit_req_node_t *lr; | 360 ngx_http_limit_req_node_t *lr; |
317 | 361 |
318 tp = ngx_timeofday(); | 362 tp = ngx_timeofday(); |
319 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | 363 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
320 | 364 |
321 ctx = lrcf->shm_zone->data; | 365 ctx = limit->shm_zone->data; |
322 | 366 |
323 node = ctx->sh->rbtree.root; | 367 node = ctx->sh->rbtree.root; |
324 sentinel = ctx->sh->rbtree.sentinel; | 368 sentinel = ctx->sh->rbtree.sentinel; |
325 | 369 |
326 while (node != sentinel) { | 370 while (node != sentinel) { |
354 excess = 0; | 398 excess = 0; |
355 } | 399 } |
356 | 400 |
357 *ep = excess; | 401 *ep = excess; |
358 | 402 |
359 if ((ngx_uint_t) excess > lrcf->burst) { | 403 if ((ngx_uint_t) excess > limit->burst) { |
360 return NGX_BUSY; | 404 return NGX_BUSY; |
361 } | 405 } |
362 | 406 |
363 lr->excess = excess; | 407 if (account) { |
364 lr->last = now; | 408 lr->excess = excess; |
365 | 409 lr->last = now; |
366 if (excess) { | 410 return NGX_OK; |
367 return NGX_AGAIN; | |
368 } | 411 } |
369 | 412 |
370 return NGX_OK; | 413 lr->count++; |
414 | |
415 ctx->node = lr; | |
416 | |
417 return NGX_AGAIN; | |
371 } | 418 } |
372 | 419 |
373 node = (rc < 0) ? node->left : node->right; | 420 node = (rc < 0) ? node->left : node->right; |
374 | 421 |
375 } while (node != sentinel && hash == node->key); | 422 } while (node != sentinel && hash == node->key); |
404 | 451 |
405 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | 452 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
406 | 453 |
407 lr->len = (u_char) len; | 454 lr->len = (u_char) len; |
408 lr->excess = 0; | 455 lr->excess = 0; |
409 lr->last = now; | |
410 | 456 |
411 ngx_memcpy(lr->data, data, len); | 457 ngx_memcpy(lr->data, data, len); |
412 | 458 |
413 return NGX_OK; | 459 if (account) { |
460 lr->last = now; | |
461 lr->count = 0; | |
462 return NGX_OK; | |
463 } | |
464 | |
465 lr->last = 0; | |
466 lr->count = 1; | |
467 | |
468 ctx->node = lr; | |
469 | |
470 return NGX_AGAIN; | |
471 } | |
472 | |
473 | |
474 static ngx_msec_t | |
475 ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, | |
476 ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit) | |
477 { | |
478 ngx_int_t excess; | |
479 ngx_time_t *tp; | |
480 ngx_msec_t now, delay, max_delay; | |
481 ngx_msec_int_t ms; | |
482 ngx_http_limit_req_ctx_t *ctx; | |
483 ngx_http_limit_req_node_t *lr; | |
484 | |
485 excess = *ep; | |
486 | |
487 if (excess == 0 || (*limit)->nodelay) { | |
488 max_delay = 0; | |
489 | |
490 } else { | |
491 ctx = (*limit)->shm_zone->data; | |
492 max_delay = excess * 1000 / ctx->rate; | |
493 } | |
494 | |
495 while (n--) { | |
496 ctx = limits[n].shm_zone->data; | |
497 lr = ctx->node; | |
498 | |
499 if (lr == NULL) { | |
500 continue; | |
501 } | |
502 | |
503 ngx_shmtx_lock(&ctx->shpool->mutex); | |
504 | |
505 tp = ngx_timeofday(); | |
506 | |
507 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | |
508 ms = (ngx_msec_int_t) (now - lr->last); | |
509 | |
510 excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; | |
511 | |
512 if (excess < 0) { | |
513 excess = 0; | |
514 } | |
515 | |
516 lr->last = now; | |
517 lr->excess = excess; | |
518 lr->count--; | |
519 | |
520 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
521 | |
522 ctx->node = NULL; | |
523 | |
524 if (limits[n].nodelay) { | |
525 continue; | |
526 } | |
527 | |
528 delay = excess * 1000 / ctx->rate; | |
529 | |
530 if (delay > max_delay) { | |
531 max_delay = delay; | |
532 *ep = excess; | |
533 *limit = &limits[n]; | |
534 } | |
535 } | |
536 | |
537 return max_delay; | |
414 } | 538 } |
415 | 539 |
416 | 540 |
417 static void | 541 static void |
418 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) | 542 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) |
443 | 567 |
444 q = ngx_queue_last(&ctx->sh->queue); | 568 q = ngx_queue_last(&ctx->sh->queue); |
445 | 569 |
446 lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue); | 570 lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue); |
447 | 571 |
572 if (lr->count) { | |
573 | |
574 /* | |
575 * There is not much sense in looking further, | |
576 * because we bump nodes on the lookup stage. | |
577 */ | |
578 | |
579 return; | |
580 } | |
581 | |
448 if (n++ != 0) { | 582 if (n++ != 0) { |
449 | 583 |
450 ms = (ngx_msec_int_t) (now - lr->last); | 584 ms = (ngx_msec_int_t) (now - lr->last); |
451 ms = ngx_abs(ms); | 585 ms = ngx_abs(ms); |
452 | 586 |
543 } | 677 } |
544 | 678 |
545 /* | 679 /* |
546 * set by ngx_pcalloc(): | 680 * set by ngx_pcalloc(): |
547 * | 681 * |
548 * conf->shm_zone = NULL; | 682 * conf->limits.elts = NULL; |
549 * conf->burst = 0; | |
550 * conf->nodelay = 0; | |
551 */ | 683 */ |
552 | 684 |
553 conf->limit_log_level = NGX_CONF_UNSET_UINT; | 685 conf->limit_log_level = NGX_CONF_UNSET_UINT; |
554 | 686 |
555 return conf; | 687 return conf; |
560 ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child) | 692 ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child) |
561 { | 693 { |
562 ngx_http_limit_req_conf_t *prev = parent; | 694 ngx_http_limit_req_conf_t *prev = parent; |
563 ngx_http_limit_req_conf_t *conf = child; | 695 ngx_http_limit_req_conf_t *conf = child; |
564 | 696 |
565 if (conf->shm_zone == NULL) { | 697 if (conf->limits.elts == NULL) { |
566 conf->shm_zone = prev->shm_zone; | 698 conf->limits = prev->limits; |
567 conf->burst = prev->burst; | |
568 conf->nodelay = prev->nodelay; | |
569 } | 699 } |
570 | 700 |
571 ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, | 701 ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, |
572 NGX_LOG_ERR); | 702 NGX_LOG_ERR); |
573 | 703 |
724 static char * | 854 static char * |
725 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 855 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
726 { | 856 { |
727 ngx_http_limit_req_conf_t *lrcf = conf; | 857 ngx_http_limit_req_conf_t *lrcf = conf; |
728 | 858 |
729 ngx_int_t burst; | 859 ngx_int_t burst; |
730 ngx_str_t *value, s; | 860 ngx_str_t *value, s; |
731 ngx_uint_t i; | 861 ngx_uint_t i, nodelay; |
732 | 862 ngx_shm_zone_t *shm_zone; |
733 if (lrcf->shm_zone) { | 863 ngx_http_limit_req_limit_t *limit, *limits; |
734 return "is duplicate"; | |
735 } | |
736 | 864 |
737 value = cf->args->elts; | 865 value = cf->args->elts; |
738 | 866 |
867 shm_zone = NULL; | |
739 burst = 0; | 868 burst = 0; |
869 nodelay = 0; | |
740 | 870 |
741 for (i = 1; i < cf->args->nelts; i++) { | 871 for (i = 1; i < cf->args->nelts; i++) { |
742 | 872 |
743 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { | 873 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { |
744 | 874 |
745 s.len = value[i].len - 5; | 875 s.len = value[i].len - 5; |
746 s.data = value[i].data + 5; | 876 s.data = value[i].data + 5; |
747 | 877 |
748 lrcf->shm_zone = ngx_shared_memory_add(cf, &s, 0, | 878 shm_zone = ngx_shared_memory_add(cf, &s, 0, |
749 &ngx_http_limit_req_module); | 879 &ngx_http_limit_req_module); |
750 if (lrcf->shm_zone == NULL) { | 880 if (shm_zone == NULL) { |
751 return NGX_CONF_ERROR; | 881 return NGX_CONF_ERROR; |
752 } | 882 } |
753 | 883 |
754 continue; | 884 continue; |
755 } | 885 } |
765 | 895 |
766 continue; | 896 continue; |
767 } | 897 } |
768 | 898 |
769 if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) { | 899 if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) { |
770 lrcf->nodelay = 1; | 900 nodelay = 1; |
771 continue; | 901 continue; |
772 } | 902 } |
773 | 903 |
774 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 904 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
775 "invalid parameter \"%V\"", &value[i]); | 905 "invalid parameter \"%V\"", &value[i]); |
776 return NGX_CONF_ERROR; | 906 return NGX_CONF_ERROR; |
777 } | 907 } |
778 | 908 |
779 if (lrcf->shm_zone == NULL) { | 909 if (shm_zone == NULL) { |
780 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 910 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
781 "\"%V\" must have \"zone\" parameter", | 911 "\"%V\" must have \"zone\" parameter", |
782 &cmd->name); | 912 &cmd->name); |
783 return NGX_CONF_ERROR; | 913 return NGX_CONF_ERROR; |
784 } | 914 } |
785 | 915 |
786 if (lrcf->shm_zone->data == NULL) { | 916 if (shm_zone->data == NULL) { |
787 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 917 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
788 "unknown limit_req_zone \"%V\"", | 918 "unknown limit_req_zone \"%V\"", |
789 &lrcf->shm_zone->shm.name); | 919 &shm_zone->shm.name); |
790 return NGX_CONF_ERROR; | 920 return NGX_CONF_ERROR; |
791 } | 921 } |
792 | 922 |
793 lrcf->burst = burst * 1000; | 923 limits = lrcf->limits.elts; |
924 | |
925 if (limits == NULL) { | |
926 if (ngx_array_init(&lrcf->limits, cf->pool, 1, | |
927 sizeof(ngx_http_limit_req_limit_t)) | |
928 != NGX_OK) | |
929 { | |
930 return NGX_CONF_ERROR; | |
931 } | |
932 } | |
933 | |
934 for (i = 0; i < lrcf->limits.nelts; i++) { | |
935 if (shm_zone == limits[i].shm_zone) { | |
936 return "is duplicate"; | |
937 } | |
938 } | |
939 | |
940 limit = ngx_array_push(&lrcf->limits); | |
941 | |
942 limit->shm_zone = shm_zone; | |
943 limit->burst = burst * 1000; | |
944 limit->nodelay = nodelay; | |
794 | 945 |
795 return NGX_CONF_OK; | 946 return NGX_CONF_OK; |
796 } | 947 } |
797 | 948 |
798 | 949 |