Skip to content

Instantly share code, notes, and snippets.

@tksmd
Last active September 16, 2020 03:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tksmd/97aa35a556d9628c2eea to your computer and use it in GitHub Desktop.
Save tksmd/97aa35a556d9628c2eea to your computer and use it in GitHub Desktop.
nginx 1.2.x patch for limit_req module to return 429 (Too Many Requests) instead of 503 in case the number of requests in given amount of time excesses the configured rate. Besides, "Retry-After" header with the value calcurated from the rate will be added automatically in that case.
Only in nginx-1.2.9: Makefile
Only in nginx-1.2.9: objs
diff -Bbu -ur nginx-1.2.9-orig/src/http/modules/ngx_http_limit_req_module.c nginx-1.2.9/src/http/modules/ngx_http_limit_req_module.c
--- nginx-1.2.9-orig/src/http/modules/ngx_http_limit_req_module.c 2013-05-13 19:43:28.000000000 +0900
+++ nginx-1.2.9/src/http/modules/ngx_http_limit_req_module.c 2013-07-08 23:29:38.000000000 +0900
@@ -154,6 +154,9 @@
ngx_http_limit_req_ctx_t *ctx;
ngx_http_limit_req_conf_t *lrcf;
ngx_http_limit_req_limit_t *limit, *limits;
+ ngx_table_elt_t *h;
+ ngx_uint_t rate;
+ u_char *ra;
if (r->main->limit_req_set) {
return NGX_DECLINED;
@@ -163,6 +166,7 @@
limits = lrcf->limits.elts;
excess = 0;
+ rate = 0;
rc = NGX_DECLINED;
@@ -210,6 +214,7 @@
n, rc, excess / 1000, excess % 1000);
if (rc != NGX_AGAIN) {
+ rate = ctx->rate;
break;
}
}
@@ -227,6 +232,17 @@
"limiting requests, excess: %ui.%03ui by zone \"%V\"",
excess / 1000, excess % 1000,
&limit->shm_zone->shm.name);
+
+ if ( rate > 0 && (ra = ngx_pcalloc(r->pool, sizeof(u_char *))) != NULL){
+ h = ngx_list_push(&r->headers_out.headers);
+ if ( h != NULL ){
+ h->hash = 1;
+ ngx_str_set(&h->key, "Retry-After");
+ ngx_sprintf(ra, "%ui", (rate >= 1000) ? 1 : 1000/rate);
+ h->value.len = ngx_strlen(ra);
+ h->value.data = ra;
+ }
+ }
}
while (n--) {
@@ -245,7 +261,7 @@
ctx->node = NULL;
}
- return NGX_HTTP_SERVICE_UNAVAILABLE;
+ return (rc == NGX_BUSY) ? NGX_HTTP_TOO_MANY_REQUESTS : NGX_HTTP_SERVICE_UNAVAILABLE;
}
/* rc == NGX_AGAIN || rc == NGX_OK */
diff -Bbu -ur nginx-1.2.9-orig/src/http/ngx_http_header_filter_module.c nginx-1.2.9/src/http/ngx_http_header_filter_module.c
--- nginx-1.2.9-orig/src/http/ngx_http_header_filter_module.c 2013-05-13 19:43:28.000000000 +0900
+++ nginx-1.2.9/src/http/ngx_http_header_filter_module.c 2013-07-03 09:58:52.000000000 +0900
@@ -99,16 +99,23 @@
ngx_string("415 Unsupported Media Type"),
ngx_string("416 Requested Range Not Satisfiable"),
- /* ngx_null_string, */ /* "417 Expectation Failed" */
- /* ngx_null_string, */ /* "418 unused" */
- /* ngx_null_string, */ /* "419 unused" */
- /* ngx_null_string, */ /* "420 unused" */
- /* ngx_null_string, */ /* "421 unused" */
- /* ngx_null_string, */ /* "422 Unprocessable Entity" */
- /* ngx_null_string, */ /* "423 Locked" */
- /* ngx_null_string, */ /* "424 Failed Dependency" */
+ ngx_null_string, /* "417 Expectation Failed" */
+ ngx_null_string, /* "418 I'm a teapot" */
+ ngx_null_string, /* "419 unused" */
+ ngx_null_string, /* "420 unused" */
+ ngx_null_string, /* "421 unused" */
+ ngx_null_string, /* "422 Unprocessable Entity" */
+ ngx_null_string, /* "423 Locked" */
+ ngx_null_string, /* "424 Failed Dependency" */
+ ngx_null_string, /* "425 No code" */
+ ngx_null_string, /* "426 Upgrade Required" */
+ ngx_null_string, /* "427 unused" */
+ ngx_null_string, /* "428 Precondition Required" */
+ ngx_string("429 Too Many Requests"),
+ ngx_null_string, /* "430 unused" */
+ ngx_null_string, /* "431 Request Header Fields Too Large" */
-#define NGX_HTTP_LAST_4XX 417
+#define NGX_HTTP_LAST_4XX 432
#define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
ngx_string("500 Internal Server Error"),
diff -Bbu -ur nginx-1.2.9-orig/src/http/ngx_http_request.h nginx-1.2.9/src/http/ngx_http_request.h
--- nginx-1.2.9-orig/src/http/ngx_http_request.h 2013-05-13 19:43:28.000000000 +0900
+++ nginx-1.2.9/src/http/ngx_http_request.h 2013-07-03 09:58:52.000000000 +0900
@@ -91,6 +91,7 @@
#define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE 415
#define NGX_HTTP_RANGE_NOT_SATISFIABLE 416
+#define NGX_HTTP_TOO_MANY_REQUESTS 429
/* Our own HTTP codes */
diff -Bbu -ur nginx-1.2.9-orig/src/http/ngx_http_special_response.c nginx-1.2.9/src/http/ngx_http_special_response.c
--- nginx-1.2.9-orig/src/http/ngx_http_special_response.c 2013-05-13 19:43:28.000000000 +0900
+++ nginx-1.2.9/src/http/ngx_http_special_response.c 2013-07-03 09:58:52.000000000 +0900
@@ -334,8 +334,23 @@
ngx_string(ngx_http_error_414_page),
ngx_string(ngx_http_error_415_page),
ngx_string(ngx_http_error_416_page),
+ ngx_null_string, /* 417 */
+ ngx_null_string, /* 418 */
+ ngx_null_string, /* 419 */
+ ngx_null_string, /* 429 */
+ ngx_null_string, /* 421 */
+ ngx_null_string, /* 422 */
+ ngx_null_string, /* 423 */
+ ngx_null_string, /* 424 */
+ ngx_null_string, /* 425 */
+ ngx_null_string, /* 426 */
+ ngx_null_string, /* 427 */
+ ngx_null_string, /* 428 */
+ ngx_null_string, /* 429 */
+ ngx_null_string, /* 430 */
+ ngx_null_string, /* 431 */
-#define NGX_HTTP_LAST_4XX 417
+#define NGX_HTTP_LAST_4XX 432
#define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
ngx_string(ngx_http_error_494_page), /* 494, request header too large */
@tksmd
Copy link
Author

tksmd commented Jul 10, 2013

How To apply this patch

$ wget http://nginx.org/download/nginx-1.2.9.tar.gz
$ wget --no-check-certificate -O - https://gist.github.com/tksmd/97aa35a556d9628c2eea/download | gunzip  > nginx-1.2.x-too-many-requests-retryafter.patch
$ tar zxvf nginx-1.2.9.tar.gz
$ cd nginx-1.2.9
$ patch -p1 < ../nginx-1.2.x-too-many-requests-retryafter.patch
$ ./configure
$ make

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment