Mercurial > hg > nginx
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 |