[PATCH] Limit req, Limit conn: The "off" parameter of the 'limit_conn' and 'limit_req' directives

Maxim Dounin mdounin at mdounin.ru
Sun Feb 7 16:40:41 UTC 2016


Hello!

On Sun, Feb 07, 2016 at 03:32:42PM +0600, Pavel V. Rochnyack wrote:

> # HG changeset patch
> # User Pavel V. Rochnyack <pavel2000 at ngs.ru>
> # Date 1454835814 -21600
> # Node ID f7caa68ea80358a035ab766bdb62676522ec529f
> # Parent  3577c021f21eb4de6d09c1d624ba77ee9ee1eb6d
> Limit req, Limit conn: The "off" parameter of the 'limit_conn' and 'limit_req' directives.
> 
> Added support for inherited "limit_conn" and "limit_req" directives disable.

Please re-read http://nginx.org/en/docs/contributing_changes.html.  
In particular:

: maximum text width is 80 characters
...
: The commit message should have a single-line synopsis followed 
: by verbose description after an empty line. It is desirable that 
: the first line is no longer than 67 symbols.

In this particular case I would also recommend to split the patch 
into two separate patches: one for limit req, and another one for 
limit conn.

> diff -r 3577c021f21e -r f7caa68ea803 src/http/modules/ngx_http_limit_conn_module.c
> --- a/src/http/modules/ngx_http_limit_conn_module.c	Fri Feb 05 21:48:25 2016 +0300
> +++ b/src/http/modules/ngx_http_limit_conn_module.c	Sun Feb 07 15:03:34 2016 +0600
> @@ -40,6 +40,7 @@

Please add

[diff]
showfunc=1

to your ~/.hgrc file, this generally simplifies review process.

>      ngx_array_t                limits;
>      ngx_uint_t                 log_level;
>      ngx_uint_t                 status_code;
> +    ngx_uint_t                 off;     /* unsigned  off:1 */
>  } ngx_http_limit_conn_conf_t;

Indentation of the "/* unsigned  off:1 */" looks wrong.

>  
>  
> @@ -82,7 +83,7 @@
>        NULL },
>  
>      { ngx_string("limit_conn"),
> -      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
> +      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
>        ngx_http_limit_conn,
>        NGX_HTTP_LOC_CONF_OFFSET,
>        0,
> @@ -160,6 +161,10 @@
>      lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module);
>      limits = lccf->limits.elts;
>  
> +    if (lccf->off) {
> +        return NGX_DECLINED;
> +    }
> +
>      for (i = 0; i < lccf->limits.nelts; i++) {
>          ctx = limits[i].shm_zone->data;
>  
> @@ -466,6 +471,7 @@
>  
>      conf->log_level = NGX_CONF_UNSET_UINT;
>      conf->status_code = NGX_CONF_UNSET_UINT;
> +    conf->off = NGX_CONF_UNSET_UINT;
>  
>      return conf;
>  }
> @@ -478,6 +484,7 @@
>      ngx_http_limit_conn_conf_t *conf = child;
>  
>      if (conf->limits.elts == NULL) {
> +        ngx_conf_merge_uint_value(conf->off, prev->off, 0);
>          conf->limits = prev->limits;
>      }
>  

See no reasons why limits from previous level should be meged if 
"off" is used on the current level.  It's just unneeded work, 
which also add complexity in other places (like a need to check 
off at runtime, and merge off values from previous levels).

Better approach would be to don't inherit limits if "off" is set 
on the current level.

> @@ -603,6 +610,13 @@
>  
>      value = cf->args->elts;
>  
> +    lccf->off = 0;
> +
> +    if (ngx_strcmp(value[1].data, "off") == 0 && cf->args->nelts == 2) {
> +        lccf->off = 1;
> +        return NGX_CONF_OK;
> +    }
> +
>      shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
>                                       &ngx_http_limit_conn_module);
>      if (shm_zone == NULL) {

This variant of the code doesn't check "off" if additional 
arguments are used.  Limit req's version however does (and 
complains if number of arguments is incorrect).  Reasons for the 
difference are not clear.

With this code something like "limit_conn foo" will try to access 
value[2] unconditionally, potentially resulting in segmentation 
fault during configuration parsing.

This code silently allows "limit_conn off" to be used multiple 
times, as well as with other limit_conn directives.  This leads to 
a situation where:

   limit_conn off;
   limit_conn foo 10;

will not use "limit_conn foo 10" configured without any 
indication, which looks incorrect and confusing.  It should either 
complain, or use limits configured.

> diff -r 3577c021f21e -r f7caa68ea803 src/http/modules/ngx_http_limit_req_module.c
> --- a/src/http/modules/ngx_http_limit_req_module.c	Fri Feb 05 21:48:25 2016 +0300
> +++ b/src/http/modules/ngx_http_limit_req_module.c	Sun Feb 07 15:03:34 2016 +0600
> @@ -53,6 +53,7 @@
>      ngx_uint_t                   limit_log_level;
>      ngx_uint_t                   delay_log_level;
>      ngx_uint_t                   status_code;
> +    ngx_uint_t                   off;     /* unsigned  off:1 */
>  } ngx_http_limit_req_conf_t;
>  
>  
> @@ -172,6 +173,10 @@
>      lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module);
>      limits = lrcf->limits.elts;
>  
> +    if (lrcf->off) {
> +        return NGX_DECLINED;
> +    }
> +
>      excess = 0;
>  
>      rc = NGX_DECLINED;
> @@ -698,6 +703,7 @@
>  
>      conf->limit_log_level = NGX_CONF_UNSET_UINT;
>      conf->status_code = NGX_CONF_UNSET_UINT;
> +    conf->off = NGX_CONF_UNSET_UINT;
>  
>      return conf;
>  }
> @@ -710,6 +716,7 @@
>      ngx_http_limit_req_conf_t *conf = child;
>  
>      if (conf->limits.elts == NULL) {
> +        ngx_conf_merge_uint_value(conf->off, prev->off, 0);
>          conf->limits = prev->limits;
>      }
>  
> @@ -870,6 +877,19 @@
>  
>      value = cf->args->elts;
>  
> +    lrcf->off = 0;
> +
> +    if (ngx_strcmp(value[1].data, "off") == 0) {
> +        lrcf->off = 1;
> +        if (cf->args->nelts == 2) {
> +            return NGX_CONF_OK;
> +        }
> +
> +        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> +                           "invalid parameter \"%V\"", &value[2]);
> +        return NGX_CONF_ERROR;
> +    }
> +
>      shm_zone = NULL;
>      burst = 0;
>      nodelay = 0;

See comments for the limit_conn part of the patch, most of them 
apply here as well.

-- 
Maxim Dounin
http://nginx.org/



More information about the nginx-devel mailing list