[PATCH] Limit req: r/h and r/d support

Maxim Dounin mdounin at mdounin.ru
Fri Feb 16 16:52:25 UTC 2018


Hello!

On Fri, Feb 16, 2018 at 03:57:05PM +0100, Bernhard Reutner-Fischer wrote:

> Attached is a patch to add r/h and r/d limit_req support.
> 
> There are at least two feature requests that i found asking for this:
> - https://trac.nginx.org/nginx/ticket/68
> - https://trac.nginx.org/nginx/ticket/1060
> 
> Ok?
> 
> Please consider applying.

Do you use it yourself, or your patch is based on the feature 
requests in question?  If yes, what is your use case?

Some obvious problems with the patch outlined below.

> # HG changeset patch
> # User Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
> # Date 1518790589 -3600
> #      Fri Feb 16 15:16:29 2018 +0100
> # Node ID 4f5981016b6d3b4b9745f90ddf9521fa7a0d375f
> # Parent  a49af443656f2b65ca5de9d8cad5594f44e18ff7
> Limit req: r/h and r/d support

Style: please add a trailing dot.

> 
> diff -r a49af443656f -r 4f5981016b6d src/http/modules/ngx_http_limit_req_module.c
> --- a/src/http/modules/ngx_http_limit_req_module.c	Thu Feb 08 12:11:30 2018 +0300
> +++ b/src/http/modules/ngx_http_limit_req_module.c	Fri Feb 16 15:16:29 2018 +0100
> @@ -16,7 +16,7 @@
>      u_short                      len;
>      ngx_queue_t                  queue;
>      ngx_msec_t                   last;
> -    /* integer value, 1 corresponds to 0.001 r/s */
> +    /* integer value, 1 corresponds to 0.00001 r/s */
>      ngx_uint_t                   excess;
>      ngx_uint_t                   count;
>      u_char                       data[1];
> @@ -33,7 +33,7 @@
>  typedef struct {
>      ngx_http_limit_req_shctx_t  *sh;
>      ngx_slab_pool_t             *shpool;
> -    /* integer value, 1 corresponds to 0.001 r/s */
> +    /* integer value, 1 corresponds to 0.00001 r/s */
>      ngx_uint_t                   rate;

On 32-bit platforms this means that the maximum supported rate 
would be about ~40kr/s.  And I suspect this can hurt real setups.

[...]

> @@ -213,7 +213,7 @@
>  
>          ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
>                         "limit_req[%ui]: %i %ui.%03ui",
> -                       n, rc, excess / 1000, excess % 1000);
> +                       n, rc, excess / 100000, excess % 100000);

The "%ui.%03ui" format needs to be adjusted as well, here and in 
all other places.

[...]

> @@ -398,8 +398,9 @@
>              ngx_queue_insert_head(&ctx->sh->queue, &lr->queue);
>  
>              ms = (ngx_msec_int_t) (now - lr->last);
> +            ms = ngx_abs(ms);
>  
> -            excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000;
> +            excess = lr->excess - ctx->rate * ms * 100 / 100000 + 100000;

Just keeping "/ 1000" might be a better option, given it 
corresponds to milliseconds in the "ms" variable.

[...]

> @@ -527,7 +529,7 @@
>              continue;
>          }
>  
> -        delay = excess * 1000 / ctx->rate;
> +        delay = excess * 100000 / ctx->rate;
>  
>          if (delay > max_delay) {
>              max_delay = delay;
> @@ -535,7 +537,7 @@
>              *limit = &limits[n];
>          }
>      }
> -
> +    max_delay /= 100;
>      return max_delay;

It is not clear why calculate delay in different units instead of 
milliseconds as specified by the type used, and then convert it 
back to milliseconds.

[...]

> @@ -825,7 +835,11 @@
>          return NGX_CONF_ERROR;
>      }
>  
> -    ctx->rate = rate * 1000 / scale;
> +    ctx->rate = rate * 100000 / scale;
> +    if (ctx->rate < 1) {
> +        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid rate \"%ui\"", rate);
> +        return NGX_CONF_ERROR;
> +    }

The ctx->rate is unsigned, and the ctx->rate check will only fail 
if ctx->rate is 0.  While this might happen in some cases, it 
certainly won't catch all overflows (which are quite likely in 
real configurations on 32-bit platforms, see above).

Also, the "rate" type is ngx_int_t, so (rate * 100000) will cause 
integer overflow, which is not defined.  It might be a better idea 
to avoid overflows at all.

Also, the "rate" type is ngx_int_t, not ngx_uint_t, so proper 
format would be "%i". 

In general, it might be a better idea to move the check to 
ngx_atoi(), and test something like NGX_MAX_INT_T_VALUE / 100000.  
This will ensure no overflow can happen during calculations below, 
and will allow logging of the original value.  This will further 
limit maximum rate to about 20kr/s on 32-bit platforms though.

Note that I have no good solution for 32-bit platforms and the 
40kr/s (20kr/s) limit.

-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list