~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/modules/ngx_http_limit_req_module.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_http.h>
 10 
 11 
 12 typedef struct {
 13     u_char                       color;
 14     u_char                       dummy;
 15     u_short                      len;
 16     ngx_queue_t                  queue;
 17     ngx_msec_t                   last;
 18     /* integer value, 1 corresponds to 0.001 r/s */
 19     ngx_uint_t                   excess;
 20     u_char                       data[1];
 21 } ngx_http_limit_req_node_t;
 22 
 23 
 24 typedef struct {
 25     ngx_rbtree_t                  rbtree;
 26     ngx_rbtree_node_t             sentinel;
 27     ngx_queue_t                   queue;
 28 } ngx_http_limit_req_shctx_t;
 29 
 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;
 38 } ngx_http_limit_req_ctx_t;
 39 
 40 
 41 typedef struct {
 42     ngx_shm_zone_t              *shm_zone;
 43     /* integer value, 1 corresponds to 0.001 r/s */
 44     ngx_uint_t                   burst;
 45     ngx_uint_t                   limit_log_level;
 46     ngx_uint_t                   delay_log_level;
 47 
 48     ngx_uint_t                   nodelay; /* unsigned  nodelay:1 */
 49 } ngx_http_limit_req_conf_t;
 50 
 51 
 52 static void ngx_http_limit_req_delay(ngx_http_request_t *r);
 53 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf,
 54     ngx_uint_t hash, u_char *data, size_t len, ngx_http_limit_req_node_t **lrp);
 55 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx,
 56     ngx_uint_t n);
 57 
 58 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf);
 59 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent,
 60     void *child);
 61 static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd,
 62     void *conf);
 63 static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd,
 64     void *conf);
 65 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf);
 66 
 67 
 68 static ngx_conf_enum_t  ngx_http_limit_req_log_levels[] = {
 69     { ngx_string("info"), NGX_LOG_INFO },
 70     { ngx_string("notice"), NGX_LOG_NOTICE },
 71     { ngx_string("warn"), NGX_LOG_WARN },
 72     { ngx_string("error"), NGX_LOG_ERR },
 73     { ngx_null_string, 0 }
 74 };
 75 
 76 
 77 static ngx_command_t  ngx_http_limit_req_commands[] = {
 78 
 79     { ngx_string("limit_req_zone"),
 80       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
 81       ngx_http_limit_req_zone,
 82       0,
 83       0,
 84       NULL },
 85 
 86     { ngx_string("limit_req"),
 87       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
 88       ngx_http_limit_req,
 89       NGX_HTTP_LOC_CONF_OFFSET,
 90       0,
 91       NULL },
 92 
 93     { ngx_string("limit_req_log_level"),
 94       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
 95       ngx_conf_set_enum_slot,
 96       NGX_HTTP_LOC_CONF_OFFSET,
 97       offsetof(ngx_http_limit_req_conf_t, limit_log_level),
 98       &ngx_http_limit_req_log_levels },
 99 
100       ngx_null_command
101 };
102 
103 
104 static ngx_http_module_t  ngx_http_limit_req_module_ctx = {
105     NULL,                                  /* preconfiguration */
106     ngx_http_limit_req_init,               /* postconfiguration */
107 
108     NULL,                                  /* create main configuration */
109     NULL,                                  /* init main configuration */
110 
111     NULL,                                  /* create server configuration */
112     NULL,                                  /* merge server configuration */
113 
114     ngx_http_limit_req_create_conf,        /* create location configration */
115     ngx_http_limit_req_merge_conf          /* merge location configration */
116 };
117 
118 
119 ngx_module_t  ngx_http_limit_req_module = {
120     NGX_MODULE_V1,
121     &ngx_http_limit_req_module_ctx,        /* module context */
122     ngx_http_limit_req_commands,           /* module directives */
123     NGX_HTTP_MODULE,                       /* module type */
124     NULL,                                  /* init master */
125     NULL,                                  /* init module */
126     NULL,                                  /* init process */
127     NULL,                                  /* init thread */
128     NULL,                                  /* exit thread */
129     NULL,                                  /* exit process */
130     NULL,                                  /* exit master */
131     NGX_MODULE_V1_PADDING
132 };
133 
134 
135 static ngx_int_t
136 ngx_http_limit_req_handler(ngx_http_request_t *r)
137 {
138     size_t                      len, n;
139     uint32_t                    hash;
140     ngx_int_t                   rc;
141     ngx_uint_t                  excess;
142     ngx_time_t                 *tp;
143     ngx_rbtree_node_t          *node;
144     ngx_http_variable_value_t  *vv;
145     ngx_http_limit_req_ctx_t   *ctx;
146     ngx_http_limit_req_node_t  *lr;
147     ngx_http_limit_req_conf_t  *lrcf;
148 
149     if (r->main->limit_req_set) {
150         return NGX_DECLINED;
151     }
152 
153     lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module);
154 
155     if (lrcf->shm_zone == NULL) {
156         return NGX_DECLINED;
157     }
158 
159     ctx = lrcf->shm_zone->data;
160 
161     vv = ngx_http_get_indexed_variable(r, ctx->index);
162 
163     if (vv == NULL || vv->not_found) {
164         return NGX_DECLINED;
165     }
166 
167     len = vv->len;
168 
169     if (len == 0) {
170         return NGX_DECLINED;
171     }
172 
173     if (len > 65535) {
174         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
175                       "the value of the \"%V\" variable "
176                       "is more than 65535 bytes: \"%v\"",
177                       &ctx->var, vv);
178         return NGX_DECLINED;
179     }
180 
181     r->main->limit_req_set = 1;
182 
183     hash = ngx_crc32_short(vv->data, len);
184 
185     ngx_shmtx_lock(&ctx->shpool->mutex);
186 
187     ngx_http_limit_req_expire(ctx, 1);
188 
189     rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &lr);
190 
191     if (lr) {
192         ngx_queue_remove(&lr->queue);
193 
194         ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
195 
196         excess = lr->excess;
197 
198     } else {
199         excess = 0;
200     }
201 
202     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
203                    "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000);
204 
205     if (rc == NGX_BUSY) {
206         ngx_shmtx_unlock(&ctx->shpool->mutex);
207 
208         ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
209                       "limiting requests, excess: %ui.%03ui by zone \"%V\"",
210                       excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
211 
212         return NGX_HTTP_SERVICE_UNAVAILABLE;
213     }
214 
215     if (rc == NGX_AGAIN) {
216         ngx_shmtx_unlock(&ctx->shpool->mutex);
217 
218         if (lrcf->nodelay) {
219             return NGX_DECLINED;
220         }
221 
222         ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
223                       "delaying request, excess: %ui.%03ui, by zone \"%V\"",
224                       excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name);
225 
226         if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
227             return NGX_HTTP_INTERNAL_SERVER_ERROR;
228         }
229 
230         r->read_event_handler = ngx_http_test_reading;
231         r->write_event_handler = ngx_http_limit_req_delay;
232         ngx_add_timer(r->connection->write, (ngx_msec_t) excess);
233 
234         return NGX_AGAIN;
235     }
236 
237     if (rc == NGX_OK) {
238         goto done;
239     }
240 
241     /* rc == NGX_DECLINED */
242 
243     n = offsetof(ngx_rbtree_node_t, color)
244         + offsetof(ngx_http_limit_req_node_t, data)
245         + len;
246 
247     node = ngx_slab_alloc_locked(ctx->shpool, n);
248     if (node == NULL) {
249 
250         ngx_http_limit_req_expire(ctx, 0);
251 
252         node = ngx_slab_alloc_locked(ctx->shpool, n);
253         if (node == NULL) {
254             ngx_shmtx_unlock(&ctx->shpool->mutex);
255             return NGX_HTTP_SERVICE_UNAVAILABLE;
256         }
257     }
258 
259     lr = (ngx_http_limit_req_node_t *) &node->color;
260 
261     node->key = hash;
262     lr->len = (u_char) len;
263 
264     tp = ngx_timeofday();
265     lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
266 
267     lr->excess = 0;
268     ngx_memcpy(lr->data, vv->data, len);
269 
270     ngx_rbtree_insert(&ctx->sh->rbtree, node);
271 
272     ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
273 
274 done:
275 
276     ngx_shmtx_unlock(&ctx->shpool->mutex);
277 
278     return NGX_DECLINED;
279 }
280 
281 
282 static void
283 ngx_http_limit_req_delay(ngx_http_request_t *r)
284 {
285     ngx_event_t  *wev;
286 
287     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
288                    "limit_req delay");
289 
290     wev = r->connection->write;
291 
292     if (!wev->timedout) {
293 
294         if (ngx_handle_write_event(wev, 0) != NGX_OK) {
295             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
296         }
297 
298         return;
299     }
300 
301     wev->timedout = 0;
302 
303     if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
304         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
305         return;
306     }
307 
308     r->read_event_handler = ngx_http_block_reading;
309     r->write_event_handler = ngx_http_core_run_phases;
310 
311     ngx_http_core_run_phases(r);
312 }
313 
314 
315 static void
316 ngx_http_limit_req_rbtree_insert_value(ngx_rbtree_node_t *temp,
317     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
318 {
319     ngx_rbtree_node_t          **p;
320     ngx_http_limit_req_node_t   *lrn, *lrnt;
321 
322     for ( ;; ) {
323 
324         if (node->key < temp->key) {
325 
326             p = &temp->left;
327 
328         } else if (node->key > temp->key) {
329 
330             p = &temp->right;
331 
332         } else { /* node->key == temp->key */
333 
334             lrn = (ngx_http_limit_req_node_t *) &node->color;
335             lrnt = (ngx_http_limit_req_node_t *) &temp->color;
336 
337             p = (ngx_memn2cmp(lrn->data, lrnt->data, lrn->len, lrnt->len) < 0)
338                 ? &temp->left : &temp->right;
339         }
340 
341         if (*p == sentinel) {
342             break;
343         }
344 
345         temp = *p;
346     }
347 
348     *p = node;
349     node->parent = temp;
350     node->left = sentinel;
351     node->right = sentinel;
352     ngx_rbt_red(node);
353 }
354 
355 
356 static ngx_int_t
357 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash,
358     u_char *data, size_t len, ngx_http_limit_req_node_t **lrp)
359 {
360     ngx_int_t                   rc, excess;
361     ngx_time_t                 *tp;
362     ngx_msec_t                  now;
363     ngx_msec_int_t              ms;
364     ngx_rbtree_node_t          *node, *sentinel;
365     ngx_http_limit_req_ctx_t   *ctx;
366     ngx_http_limit_req_node_t  *lr;
367 
368     ctx = lrcf->shm_zone->data;
369 
370     node = ctx->sh->rbtree.root;
371     sentinel = ctx->sh->rbtree.sentinel;
372 
373     while (node != sentinel) {
374 
375         if (hash < node->key) {
376             node = node->left;
377             continue;
378         }
379 
380         if (hash > node->key) {
381             node = node->right;
382             continue;
383         }
384 
385         /* hash == node->key */
386 
387         do {
388             lr = (ngx_http_limit_req_node_t *) &node->color;
389 
390             rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len);
391 
392             if (rc == 0) {
393 
394                 tp = ngx_timeofday();
395 
396                 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
397                 ms = (ngx_msec_int_t) (now - lr->last);
398 
399                 excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000;
400 
401                 if (excess < 0) {
402                     excess = 0;
403                 }
404 
405                 if ((ngx_uint_t) excess > lrcf->burst) {
406                     *lrp = lr;
407                     return NGX_BUSY;
408                 }
409 
410                 lr->excess = excess;
411                 lr->last = now;
412 
413                 *lrp = lr;
414 
415                 if (excess) {
416                     return NGX_AGAIN;
417                 }
418 
419                 return NGX_OK;
420             }
421 
422             node = (rc < 0) ? node->left : node->right;
423 
424         } while (node != sentinel && hash == node->key);
425 
426         break;
427     }
428 
429     *lrp = NULL;
430 
431     return NGX_DECLINED;
432 }
433 
434 
435 static void
436 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n)
437 {
438     ngx_int_t                   excess;
439     ngx_time_t                 *tp;
440     ngx_msec_t                  now;
441     ngx_queue_t                *q;
442     ngx_msec_int_t              ms;
443     ngx_rbtree_node_t          *node;
444     ngx_http_limit_req_node_t  *lr;
445 
446     tp = ngx_timeofday();
447 
448     now = (ngx_msec_t) (tp->sec * 1000 + tp->msec);
449 
450     /*
451      * n == 1 deletes one or two zero rate entries
452      * n == 0 deletes oldest entry by force
453      *        and one or two zero rate entries
454      */
455 
456     while (n < 3) {
457 
458         if (ngx_queue_empty(&ctx->sh->queue)) {
459             return;
460         }
461 
462         q = ngx_queue_last(&ctx->sh->queue);
463 
464         lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue);
465 
466         if (n++ != 0) {
467 
468             ms = (ngx_msec_int_t) (now - lr->last);
469             ms = ngx_abs(ms);
470 
471             if (ms < 60000) {
472                 return;
473             }
474 
475             excess = lr->excess - ctx->rate * ms / 1000;
476 
477             if (excess > 0) {
478                 return;
479             }
480         }
481 
482         ngx_queue_remove(q);
483 
484         node = (ngx_rbtree_node_t *)
485                    ((u_char *) lr - offsetof(ngx_rbtree_node_t, color));
486 
487         ngx_rbtree_delete(&ctx->sh->rbtree, node);
488 
489         ngx_slab_free_locked(ctx->shpool, node);
490     }
491 }
492 
493 
494 static ngx_int_t
495 ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data)
496 {
497     ngx_http_limit_req_ctx_t  *octx = data;
498 
499     size_t                     len;
500     ngx_http_limit_req_ctx_t  *ctx;
501 
502     ctx = shm_zone->data;
503 
504     if (octx) {
505         if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
506             ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
507                           "limit_req \"%V\" uses the \"%V\" variable "
508                           "while previously it used the \"%V\" variable",
509                           &shm_zone->shm.name, &ctx->var, &octx->var);
510             return NGX_ERROR;
511         }
512 
513         ctx->sh = octx->sh;
514         ctx->shpool = octx->shpool;
515 
516         return NGX_OK;
517     }
518 
519     ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
520 
521     if (shm_zone->shm.exists) {
522         ctx->sh = ctx->shpool->data;
523 
524         return NGX_OK;
525     }
526 
527     ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_shctx_t));
528     if (ctx->sh == NULL) {
529         return NGX_ERROR;
530     }
531 
532     ctx->shpool->data = ctx->sh;
533 
534     ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
535                     ngx_http_limit_req_rbtree_insert_value);
536 
537     ngx_queue_init(&ctx->sh->queue);
538 
539     len = sizeof(" in limit_req zone \"\"") + shm_zone->shm.name.len;
540 
541     ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
542     if (ctx->shpool->log_ctx == NULL) {
543         return NGX_ERROR;
544     }
545 
546     ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z",
547                 &shm_zone->shm.name);
548 
549     return NGX_OK;
550 }
551 
552 
553 static void *
554 ngx_http_limit_req_create_conf(ngx_conf_t *cf)
555 {
556     ngx_http_limit_req_conf_t  *conf;
557 
558     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t));
559     if (conf == NULL) {
560         return NULL;
561     }
562 
563     /*
564      * set by ngx_pcalloc():
565      *
566      *     conf->shm_zone = NULL;
567      *     conf->burst = 0;
568      *     conf->nodelay = 0;
569      */
570 
571     conf->limit_log_level = NGX_CONF_UNSET_UINT;
572 
573     return conf;
574 }
575 
576 
577 static char *
578 ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child)
579 {
580     ngx_http_limit_req_conf_t *prev = parent;
581     ngx_http_limit_req_conf_t *conf = child;
582 
583     if (conf->shm_zone == NULL) {
584         *conf = *prev;
585     }
586 
587     ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level,
588                               NGX_LOG_ERR);
589 
590     conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ?
591                                 NGX_LOG_INFO : conf->limit_log_level + 1;
592 
593     return NGX_CONF_OK;
594 }
595 
596 
597 static char *
598 ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
599 {
600     u_char                    *p;
601     size_t                     size, len;
602     ngx_str_t                 *value, name, s;
603     ngx_int_t                  rate, scale;
604     ngx_uint_t                 i;
605     ngx_shm_zone_t            *shm_zone;
606     ngx_http_limit_req_ctx_t  *ctx;
607 
608     value = cf->args->elts;
609 
610     ctx = NULL;
611     size = 0;
612     rate = 1;
613     scale = 1;
614     name.len = 0;
615 
616     for (i = 1; i < cf->args->nelts; i++) {
617 
618         if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
619 
620             name.data = value[i].data + 5;
621 
622             p = (u_char *) ngx_strchr(name.data, ':');
623 
624             if (p) {
625                 *p = '\0';
626 
627                 name.len = p - name.data;
628 
629                 p++;
630 
631                 s.len = value[i].data + value[i].len - p;
632                 s.data = p;
633 
634                 size = ngx_parse_size(&s);
635                 if (size > 8191) {
636                     continue;
637                 }
638             }
639 
640             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
641                                "invalid zone size \"%V\"", &value[i]);
642             return NGX_CONF_ERROR;
643         }
644 
645         if (ngx_strncmp(value[i].data, "rate=", 5) == 0) {
646 
647             len = value[i].len;
648             p = value[i].data + len - 3;
649 
650             if (ngx_strncmp(p, "r/s", 3) == 0) {
651                 scale = 1;
652                 len -= 3;
653 
654             } else if (ngx_strncmp(p, "r/m", 3) == 0) {
655                 scale = 60;
656                 len -= 3;
657             }
658 
659             rate = ngx_atoi(value[i].data + 5, len - 5);
660             if (rate <= NGX_ERROR) {
661                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
662                                    "invalid rate \"%V\"", &value[i]);
663                 return NGX_CONF_ERROR;
664             }
665 
666             continue;
667         }
668 
669         if (value[i].data[0] == '$') {
670 
671             value[i].len--;
672             value[i].data++;
673 
674             ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t));
675             if (ctx == NULL) {
676                 return NGX_CONF_ERROR;
677             }
678 
679             ctx->index = ngx_http_get_variable_index(cf, &value[i]);
680             if (ctx->index == NGX_ERROR) {
681                 return NGX_CONF_ERROR;
682             }
683 
684             ctx->var = value[i];
685 
686             continue;
687         }
688 
689         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
690                            "invalid parameter \"%V\"", &value[i]);
691         return NGX_CONF_ERROR;
692     }
693 
694     if (name.len == 0 || size == 0) {
695         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
696                            "\"%V\" must have \"zone\" parameter",
697                            &cmd->name);
698         return NGX_CONF_ERROR;
699     }
700 
701     if (ctx == NULL) {
702         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
703                            "no variable is defined for limit_req_zone \"%V\"",
704                            &cmd->name);
705         return NGX_CONF_ERROR;
706     }
707 
708     ctx->rate = rate * 1000 / scale;
709 
710     shm_zone = ngx_shared_memory_add(cf, &name, size,
711                                      &ngx_http_limit_req_module);
712     if (shm_zone == NULL) {
713         return NGX_CONF_ERROR;
714     }
715 
716     if (shm_zone->data) {
717         ctx = shm_zone->data;
718 
719         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
720                    "limit_req_zone \"%V\" is already bound to variable \"%V\"",
721                    &value[1], &ctx->var);
722         return NGX_CONF_ERROR;
723     }
724 
725     shm_zone->init = ngx_http_limit_req_init_zone;
726     shm_zone->data = ctx;
727 
728     return NGX_CONF_OK;
729 }
730 
731 
732 static char *
733 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
734 {
735     ngx_http_limit_req_conf_t  *lrcf = conf;
736 
737     ngx_int_t    burst;
738     ngx_str_t   *value, s;
739     ngx_uint_t   i;
740 
741     if (lrcf->shm_zone) {
742         return "is duplicate";
743     }
744 
745     value = cf->args->elts;
746 
747     burst = 0;
748 
749     for (i = 1; i < cf->args->nelts; i++) {
750 
751         if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
752 
753             s.len = value[i].len - 5;
754             s.data = value[i].data + 5;
755 
756             lrcf->shm_zone = ngx_shared_memory_add(cf, &s, 0,
757                                                    &ngx_http_limit_req_module);
758             if (lrcf->shm_zone == NULL) {
759                 return NGX_CONF_ERROR;
760             }
761 
762             continue;
763         }
764 
765         if (ngx_strncmp(value[i].data, "burst=", 6) == 0) {
766 
767             burst = ngx_atoi(value[i].data + 6, value[i].len - 6);
768             if (burst <= 0) {
769                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
770                                    "invalid burst rate \"%V\"", &value[i]);
771                 return NGX_CONF_ERROR;
772             }
773 
774             continue;
775         }
776 
777         if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) {
778             lrcf->nodelay = 1;
779             continue;
780         }
781 
782         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
783                            "invalid parameter \"%V\"", &value[i]);
784         return NGX_CONF_ERROR;
785     }
786 
787     if (lrcf->shm_zone == NULL) {
788         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
789                            "\"%V\" must have \"zone\" parameter",
790                            &cmd->name);
791         return NGX_CONF_ERROR;
792     }
793 
794     if (lrcf->shm_zone->data == NULL) {
795         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
796                            "unknown limit_req_zone \"%V\"",
797                            &lrcf->shm_zone->shm.name);
798         return NGX_CONF_ERROR;
799     }
800 
801     lrcf->burst = burst * 1000;
802 
803     return NGX_CONF_OK;
804 }
805 
806 
807 static ngx_int_t
808 ngx_http_limit_req_init(ngx_conf_t *cf)
809 {
810     ngx_http_handler_pt        *h;
811     ngx_http_core_main_conf_t  *cmcf;
812 
813     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
814 
815     h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
816     if (h == NULL) {
817         return NGX_ERROR;
818     }
819 
820     *h = ngx_http_limit_req_handler;
821 
822     return NGX_OK;
823 }
824 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.