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";
       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

The disadvantage is that it may waste lots of resource in read-then-discard
     process.

  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.

     The disadvantage is that it compromise the performance the keepalive
     connections between backend and proxy.

Please shed some light, lots thanks in advance!

Shuxin



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

1. proxy conf;

    upstream backend {
        server 127.0.0.1:8081;
        keepalive 32;
    }

    server {
        listen 8080;
        proxy_request_buffering off;
        location / {
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_pass http://backend;
        }
    }

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.


















POST /bad1 HTTP/1.1
User-Agent: curl/7.35.0
Host: localhost:8088
Accept: */*
Content-Length: 8
Content-Type: application/x-www-form-urlencoded

_______________________________________________
nginx mailing list
[email protected]
http://mailman.nginx.org/mailman/listinfo/nginx

Reply via email to