comparison src/http/modules/ngx_http_limit_req_module.c @ 7592:776d1bebdca2

Limit req: $limit_req_status variable. The variable takes one of the values: PASSED, DELAYED, REJECTED, DELAYED_DRY_RUN or REJECTED_DRY_RUN.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 06 Nov 2019 19:03:18 +0300
parents 2db68852d6a0
children 559d19037984
comparison
equal deleted inserted replaced
7591:89adf49fe76a 7592:776d1bebdca2
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_REQ_PASSED 1
14 #define NGX_HTTP_LIMIT_REQ_DELAYED 2
15 #define NGX_HTTP_LIMIT_REQ_REJECTED 3
16 #define NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN 4
17 #define NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN 5
11 18
12 19
13 typedef struct { 20 typedef struct {
14 u_char color; 21 u_char color;
15 u_char dummy; 22 u_char dummy;
63 static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, 70 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); 71 ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit);
65 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, 72 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx,
66 ngx_uint_t n); 73 ngx_uint_t n);
67 74
75 static ngx_int_t ngx_http_limit_req_status_variable(ngx_http_request_t *r,
76 ngx_http_variable_value_t *v, uintptr_t data);
68 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); 77 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf);
69 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, 78 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent,
70 void *child); 79 void *child);
71 static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, 80 static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd,
72 void *conf); 81 void *conf);
73 static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, 82 static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd,
74 void *conf); 83 void *conf);
84 static ngx_int_t ngx_http_limit_req_add_variables(ngx_conf_t *cf);
75 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); 85 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf);
76 86
77 87
78 static ngx_conf_enum_t ngx_http_limit_req_log_levels[] = { 88 static ngx_conf_enum_t ngx_http_limit_req_log_levels[] = {
79 { ngx_string("info"), NGX_LOG_INFO }, 89 { ngx_string("info"), NGX_LOG_INFO },
129 ngx_null_command 139 ngx_null_command
130 }; 140 };
131 141
132 142
133 static ngx_http_module_t ngx_http_limit_req_module_ctx = { 143 static ngx_http_module_t ngx_http_limit_req_module_ctx = {
134 NULL, /* preconfiguration */ 144 ngx_http_limit_req_add_variables, /* preconfiguration */
135 ngx_http_limit_req_init, /* postconfiguration */ 145 ngx_http_limit_req_init, /* postconfiguration */
136 146
137 NULL, /* create main configuration */ 147 NULL, /* create main configuration */
138 NULL, /* init main configuration */ 148 NULL, /* init main configuration */
139 149
159 NULL, /* exit master */ 169 NULL, /* exit master */
160 NGX_MODULE_V1_PADDING 170 NGX_MODULE_V1_PADDING
161 }; 171 };
162 172
163 173
174 static ngx_http_variable_t ngx_http_limit_req_vars[] = {
175
176 { ngx_string("limit_req_status"), NULL,
177 ngx_http_limit_req_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
178
179 ngx_http_null_variable
180 };
181
182
183 static ngx_str_t ngx_http_limit_req_status[] = {
184 ngx_string("PASSED"),
185 ngx_string("DELAYED"),
186 ngx_string("REJECTED"),
187 ngx_string("DELAYED_DRY_RUN"),
188 ngx_string("REJECTED_DRY_RUN")
189 };
190
191
164 static ngx_int_t 192 static ngx_int_t
165 ngx_http_limit_req_handler(ngx_http_request_t *r) 193 ngx_http_limit_req_handler(ngx_http_request_t *r)
166 { 194 {
167 uint32_t hash; 195 uint32_t hash;
168 ngx_str_t key; 196 ngx_str_t key;
171 ngx_msec_t delay; 199 ngx_msec_t delay;
172 ngx_http_limit_req_ctx_t *ctx; 200 ngx_http_limit_req_ctx_t *ctx;
173 ngx_http_limit_req_conf_t *lrcf; 201 ngx_http_limit_req_conf_t *lrcf;
174 ngx_http_limit_req_limit_t *limit, *limits; 202 ngx_http_limit_req_limit_t *limit, *limits;
175 203
176 if (r->main->limit_req_set) { 204 if (r->main->limit_req_status) {
177 return NGX_DECLINED; 205 return NGX_DECLINED;
178 } 206 }
179 207
180 lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); 208 lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module);
181 limits = lrcf->limits.elts; 209 limits = lrcf->limits.elts;
229 } 257 }
230 258
231 if (rc == NGX_DECLINED) { 259 if (rc == NGX_DECLINED) {
232 return NGX_DECLINED; 260 return NGX_DECLINED;
233 } 261 }
234
235 r->main->limit_req_set = 1;
236 262
237 if (rc == NGX_BUSY || rc == NGX_ERROR) { 263 if (rc == NGX_BUSY || rc == NGX_ERROR) {
238 264
239 if (rc == NGX_BUSY) { 265 if (rc == NGX_BUSY) {
240 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, 266 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
259 285
260 ctx->node = NULL; 286 ctx->node = NULL;
261 } 287 }
262 288
263 if (lrcf->dry_run) { 289 if (lrcf->dry_run) {
290 r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;
264 return NGX_DECLINED; 291 return NGX_DECLINED;
265 } 292 }
293
294 r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED;
266 295
267 return lrcf->status_code; 296 return lrcf->status_code;
268 } 297 }
269 298
270 /* rc == NGX_AGAIN || rc == NGX_OK */ 299 /* rc == NGX_AGAIN || rc == NGX_OK */
274 } 303 }
275 304
276 delay = ngx_http_limit_req_account(limits, n, &excess, &limit); 305 delay = ngx_http_limit_req_account(limits, n, &excess, &limit);
277 306
278 if (!delay) { 307 if (!delay) {
308 r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_PASSED;
279 return NGX_DECLINED; 309 return NGX_DECLINED;
280 } 310 }
281 311
282 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, 312 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
283 "delaying request%s, excess: %ui.%03ui, by zone \"%V\"", 313 "delaying request%s, excess: %ui.%03ui, by zone \"%V\"",
284 lrcf->dry_run ? ", dry run" : "", 314 lrcf->dry_run ? ", dry run" : "",
285 excess / 1000, excess % 1000, &limit->shm_zone->shm.name); 315 excess / 1000, excess % 1000, &limit->shm_zone->shm.name);
286 316
287 if (lrcf->dry_run) { 317 if (lrcf->dry_run) {
318 r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN;
288 return NGX_DECLINED; 319 return NGX_DECLINED;
289 } 320 }
321
322 r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED;
290 323
291 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { 324 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
292 return NGX_HTTP_INTERNAL_SERVER_ERROR; 325 return NGX_HTTP_INTERNAL_SERVER_ERROR;
293 } 326 }
294 327
709 742
710 return NGX_OK; 743 return NGX_OK;
711 } 744 }
712 745
713 746
747 static ngx_int_t
748 ngx_http_limit_req_status_variable(ngx_http_request_t *r,
749 ngx_http_variable_value_t *v, uintptr_t data)
750 {
751 if (r->main->limit_req_status == 0) {
752 v->not_found = 1;
753 return NGX_OK;
754 }
755
756 v->valid = 1;
757 v->no_cacheable = 0;
758 v->not_found = 0;
759 v->len = ngx_http_limit_req_status[r->main->limit_req_status - 1].len;
760 v->data = ngx_http_limit_req_status[r->main->limit_req_status - 1].data;
761
762 return NGX_OK;
763 }
764
765
714 static void * 766 static void *
715 ngx_http_limit_req_create_conf(ngx_conf_t *cf) 767 ngx_http_limit_req_create_conf(ngx_conf_t *cf)
716 { 768 {
717 ngx_http_limit_req_conf_t *conf; 769 ngx_http_limit_req_conf_t *conf;
718 770
994 return NGX_CONF_OK; 1046 return NGX_CONF_OK;
995 } 1047 }
996 1048
997 1049
998 static ngx_int_t 1050 static ngx_int_t
1051 ngx_http_limit_req_add_variables(ngx_conf_t *cf)
1052 {
1053 ngx_http_variable_t *var, *v;
1054
1055 for (v = ngx_http_limit_req_vars; v->name.len; v++) {
1056 var = ngx_http_add_variable(cf, &v->name, v->flags);
1057 if (var == NULL) {
1058 return NGX_ERROR;
1059 }
1060
1061 var->get_handler = v->get_handler;
1062 var->data = v->data;
1063 }
1064
1065 return NGX_OK;
1066 }
1067
1068
1069 static ngx_int_t
999 ngx_http_limit_req_init(ngx_conf_t *cf) 1070 ngx_http_limit_req_init(ngx_conf_t *cf)
1000 { 1071 {
1001 ngx_http_handler_pt *h; 1072 ngx_http_handler_pt *h;
1002 ngx_http_core_main_conf_t *cmcf; 1073 ngx_http_core_main_conf_t *cmcf;
1003 1074