comparison src/http/modules/ngx_http_limit_conn_module.c @ 7595:9606d93aa586

Limit conn: $limit_conn_status variable. The variable takes one of the values: PASSED, REJECTED or REJECTED_DRY_RUN.
author Roman Arutyunyan <arut@nginx.com>
date Mon, 18 Nov 2019 17:48:32 +0300
parents 359b0ea2b067
children b45f052483b8
comparison
equal deleted inserted replaced
7594:359b0ea2b067 7595:9606d93aa586
6 6
7 7
8 #include <ngx_config.h> 8 #include <ngx_config.h>
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11
12
13 #define NGX_HTTP_LIMIT_CONN_PASSED 1
14 #define NGX_HTTP_LIMIT_CONN_REJECTED 2
15 #define NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN 3
11 16
12 17
13 typedef struct { 18 typedef struct {
14 u_char color; 19 u_char color;
15 u_char len; 20 u_char len;
47 static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, 52 static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
48 ngx_str_t *key, uint32_t hash); 53 ngx_str_t *key, uint32_t hash);
49 static void ngx_http_limit_conn_cleanup(void *data); 54 static void ngx_http_limit_conn_cleanup(void *data);
50 static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); 55 static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
51 56
57 static ngx_int_t ngx_http_limit_conn_status_variable(ngx_http_request_t *r,
58 ngx_http_variable_value_t *v, uintptr_t data);
52 static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf); 59 static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
53 static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, 60 static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
54 void *child); 61 void *child);
55 static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, 62 static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
56 void *conf); 63 void *conf);
57 static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, 64 static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
58 void *conf); 65 void *conf);
66 static ngx_int_t ngx_http_limit_conn_add_variables(ngx_conf_t *cf);
59 static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf); 67 static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
60 68
61 69
62 static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { 70 static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = {
63 { ngx_string("info"), NGX_LOG_INFO }, 71 { ngx_string("info"), NGX_LOG_INFO },
113 ngx_null_command 121 ngx_null_command
114 }; 122 };
115 123
116 124
117 static ngx_http_module_t ngx_http_limit_conn_module_ctx = { 125 static ngx_http_module_t ngx_http_limit_conn_module_ctx = {
118 NULL, /* preconfiguration */ 126 ngx_http_limit_conn_add_variables, /* preconfiguration */
119 ngx_http_limit_conn_init, /* postconfiguration */ 127 ngx_http_limit_conn_init, /* postconfiguration */
120 128
121 NULL, /* create main configuration */ 129 NULL, /* create main configuration */
122 NULL, /* init main configuration */ 130 NULL, /* init main configuration */
123 131
143 NULL, /* exit master */ 151 NULL, /* exit master */
144 NGX_MODULE_V1_PADDING 152 NGX_MODULE_V1_PADDING
145 }; 153 };
146 154
147 155
156 static ngx_http_variable_t ngx_http_limit_conn_vars[] = {
157
158 { ngx_string("limit_conn_status"), NULL,
159 ngx_http_limit_conn_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
160
161 ngx_http_null_variable
162 };
163
164
165 static ngx_str_t ngx_http_limit_conn_status[] = {
166 ngx_string("PASSED"),
167 ngx_string("REJECTED"),
168 ngx_string("REJECTED_DRY_RUN")
169 };
170
171
148 static ngx_int_t 172 static ngx_int_t
149 ngx_http_limit_conn_handler(ngx_http_request_t *r) 173 ngx_http_limit_conn_handler(ngx_http_request_t *r)
150 { 174 {
151 size_t n; 175 size_t n;
152 uint32_t hash; 176 uint32_t hash;
159 ngx_http_limit_conn_node_t *lc; 183 ngx_http_limit_conn_node_t *lc;
160 ngx_http_limit_conn_conf_t *lccf; 184 ngx_http_limit_conn_conf_t *lccf;
161 ngx_http_limit_conn_limit_t *limits; 185 ngx_http_limit_conn_limit_t *limits;
162 ngx_http_limit_conn_cleanup_t *lccln; 186 ngx_http_limit_conn_cleanup_t *lccln;
163 187
164 if (r->main->limit_conn_set) { 188 if (r->main->limit_conn_status) {
165 return NGX_DECLINED; 189 return NGX_DECLINED;
166 } 190 }
167 191
168 lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module); 192 lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);
169 limits = lccf->limits.elts; 193 limits = lccf->limits.elts;
185 "is more than 255 bytes: \"%V\"", 209 "is more than 255 bytes: \"%V\"",
186 &ctx->key.value, &key); 210 &ctx->key.value, &key);
187 continue; 211 continue;
188 } 212 }
189 213
190 r->main->limit_conn_set = 1; 214 r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_PASSED;
191 215
192 hash = ngx_crc32_short(key.data, key.len); 216 hash = ngx_crc32_short(key.data, key.len);
193 217
194 shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; 218 shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
195 219
208 if (node == NULL) { 232 if (node == NULL) {
209 ngx_shmtx_unlock(&shpool->mutex); 233 ngx_shmtx_unlock(&shpool->mutex);
210 ngx_http_limit_conn_cleanup_all(r->pool); 234 ngx_http_limit_conn_cleanup_all(r->pool);
211 235
212 if (lccf->dry_run) { 236 if (lccf->dry_run) {
237 r->main->limit_conn_status =
238 NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN;
213 return NGX_DECLINED; 239 return NGX_DECLINED;
214 } 240 }
241
242 r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED;
215 243
216 return lccf->status_code; 244 return lccf->status_code;
217 } 245 }
218 246
219 lc = (ngx_http_limit_conn_node_t *) &node->color; 247 lc = (ngx_http_limit_conn_node_t *) &node->color;
239 &limits[i].shm_zone->shm.name); 267 &limits[i].shm_zone->shm.name);
240 268
241 ngx_http_limit_conn_cleanup_all(r->pool); 269 ngx_http_limit_conn_cleanup_all(r->pool);
242 270
243 if (lccf->dry_run) { 271 if (lccf->dry_run) {
272 r->main->limit_conn_status =
273 NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN;
244 return NGX_DECLINED; 274 return NGX_DECLINED;
245 } 275 }
276
277 r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED;
246 278
247 return lccf->status_code; 279 return lccf->status_code;
248 } 280 }
249 281
250 lc->conn++; 282 lc->conn++;
465 497
466 return NGX_OK; 498 return NGX_OK;
467 } 499 }
468 500
469 501
502 static ngx_int_t
503 ngx_http_limit_conn_status_variable(ngx_http_request_t *r,
504 ngx_http_variable_value_t *v, uintptr_t data)
505 {
506 if (r->main->limit_conn_status == 0) {
507 v->not_found = 1;
508 return NGX_OK;
509 }
510
511 v->valid = 1;
512 v->no_cacheable = 0;
513 v->not_found = 0;
514 v->len = ngx_http_limit_conn_status[r->main->limit_conn_status - 1].len;
515 v->data = ngx_http_limit_conn_status[r->main->limit_conn_status - 1].data;
516
517 return NGX_OK;
518 }
519
520
470 static void * 521 static void *
471 ngx_http_limit_conn_create_conf(ngx_conf_t *cf) 522 ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
472 { 523 {
473 ngx_http_limit_conn_conf_t *conf; 524 ngx_http_limit_conn_conf_t *conf;
474 525
672 return NGX_CONF_OK; 723 return NGX_CONF_OK;
673 } 724 }
674 725
675 726
676 static ngx_int_t 727 static ngx_int_t
728 ngx_http_limit_conn_add_variables(ngx_conf_t *cf)
729 {
730 ngx_http_variable_t *var, *v;
731
732 for (v = ngx_http_limit_conn_vars; v->name.len; v++) {
733 var = ngx_http_add_variable(cf, &v->name, v->flags);
734 if (var == NULL) {
735 return NGX_ERROR;
736 }
737
738 var->get_handler = v->get_handler;
739 var->data = v->data;
740 }
741
742 return NGX_OK;
743 }
744
745
746 static ngx_int_t
677 ngx_http_limit_conn_init(ngx_conf_t *cf) 747 ngx_http_limit_conn_init(ngx_conf_t *cf)
678 { 748 {
679 ngx_http_handler_pt *h; 749 ngx_http_handler_pt *h;
680 ngx_http_core_main_conf_t *cmcf; 750 ngx_http_core_main_conf_t *cmcf;
681 751