HttpLimitReqModule delivers "nginx/1.4.3" as a message for HTTP status code 429. Too generic!

Hi,

I’m doing this: limit_req_status 429;

The module HttpLimitReqModule delivers “nginx/1.4.3” (at least with
version
1.4.3) as a message for the HTTP status code 429. That is too generic
and
not useful at all. Why doesn’t it deliver a “Too Many Requests” message
instead of that? It is absurd, useless.

Not only that, but the HTML response that comes with an HTTP 503 status
(the
default status when they exceed the limits) is something descriptive,
that
informs the HTTP status code and message. But with the HTTP status code
429
we get an empty HTML response!

Can this be solved?

Brian

Posted at Nginx Forum:

On Sat, Oct 26, 2013 at 11:43:29PM -0400, Brian08275660 wrote:

Hi there,

The module HttpLimitReqModule delivers “nginx/1.4.3” (at least with version
1.4.3) as a message for the HTTP status code 429. That is too generic and
not useful at all.

Are you reporting that nginx generates a malformed response?

Or are you reporting that your http client handles a well-formed
response
poorly?

The first sounds like something patchable in nginx. The second doesn’t.

But with the HTTP status code 429
we get an empty HTML response!

Module ngx_http_core_module ?

f

Francis D. [email protected]

Hi Francis,

I think I’m actually reporting a malformed response, it is Nginx that
send
“nginx/1.4.3” instead of something useful as “too many requests”. I have
tested it with Firefox and there is no doubt. Also tested it with a java
HTTP client component, the same result. The status code received is
correct
(429), but not the message that comes with it.

I had just discovered the “error_page” directive after I sent the email,
I
will create it, thanks. It is easy to do it. But why doesn’t nginx
deliver a
default HTML response for 429, as it does for 503 and other codes? Why
the
empty page? It would make more sense to deliver the typical simple
response,
and that we could customize it with “error_page” if we wanted something
more
special.

Brian

Posted at Nginx Forum:

On 27 October 2013 13:40, Brian08275660 [email protected] wrote:

I think I’m actually reporting a malformed response, it is Nginx that send
“nginx/1.4.3” instead of something useful as “too many requests”.

Please show the complete output of “curl -v <429-uri>”.

I don’t see any visible output from a 429 with nginx 1.4.1 - I just
see an empty response body.

J

This is the output:

root@ip-10-139-33-71:~# curl -v

