# Bug of discarding request body

**URL:** <https://www.ruby-forum.com/t/bug-of-discarding-request-body/243540>\
**Category:** NGINX\
**Created:** [December 2, 2015, 10:13am UTC](https://www.ruby-forum.com/t/bug-of-discarding-request-body/243540 "2015-12-02T10:13:24Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rafa\_F](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/958977/32.png) [@Rafa\_F](https://www.ruby-forum.com/u/Rafa_F)\
**Post date:** [December 2, 2015, 10:13am UTC](https://www.ruby-forum.com/t/bug-of-discarding-request-body/243540/1 "2015-12-02T10:13:24Z")

</div>

Hi, There:

```
 I run into a bug which I believe it is about

```

ngx\_http\_discard\_request\_body()  
(discard\_body() for short). This bug is reproducible using the 1.9.7  
release.

The discard\_body() discards request body by reading it. However,  
the if the body is not ready yet (i.e.  
ngx\_http\_read\_discarded\_request\_body()  
returns NGX\_AGAIN), it still return NGX\_OK.

ngx\_http\_special\_response\_handler() (special\_handler() for short)  
calls  
discard\_body(). If the discard\_body() returns NGX\_OK, it does _NOT_  
disable  
keepalive connection, in the meantime, it sends out the special response  
before the request body is completely discarded. This cause the problem!

# This is my setup to expose the bug:

My OS is Ubuntu 14.

a). the “backend” server have two locations, one return 200; the other  
one return 403  
b). the reverse proxy hook to the backend with:  
b1) keepalive  
b2) uploading is unbuffered;  
so we can send incomplete request to the backend, which is to  
mimic the situation  
when the body is not sent at all of somehow dealayed.  
b3) send incomplete POST request R1 to the ‘/bad’ relocation  
via "cat post\_bad.txt | nc -q -1 127.0.0.1 8080’  
b4) (much be quick) send another request R2 via “curl -X GET  
[http://localhost:8080/good](http://localhost:8080/good)”  
you may end up see 400 reponse.

# Observeration/Analysis:

```
If you strace the backend server, you will see it first send

```

403-response to  
the proxy, then call recvfrom() trying to get the body the R1.

```
The recvfrom() does not get the body of the R1, instead it gets the

```

leading  
part of the R2, and discard it.

```
The subsequent call to recvfrom() get the trailing part of the R2.

```

Nginx thought  
it is starting part of R2, and gives 400 response.

# Proposed Fix:

1. Make sure discard\_body() completely discard body before it sends  
the header

2. If discard\_body() does not complete, just return NGX\_AGAIN instead  
of  
NGX\_OK, whichyby special handler disable keepalive, making sure  
the boundary of requests are clean.

Please shed some light, lots thanks in advance!

Shuxin

====================================================  
Following is my setup:

1. proxy conf;

o. backend:  
server {  
listen 8081;  
proxy\_request\_buffering off; # dose not matter

```
     location /good {
         content_by_lua 'ngx.say("lol")';
     }

     location /bad1 {
         return 403;
     }
 }

```

o. incomplete request to the bad request  
cat post\_bad1.txt | nc -q -1 127.0.0.1 8080

The post\_bad1.txt is attached to this mail.

---

<div class="post-metadata">

**Author:** ![Shuxin\_Yang](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/9dc877/32.png) [@Shuxin\_Yang](https://www.ruby-forum.com/u/Shuxin_Yang)\
**Post date:** [December 3, 2015, 1:39am UTC](https://www.ruby-forum.com/t/bug-of-discarding-request-body/243540/2 "2015-12-03T01:39:25Z")

</div>

Hi, Maxim:

```
Thank you so much for your insightful comment!

Unbuffered-uploading not just to make things easier to reproduce the

```

problem.  
It is trivial. So to speak.

```
It is translating to say it is rather dangerous to use the

```

unbuffered-uploading along  
with keepalive connections, as the combination make the proxy server  
paper thin  
to penetrate.

Thanks  
Shuxin
