diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c index 806452296..6bd3e6a3b 100644 --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -10,6 +10,13 @@ #include +#define NGX_HTTP_LIMIT_REQ_PASSED 1 +#define NGX_HTTP_LIMIT_REQ_DELAYED 2 +#define NGX_HTTP_LIMIT_REQ_REJECTED 3 +#define NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN 4 +#define NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN 5 + + typedef struct { u_char color; u_char dummy; @@ -65,6 +72,8 @@ static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n); +static ngx_int_t ngx_http_limit_req_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -72,6 +81,7 @@ static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_limit_req_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); @@ -131,7 +141,7 @@ static ngx_command_t ngx_http_limit_req_commands[] = { static ngx_http_module_t ngx_http_limit_req_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_limit_req_add_variables, /* preconfiguration */ ngx_http_limit_req_init, /* postconfiguration */ NULL, /* create main configuration */ @@ -161,6 +171,24 @@ ngx_module_t ngx_http_limit_req_module = { }; +static ngx_http_variable_t ngx_http_limit_req_vars[] = { + + { ngx_string("limit_req_status"), NULL, + ngx_http_limit_req_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + ngx_http_null_variable +}; + + +static ngx_str_t ngx_http_limit_req_status[] = { + ngx_string("PASSED"), + ngx_string("DELAYED"), + ngx_string("REJECTED"), + ngx_string("DELAYED_DRY_RUN"), + ngx_string("REJECTED_DRY_RUN") +}; + + static ngx_int_t ngx_http_limit_req_handler(ngx_http_request_t *r) { @@ -173,7 +201,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) ngx_http_limit_req_conf_t *lrcf; ngx_http_limit_req_limit_t *limit, *limits; - if (r->main->limit_req_set) { + if (r->main->limit_req_status) { return NGX_DECLINED; } @@ -232,8 +260,6 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) return NGX_DECLINED; } - r->main->limit_req_set = 1; - if (rc == NGX_BUSY || rc == NGX_ERROR) { if (rc == NGX_BUSY) { @@ -261,9 +287,12 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) } if (lrcf->dry_run) { + r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN; return NGX_DECLINED; } + r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED; + return lrcf->status_code; } @@ -276,6 +305,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) delay = ngx_http_limit_req_account(limits, n, &excess, &limit); if (!delay) { + r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_PASSED; return NGX_DECLINED; } @@ -285,9 +315,12 @@ ngx_http_limit_req_handler(ngx_http_request_t *r) excess / 1000, excess % 1000, &limit->shm_zone->shm.name); if (lrcf->dry_run) { + r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN; return NGX_DECLINED; } + r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED; + if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -711,6 +744,25 @@ ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data) } +static ngx_int_t +ngx_http_limit_req_status_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->main->limit_req_status == 0) { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = ngx_http_limit_req_status[r->main->limit_req_status - 1].len; + v->data = ngx_http_limit_req_status[r->main->limit_req_status - 1].data; + + return NGX_OK; +} + + static void * ngx_http_limit_req_create_conf(ngx_conf_t *cf) { @@ -995,6 +1047,25 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +static ngx_int_t +ngx_http_limit_req_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_limit_req_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index fc29359f5..d19a389dc 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -513,7 +513,7 @@ struct ngx_http_request_s { * we use the single bits in the request structure */ unsigned limit_conn_set:1; - unsigned limit_req_set:1; + unsigned limit_req_status:3; unsigned limit_rate_set:1; unsigned limit_rate_after_set:1;