GET /location/locate-ip?key=BBANBWEDS7UZ6FD8747F76VZ&ip=201.1.1.1
HTTP/1.1
User-Agent: curl/7.22.0 (i686-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1
zlib/1.2.3.4 libidn/1.23 librtmp/2.3
Host: api.xxxxxxxxxxxx.com
Accept: /

< HTTP/1.1 429 nginx/1.4.3
<-----------------------------------------THIS
IS WRONG
< Date: Sun, 27 Oct 2013 17:12:42 GMT
< Content-Length: 0
< Connection: keep-alive
<

Please look the line I’m considering wrong. After “429” it says
“nginx/1.4.3”, whereas it shoud say “too many connections” or something
like
that.

The HTML output is empty, certainly. I can customize that with the
“error_page” directive so that not a big problem (even though I think it
should deliver a standard non-empty response explaning the 429 code).

Posted at Nginx Forum:

Hi!

What you have shown looks well-formed to me, but doesn’t look as useful
as you want. (They are different things. If it is a well-formed http
429 response, then it is the client’s job to know what that means. The
reason-phrase and the http body content are optional enhancements that
the server can choose to send. According to my reading of RFC 2616.)

What is confusing is that when I do something similar, I get different
output which does not look well-formed to me:

I think nginx is returning the same thing for you both, and that curl
fails to parse this bogus HTTP response (maybe you are using different
curl releases).

If we look again at Brian’s curl output, we don’t see any Server header
in the response, which is not configurable in nginx afaik:

< HTTP/1.1 429 nginx/1.4.3 <— THIS IS WRONG
< Date: Sun, 27 Oct 2013 17:12:42 GMT
< Content-Length: 0
< Connection: keep-alive

From rfc2616#section-6.1 [1]:

6.1 Status-Line

The first line of a Response message is the Status-Line, consisting
of the protocol version followed by a numeric status code and its
associated textual phrase, with each element separated by SP
characters. No CR or LF is allowed except in the final CRLF sequence.

Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

While nginx seems to return:
HTTP-Version SP Status-Code CRLF

as per Francis’ output.

The Reason-Phrase clearly is a hard requirement and cannot be omitted.

Regards,

Lukas

[1] RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1

On Sun, Oct 27, 2013 at 09:40:11AM -0400, Brian08275660 wrote:

Hi there,

I think I’m actually reporting a malformed response, it is Nginx that send
“nginx/1.4.3” instead of something useful as “too many requests”.

This is quite confusing to me.

What you have shown looks well-formed to me, but doesn’t look as useful
as you want. (They are different things. If it is a well-formed http
429 response, then it is the client’s job to know what that means. The
reason-phrase and the http body content are optional enhancements that
the server can choose to send. According to my reading of RFC 2616.)

What is confusing is that when I do something similar, I get different
output which does not look well-formed to me:

===
$ curl -i -s http://localhost:8000/a.html | od -bc | head -n 6
0000000 110 124 124 120 057 061 056 061 040 064 062 071 015 012 123 145
H T T P / 1 . 1 4 2 9 \r \n S e
0000020 162 166 145 162 072 040 156 147 151 156 170 057 061 056 064 056
r v e r : n g i n x / 1 . 4 .
0000040 063 015 012 104 141 164 145 072 040 123 165 156 054 040 062 067
3 \r \n D a t e : S u n , 2 7

The lack of a space immediately following “429” up there looks incorrect
to me.

This is when using:

===
$ sbin/nginx -V
nginx version: nginx/1.4.3
built by gcc 4.4.5 (Debian 4.4.5-8)
configure arguments: --with-debug

$ cat conf/nginx.conf

events {
worker_connections 1024;
debug_connection 127.0.0.1;
}

http {
limit_req_zone $binary_remote_addr zone=zone1:128m rate=1r/m;

limit_req_status 429;
server {
    location = /a.html {
        limit_req zone=zone1 nodelay;
    }
}

}

I have
tested it with Firefox and there is no doubt. Also tested it with a java
HTTP client component, the same result. The status code received is correct
(429), but not the message that comes with it.

The message is irrelevant from a correctness point of view.

I had just discovered the “error_page” directive after I sent the email, I
will create it, thanks. It is easy to do it. But why doesn’t nginx deliver a
default HTML response for 429, as it does for 503 and other codes?

My guess is that nginx doesn’t claim to support whichever standard
defines code 429; so as far as nginx is concerned, you using it is just
like you using, say, code 477. It’s a number you choose, so you get to
ensure that the client can handle it.

(It seems to be RFC 6585, currently “Proposed Standard”, that defines
429.)

Now I think that it would probably be nice if there were a way to
provide a reason-phrase alongside a status code in nginx. I’m sure that
if somebody cares enough, a patch will be forthcoming.

And if we can find out why the response that you get and the response
that I get differ, and if it turns out that the one that is generated
by pure-nginx is actually malformed and causes a client that matters to
break, then that may become patched too.

But the response you get looks correct to me, for a status code that
nginx
doesn’t know about. The client knows it is a client error (400-series);
if the client supports RFC 6585 is also knows that it means “Too Many
Requests”; and if it doesn’t, it can show the body that you choose to
send with error_page so that the user can work out what it means.

f

Francis D. [email protected]

On Sun, Oct 27, 2013 at 09:45:40PM +0100, Lukas T. wrote:

Hi there,

What you have shown looks well-formed to me, but doesn’t look as useful
as you want.

What is confusing is that when I do something similar, I get different
output which does not look well-formed to me:

I think nginx is returning the same thing for you both, and that curl
fails to parse this bogus HTTP response (maybe you are using different
curl releases).

If curl isn’t showing exactly what is being returned, that would be
disappointing. I guess we could test with “nc” or “tcpdump” if
necessary.

Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

While nginx seems to return:
HTTP-Version SP Status-Code CRLF

as per Francis’ output.

The Reason-Phrase clearly is a hard requirement and cannot be omitted.

It can’t be omitted, but it can be zero-length. The SP before it looks
to be the part that shouldn’t be omitted.

It looks like a straightforward fix:

diff -pru nginx-1.4.3/src/http/ngx_http_header_filter_module.c
nginx-1.4.3-wip/src/http/ngx_http_header_filter_module.c
— nginx-1.4.3/src/http/ngx_http_header_filter_module.c 2013-10-08
13:07:14.000000000 +0100
+++ nginx-1.4.3/src/http/ngx_http_header_filter_module.c 2013-10-27
21:25:20.693842199 +0000
@@ -448,7 +448,7 @@ ngx_http_header_filter(ngx_http_request_
b->last = ngx_copy(b->last, status_line->data,
status_line->len);

 } else {
  •    b->last = ngx_sprintf(b->last, "%03ui", status);
    
  •    b->last = ngx_sprintf(b->last, "%03ui ", status);
    
    }
    *b->last++ = CR; *b->last++ = LF;

I think that line 270 in the file, which currently says

len += NGX_INT_T_LEN;

should probably currently say something like

len += 3; /* sizeof("404") */

and should be changed to say something like

len += 4; /* sizeof("404 ") */

but since NGX_INT_T_LEN is at least 4 anyway, len is big enough to hold
the extra space without changing that line.

Extra eyes to ensure I’ve not done something stupid are welcome.

f

Francis D. [email protected]

Nginx has actually no support for the 429 code. Either you fix it by
proposing a patch to support the error page in core or you use an
error_page directive.

error_page 429 @toomany;

 location @toomany {
     return 429 'Too many requests.\n';
 }

Just a simple example.
Le 28 oct. 2013 00:25, “Brian08275660” [email protected] a crit :

Hi Francis,

Probably I shouldn’t have said “malformed” when I chose a word to
express
the problem with the response. But I assumed that Nginx should show the
phrase that corresponds to the code. I assumed that Nginx has been coded
so
it know that 429 means “Too Many Requests” and that we should receive
that
string instead of the generic -and not very useful- string
“Nginx/”. I just expected Nginx to behave with http status 429
as
it does with http status 503.
I agree that the client should know what to do. In fact, the most
important
thing is the code, and that is being delivered perfectly. I just think
the
explanation would be useful.

I don’t know why your output is different than mine. Weird!

I know that I chose to send 429 to the client, yes, but given that 429
means
“too many requests” for the whole world (I mean, its not a status that I
haven just invented), wouldn’t it be nice if Nginx considers this and
delivers the correct phrase?

Brian

Posted at Nginx Forum: