comparison src/http/modules/ngx_http_limit_conn_module.c @ 648:f200748c0ac8 NGINX_1_1_8

nginx 1.1.8 *) Change: the ngx_http_limit_zone_module was renamed to the ngx_http_limit_conn_module. *) Change: the "limit_zone" directive was superseded by the "limit_conn_zone" directive with a new syntax. *) Feature: support for multiple "limit_conn" limits on the same level. *) Feature: the "image_filter_sharpen" directive. *) Bugfix: a segmentation fault might occur in a worker process if resolver got a big DNS response. Thanks to Ben Hawkes. *) Bugfix: in cache key calculation if internal MD5 implementation was used; the bug had appeared in 1.0.4. *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request header lines might be passed to backend while caching; or not passed without caching if caching was enabled in another part of the configuration. *) Bugfix: the module ngx_http_mp4_module sent incorrect "Content-Length" response header line if the "start" argument was used. Thanks to Piotr Sikora.
author Igor Sysoev <http://sysoev.ru>
date Mon, 14 Nov 2011 00:00:00 +0400
parents
children 9d21dad0b5a1
comparison
equal deleted inserted replaced
647:bec017127243 648:f200748c0ac8
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 len;
15 u_short conn;
16 u_char data[1];
17 } ngx_http_limit_conn_node_t;
18
19
20 typedef struct {
21 ngx_shm_zone_t *shm_zone;
22 ngx_rbtree_node_t *node;
23 } ngx_http_limit_conn_cleanup_t;
24
25
26 typedef struct {
27 ngx_rbtree_t *rbtree;
28 ngx_int_t index;
29 ngx_str_t var;
30 } ngx_http_limit_conn_ctx_t;
31
32
33 typedef struct {
34 ngx_shm_zone_t *shm_zone;
35 ngx_uint_t conn;
36 } ngx_http_limit_conn_limit_t;
37
38
39 typedef struct {
40 ngx_array_t limits;
41 ngx_uint_t log_level;
42 } ngx_http_limit_conn_conf_t;
43
44
45 static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
46 ngx_http_variable_value_t *vv, uint32_t hash);
47 static void ngx_http_limit_conn_cleanup(void *data);
48 static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
49
50 static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
51 static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
52 void *child);
53 static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
54 void *conf);
55 static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd,
56 void *conf);
57 static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
58 void *conf);
59 static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
60
61
62 static ngx_conf_deprecated_t ngx_conf_deprecated_limit_zone = {
63 ngx_conf_deprecated, "limit_zone", "limit_conn_zone"
64 };
65
66
67 static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = {
68 { ngx_string("info"), NGX_LOG_INFO },
69 { ngx_string("notice"), NGX_LOG_NOTICE },
70 { ngx_string("warn"), NGX_LOG_WARN },
71 { ngx_string("error"), NGX_LOG_ERR },
72 { ngx_null_string, 0 }
73 };
74
75
76 static ngx_command_t ngx_http_limit_conn_commands[] = {
77
78 { ngx_string("limit_conn_zone"),
79 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2,
80 ngx_http_limit_conn_zone,
81 0,
82 0,
83 NULL },
84
85 { ngx_string("limit_zone"),
86 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
87 ngx_http_limit_zone,
88 0,
89 0,
90 NULL },
91
92 { ngx_string("limit_conn"),
93 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
94 ngx_http_limit_conn,
95 NGX_HTTP_LOC_CONF_OFFSET,
96 0,
97 NULL },
98
99 { ngx_string("limit_conn_log_level"),
100 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
101 ngx_conf_set_enum_slot,
102 NGX_HTTP_LOC_CONF_OFFSET,
103 offsetof(ngx_http_limit_conn_conf_t, log_level),
104 &ngx_http_limit_conn_log_levels },
105
106 ngx_null_command
107 };
108
109
110 static ngx_http_module_t ngx_http_limit_conn_module_ctx = {
111 NULL, /* preconfiguration */
112 ngx_http_limit_conn_init, /* postconfiguration */
113
114 NULL, /* create main configuration */
115 NULL, /* init main configuration */
116
117 NULL, /* create server configuration */
118 NULL, /* merge server configuration */
119
120 ngx_http_limit_conn_create_conf, /* create location configration */
121 ngx_http_limit_conn_merge_conf /* merge location configration */
122 };
123
124
125 ngx_module_t ngx_http_limit_conn_module = {
126 NGX_MODULE_V1,
127 &ngx_http_limit_conn_module_ctx, /* module context */
128 ngx_http_limit_conn_commands, /* module directives */
129 NGX_HTTP_MODULE, /* module type */
130 NULL, /* init master */
131 NULL, /* init module */
132 NULL, /* init process */
133 NULL, /* init thread */
134 NULL, /* exit thread */
135 NULL, /* exit process */
136 NULL, /* exit master */
137 NGX_MODULE_V1_PADDING
138 };
139
140
141 static ngx_int_t
142 ngx_http_limit_conn_handler(ngx_http_request_t *r)
143 {
144 size_t len, n;
145 uint32_t hash;
146 ngx_uint_t i;
147 ngx_slab_pool_t *shpool;
148 ngx_rbtree_node_t *node;
149 ngx_pool_cleanup_t *cln;
150 ngx_http_variable_value_t *vv;
151 ngx_http_limit_conn_ctx_t *ctx;
152 ngx_http_limit_conn_node_t *lc;
153 ngx_http_limit_conn_conf_t *lccf;
154 ngx_http_limit_conn_limit_t *limits;
155 ngx_http_limit_conn_cleanup_t *lccln;
156
157 if (r->main->limit_conn_set) {
158 return NGX_DECLINED;
159 }
160
161 r->main->limit_conn_set = 1;
162
163 lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);
164 limits = lccf->limits.elts;
165
166 for (i = 0; i < lccf->limits.nelts; i++) {
167 ctx = limits[i].shm_zone->data;
168
169 vv = ngx_http_get_indexed_variable(r, ctx->index);
170
171 if (vv == NULL || vv->not_found) {
172 continue;
173 }
174
175 len = vv->len;
176
177 if (len == 0) {
178 continue;
179 }
180
181 if (len > 255) {
182 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
183 "the value of the \"%V\" variable "
184 "is more than 255 bytes: \"%v\"",
185 &ctx->var, vv);
186 continue;
187 }
188
189 hash = ngx_crc32_short(vv->data, len);
190
191 shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
192
193 ngx_shmtx_lock(&shpool->mutex);
194
195 node = ngx_http_limit_conn_lookup(ctx->rbtree, vv, hash);
196
197 if (node == NULL) {
198
199 n = offsetof(ngx_rbtree_node_t, color)
200 + offsetof(ngx_http_limit_conn_node_t, data)
201 + len;
202
203 node = ngx_slab_alloc_locked(shpool, n);
204
205 if (node == NULL) {
206 ngx_shmtx_unlock(&shpool->mutex);
207 ngx_http_limit_conn_cleanup_all(r->pool);
208 return NGX_HTTP_SERVICE_UNAVAILABLE;
209 }
210
211 lc = (ngx_http_limit_conn_node_t *) &node->color;
212
213 node->key = hash;
214 lc->len = (u_char) len;
215 lc->conn = 1;
216 ngx_memcpy(lc->data, vv->data, len);
217
218 ngx_rbtree_insert(ctx->rbtree, node);
219
220 } else {
221
222 lc = (ngx_http_limit_conn_node_t *) &node->color;
223
224 if ((ngx_uint_t) lc->conn >= limits[i].conn) {
225
226 ngx_shmtx_unlock(&shpool->mutex);
227
228 ngx_log_error(lccf->log_level, r->connection->log, 0,
229 "limiting connections by zone \"%V\"",
230 &limits[i].shm_zone->shm.name);
231
232 ngx_http_limit_conn_cleanup_all(r->pool);
233 return NGX_HTTP_SERVICE_UNAVAILABLE;
234 }
235
236 lc->conn++;
237 }
238
239 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
240 "limit zone: %08XD %d", node->key, lc->conn);
241
242 ngx_shmtx_unlock(&shpool->mutex);
243
244 cln = ngx_pool_cleanup_add(r->pool,
245 sizeof(ngx_http_limit_conn_cleanup_t));
246 if (cln == NULL) {
247 return NGX_HTTP_INTERNAL_SERVER_ERROR;
248 }
249
250 cln->handler = ngx_http_limit_conn_cleanup;
251 lccln = cln->data;
252
253 lccln->shm_zone = limits[i].shm_zone;
254 lccln->node = node;
255 }
256
257 return NGX_DECLINED;
258 }
259
260
261 static void
262 ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp,
263 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
264 {
265 ngx_rbtree_node_t **p;
266 ngx_http_limit_conn_node_t *lcn, *lcnt;
267
268 for ( ;; ) {
269
270 if (node->key < temp->key) {
271
272 p = &temp->left;
273
274 } else if (node->key > temp->key) {
275
276 p = &temp->right;
277
278 } else { /* node->key == temp->key */
279
280 lcn = (ngx_http_limit_conn_node_t *) &node->color;
281 lcnt = (ngx_http_limit_conn_node_t *) &temp->color;
282
283 p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 0)
284 ? &temp->left : &temp->right;
285 }
286
287 if (*p == sentinel) {
288 break;
289 }
290
291 temp = *p;
292 }
293
294 *p = node;
295 node->parent = temp;
296 node->left = sentinel;
297 node->right = sentinel;
298 ngx_rbt_red(node);
299 }
300
301
302 static ngx_rbtree_node_t *
303 ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv,
304 uint32_t hash)
305 {
306 ngx_int_t rc;
307 ngx_rbtree_node_t *node, *sentinel;
308 ngx_http_limit_conn_node_t *lcn;
309
310 node = rbtree->root;
311 sentinel = rbtree->sentinel;
312
313 while (node != sentinel) {
314
315 if (hash < node->key) {
316 node = node->left;
317 continue;
318 }
319
320 if (hash > node->key) {
321 node = node->right;
322 continue;
323 }
324
325 /* hash == node->key */
326
327 do {
328 lcn = (ngx_http_limit_conn_node_t *) &node->color;
329
330 rc = ngx_memn2cmp(vv->data, lcn->data,
331 (size_t) vv->len, (size_t) lcn->len);
332 if (rc == 0) {
333 return node;
334 }
335
336 node = (rc < 0) ? node->left : node->right;
337
338 } while (node != sentinel && hash == node->key);
339
340 break;
341 }
342
343 return NULL;
344 }
345
346
347 static void
348 ngx_http_limit_conn_cleanup(void *data)
349 {
350 ngx_http_limit_conn_cleanup_t *lccln = data;
351
352 ngx_slab_pool_t *shpool;
353 ngx_rbtree_node_t *node;
354 ngx_http_limit_conn_ctx_t *ctx;
355 ngx_http_limit_conn_node_t *lc;
356
357 ctx = lccln->shm_zone->data;
358 shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
359 node = lccln->node;
360 lc = (ngx_http_limit_conn_node_t *) &node->color;
361
362 ngx_shmtx_lock(&shpool->mutex);
363
364 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
365 "limit zone cleanup: %08XD %d", node->key, lc->conn);
366
367 lc->conn--;
368
369 if (lc->conn == 0) {
370 ngx_rbtree_delete(ctx->rbtree, node);
371 ngx_slab_free_locked(shpool, node);
372 }
373
374 ngx_shmtx_unlock(&shpool->mutex);
375 }
376
377
378 static ngx_inline void
379 ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool)
380 {
381 ngx_pool_cleanup_t *cln;
382
383 cln = pool->cleanup;
384
385 while (cln && cln->handler == ngx_http_limit_conn_cleanup) {
386 ngx_http_limit_conn_cleanup(cln->data);
387 cln = cln->next;
388 }
389
390 pool->cleanup = cln;
391 }
392
393
394 static ngx_int_t
395 ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
396 {
397 ngx_http_limit_conn_ctx_t *octx = data;
398
399 size_t len;
400 ngx_slab_pool_t *shpool;
401 ngx_rbtree_node_t *sentinel;
402 ngx_http_limit_conn_ctx_t *ctx;
403
404 ctx = shm_zone->data;
405
406 if (octx) {
407 if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
408 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
409 "limit_conn_zone \"%V\" uses the \"%V\" variable "
410 "while previously it used the \"%V\" variable",
411 &shm_zone->shm.name, &ctx->var, &octx->var);
412 return NGX_ERROR;
413 }
414
415 ctx->rbtree = octx->rbtree;
416
417 return NGX_OK;
418 }
419
420 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
421
422 if (shm_zone->shm.exists) {
423 ctx->rbtree = shpool->data;
424
425 return NGX_OK;
426 }
427
428 ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
429 if (ctx->rbtree == NULL) {
430 return NGX_ERROR;
431 }
432
433 shpool->data = ctx->rbtree;
434
435 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
436 if (sentinel == NULL) {
437 return NGX_ERROR;
438 }
439
440 ngx_rbtree_init(ctx->rbtree, sentinel,
441 ngx_http_limit_conn_rbtree_insert_value);
442
443 len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
444
445 shpool->log_ctx = ngx_slab_alloc(shpool, len);
446 if (shpool->log_ctx == NULL) {
447 return NGX_ERROR;
448 }
449
450 ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
451 &shm_zone->shm.name);
452
453 return NGX_OK;
454 }
455
456
457 static void *
458 ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
459 {
460 ngx_http_limit_conn_conf_t *conf;
461
462 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_conf_t));
463 if (conf == NULL) {
464 return NULL;
465 }
466
467 /*
468 * set by ngx_pcalloc():
469 *
470 * conf->limits.elts = NULL;
471 */
472
473 conf->log_level = NGX_CONF_UNSET_UINT;
474
475 return conf;
476 }
477
478
479 static char *
480 ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child)
481 {
482 ngx_http_limit_conn_conf_t *prev = parent;
483 ngx_http_limit_conn_conf_t *conf = child;
484
485 if (conf->limits.elts == NULL) {
486 *conf = *prev;
487 }
488
489 ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
490
491 return NGX_CONF_OK;
492 }
493
494
495 static char *
496 ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
497 {
498 u_char *p;
499 ssize_t size;
500 ngx_str_t *value, name, s;
501 ngx_uint_t i;
502 ngx_shm_zone_t *shm_zone;
503 ngx_http_limit_conn_ctx_t *ctx;
504
505 value = cf->args->elts;
506
507 ctx = NULL;
508 size = 0;
509 name.len = 0;
510
511 for (i = 1; i < cf->args->nelts; i++) {
512
513 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
514
515 name.data = value[i].data + 5;
516
517 p = (u_char *) ngx_strchr(name.data, ':');
518
519 if (p == NULL) {
520 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
521 "invalid zone size \"%V\"", &value[i]);
522 return NGX_CONF_ERROR;
523 }
524
525 name.len = p - name.data;
526
527 s.data = p + 1;
528 s.len = value[i].data + value[i].len - s.data;
529
530 size = ngx_parse_size(&s);
531
532 if (size == NGX_ERROR) {
533 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
534 "invalid zone size \"%V\"", &value[i]);
535 return NGX_CONF_ERROR;
536 }
537
538 if (size < (ssize_t) (8 * ngx_pagesize)) {
539 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
540 "zone \"%V\" is too small", &value[i]);
541 return NGX_CONF_ERROR;
542 }
543
544 continue;
545 }
546
547 if (value[i].data[0] == '$') {
548
549 value[i].len--;
550 value[i].data++;
551
552 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
553 if (ctx == NULL) {
554 return NGX_CONF_ERROR;
555 }
556
557 ctx->index = ngx_http_get_variable_index(cf, &value[i]);
558 if (ctx->index == NGX_ERROR) {
559 return NGX_CONF_ERROR;
560 }
561
562 ctx->var = value[i];
563
564 continue;
565 }
566
567 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
568 "invalid parameter \"%V\"", &value[i]);
569 return NGX_CONF_ERROR;
570 }
571
572 if (name.len == 0) {
573 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
574 "\"%V\" must have \"zone\" parameter",
575 &cmd->name);
576 return NGX_CONF_ERROR;
577 }
578
579 if (ctx == NULL) {
580 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
581 "no variable is defined for %V \"%V\"",
582 &cmd->name, &name);
583 return NGX_CONF_ERROR;
584 }
585
586 shm_zone = ngx_shared_memory_add(cf, &name, size,
587 &ngx_http_limit_conn_module);
588 if (shm_zone == NULL) {
589 return NGX_CONF_ERROR;
590 }
591
592 if (shm_zone->data) {
593 ctx = shm_zone->data;
594
595 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
596 "%V \"%V\" is already bound to variable \"%V\"",
597 &cmd->name, &name, &ctx->var);
598 return NGX_CONF_ERROR;
599 }
600
601 shm_zone->init = ngx_http_limit_conn_init_zone;
602 shm_zone->data = ctx;
603
604 return NGX_CONF_OK;
605 }
606
607
608 static char *
609 ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
610 {
611 ssize_t n;
612 ngx_str_t *value;
613 ngx_shm_zone_t *shm_zone;
614 ngx_http_limit_conn_ctx_t *ctx;
615
616 ngx_conf_deprecated(cf, &ngx_conf_deprecated_limit_zone, NULL);
617
618 value = cf->args->elts;
619
620 if (value[2].data[0] != '$') {
621 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
622 "invalid variable name \"%V\"", &value[2]);
623 return NGX_CONF_ERROR;
624 }
625
626 value[2].len--;
627 value[2].data++;
628
629 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t));
630 if (ctx == NULL) {
631 return NGX_CONF_ERROR;
632 }
633
634 ctx->index = ngx_http_get_variable_index(cf, &value[2]);
635 if (ctx->index == NGX_ERROR) {
636 return NGX_CONF_ERROR;
637 }
638
639 ctx->var = value[2];
640
641 n = ngx_parse_size(&value[3]);
642
643 if (n == NGX_ERROR) {
644 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
645 "invalid size of limit_zone \"%V\"", &value[3]);
646 return NGX_CONF_ERROR;
647 }
648
649 if (n < (ngx_int_t) (8 * ngx_pagesize)) {
650 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
651 "limit_zone \"%V\" is too small", &value[1]);
652 return NGX_CONF_ERROR;
653 }
654
655
656 shm_zone = ngx_shared_memory_add(cf, &value[1], n,
657 &ngx_http_limit_conn_module);
658 if (shm_zone == NULL) {
659 return NGX_CONF_ERROR;
660 }
661
662 if (shm_zone->data) {
663 ctx = shm_zone->data;
664
665 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
666 "limit_zone \"%V\" is already bound to variable \"%V\"",
667 &value[1], &ctx->var);
668 return NGX_CONF_ERROR;
669 }
670
671 shm_zone->init = ngx_http_limit_conn_init_zone;
672 shm_zone->data = ctx;
673
674 return NGX_CONF_OK;
675 }
676
677
678 static char *
679 ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
680 {
681 ngx_shm_zone_t *shm_zone;
682 ngx_http_limit_conn_conf_t *lccf = conf;
683 ngx_http_limit_conn_limit_t *limit, *limits;
684
685 ngx_str_t *value;
686 ngx_int_t n;
687 ngx_uint_t i;
688
689 value = cf->args->elts;
690
691 shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
692 &ngx_http_limit_conn_module);
693 if (shm_zone == NULL) {
694 return NGX_CONF_ERROR;
695 }
696
697 limits = lccf->limits.elts;
698
699 if (limits == NULL) {
700 if (ngx_array_init(&lccf->limits, cf->pool, 1,
701 sizeof(ngx_http_limit_conn_limit_t))
702 != NGX_OK)
703 {
704 return NGX_CONF_ERROR;
705 }
706 }
707
708 for (i = 0; i < lccf->limits.nelts; i++) {
709 if (shm_zone == limits[i].shm_zone) {
710 return "is duplicate";
711 }
712 }
713
714 n = ngx_atoi(value[2].data, value[2].len);
715 if (n <= 0) {
716 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
717 "invalid number of connections \"%V\"", &value[2]);
718 return NGX_CONF_ERROR;
719 }
720
721 if (n > 65535) {
722 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
723 "connection limit must be less 65536");
724 return NGX_CONF_ERROR;
725 }
726
727 limit = ngx_array_push(&lccf->limits);
728 limit->conn = n;
729 limit->shm_zone = shm_zone;
730
731 return NGX_CONF_OK;
732 }
733
734
735 static ngx_int_t
736 ngx_http_limit_conn_init(ngx_conf_t *cf)
737 {
738 ngx_http_handler_pt *h;
739 ngx_http_core_main_conf_t *cmcf;
740
741 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
742
743 h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
744 if (h == NULL) {
745 return NGX_ERROR;
746 }
747
748 *h = ngx_http_limit_conn_handler;
749
750 return NGX_OK;
751 }