Re: POST with x-www-form-urlencoded Content-Type

2014-07-10 Thread Willy Tarreau
Hi Dan,

On Wed, Jul 09, 2014 at 07:13:33PM +, Daniel Dubovik wrote:
 Hello all,
 
 I am attempting to balance traffic to a number of backend instances.  I am
 balancing based off the Host header, and for the most part everything is
 working.  When testing a bit more today, I came across some weird behavior,
 and am hoping someone can help out.  When POSTing to a site, if it is done
 using the Content-Type application/x-www-form-urlencoded, and has actual
 data, HAProxy falls back to a roundrobin balancing scheme.  POSTing using a
 Content-Type of multipart/form-data, however, works just fine.  Oddly,
 application/x-www-form-urlencoded with no actual data, also works as
 expected.

(...)

There's indeed a bug, the amount of data forwarded is not deduced correctly
to rewind the buffer, I'm even wondering if it's expected that we let them
pass at this point. I'm investigating, thanks for your report!

Willy




Re: POST with x-www-form-urlencoded Content-Type

2014-07-10 Thread Willy Tarreau
Hi Dan,

On Thu, Jul 10, 2014 at 05:20:18PM +0200, Willy Tarreau wrote:
 Hi Dan,
 
 On Wed, Jul 09, 2014 at 07:13:33PM +, Daniel Dubovik wrote:
  Hello all,
  
  I am attempting to balance traffic to a number of backend instances.  I am
  balancing based off the Host header, and for the most part everything is
  working.  When testing a bit more today, I came across some weird behavior,
  and am hoping someone can help out.  When POSTing to a site, if it is done
  using the Content-Type application/x-www-form-urlencoded, and has actual
  data, HAProxy falls back to a roundrobin balancing scheme.  POSTing using a
  Content-Type of multipart/form-data, however, works just fine.  Oddly,
  application/x-www-form-urlencoded with no actual data, also works as
  expected.
 
 (...)
 
 There's indeed a bug, the amount of data forwarded is not deduced correctly
 to rewind the buffer, I'm even wondering if it's expected that we let them
 pass at this point. I'm investigating, thanks for your report!

OK I could fix it. The patch is very small but it required some extra care
because that's a sensible area that I already fixed in dev23 but not enough.
Other balancing algorithms are affected, and worse, http-send-name-header
was bogus as well in this case.

I've applied the fix, I'm attaching it here, it applies both to 1.5 and to
1.6.

Thanks for your report, that was a nasty one and I'm glad we got rid of it
early!

Willy

From bb2e669f9e73531ac9cc9277b40066b701eec918 Mon Sep 17 00:00:00 2001
From: Willy Tarreau w...@1wt.eu
Date: Thu, 10 Jul 2014 19:06:10 +0200
Subject: BUG/MAJOR: http: correctly rewind the request body after start of
 forwarding

Daniel Dubovik reported an interesting bug showing that the request body
processing was still not 100% fixed. If a POST request contained short
enough data to be forwarded at once before trying to establish the
connection to the server, we had no way to correctly rewind the body.

The first visible case is that balancing on a header does not always work
on such POST requests since the header cannot be found. But there are even
nastier implications which are that http-send-name-header would apply to
the wrong location and possibly even affect part of the request's body
due to an incorrect rewinding.

There are two options to fix the problem :
  - first one is to force the HTTP_MSG_F_WAIT_CONN flag on all hash-based
balancing algorithms and http-send-name-header, but there's always a
risk that any new algorithm forgets to set it ;

  - the second option is to account for the amount of skipped data before
the connection establishes so that we always know the position of the
request's body relative to the buffer's origin.

The second option is much more reliable and fits very well in the spirit
of the past changes to fix forwarding. Indeed, at the moment we have
msg-sov which points to the start of the body before headers are forwarded
and which equals zero afterwards (so it still points to the start of the
body before forwarding data). A minor change consists in always making it
point to the start of the body even after data have been forwarded. It means
that it can get a negative value (so we need to change its type to signed)..

In order to avoid wrapping, we only do this as long as the other side of
the buffer is not connected yet.

Doing this definitely fixes the issues above for the requests. Since the
response cannot be rewound we don't need to perform any change there.

This bug was introduced/remained unfixed in 1.5-dev23 so the fix must be
backported to 1.5.
---
 doc/internals/body-parsing.txt | 20 +---
 include/types/proto_http.h | 11 ++-
 src/proto_http.c   |  9 +++--
 3 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/doc/internals/body-parsing.txt b/doc/internals/body-parsing.txt
index e9c8b4b..5baa549 100644
--- a/doc/internals/body-parsing.txt
+++ b/doc/internals/body-parsing.txt
@@ -67,12 +67,17 @@ msg.next : points to the next byte to inspect. This offset 
is automatically
automatically adjusted to the number of bytes already inspected.
 
 msg.sov  : start of value. First character of the header's value in the header
-   states, start of the body in the data states until headers are
-   forwarded. This offset is automatically adjusted when inserting or
-   removing some headers. In data states, it always constains the size
-   of the whole HTTP headers (including the trailing CRLF) that needs
-   to be forwarded before the first byte of body. Once the headers are
-   forwarded, this value drops to zero.
+   states, start of the body in the data states. Strictly positive
+   values indicate that headers were not forwarded yet (buf.p is
+   before the start of the body), and null or positive values are seen
+   after headers are forwarded (buf.p is at or past the start of the
+   body). 

Re: POST with x-www-form-urlencoded Content-Type

2014-07-10 Thread Daniel Dubovik
Hi Willy,

I built a new package with the patch, and my test cases are passing now.

Just wanted to say thanks for the super quick turn around on this issue!

Thanks!
Dan Dubovik
Senior Linux Systems Engineer
480-505-8800 x4257





On 7/10/14 10:34 AM, Willy Tarreau w...@1wt.eu wrote:

Hi Dan,

On Thu, Jul 10, 2014 at 05:20:18PM +0200, Willy Tarreau wrote:
 Hi Dan,
 
 On Wed, Jul 09, 2014 at 07:13:33PM +, Daniel Dubovik wrote:
  Hello all,
  
  I am attempting to balance traffic to a number of backend instances.
I am
  balancing based off the Host header, and for the most part everything
is
  working.  When testing a bit more today, I came across some weird
behavior,
  and am hoping someone can help out.  When POSTing to a site, if it is
done
  using the Content-Type application/x-www-form-urlencoded, and has
actual
  data, HAProxy falls back to a roundrobin balancing scheme.  POSTing
using a
  Content-Type of multipart/form-data, however, works just fine.  Oddly,
  application/x-www-form-urlencoded with no actual data, also works as
  expected.
 
 (...)
 
 There's indeed a bug, the amount of data forwarded is not deduced
correctly
 to rewind the buffer, I'm even wondering if it's expected that we let
them
 pass at this point. I'm investigating, thanks for your report!

OK I could fix it. The patch is very small but it required some extra care
because that's a sensible area that I already fixed in dev23 but not
enough.
Other balancing algorithms are affected, and worse, http-send-name-header
was bogus as well in this case.

I've applied the fix, I'm attaching it here, it applies both to 1.5 and to
1.6.

Thanks for your report, that was a nasty one and I'm glad we got rid of it
early!

Willy





Re: POST with x-www-form-urlencoded Content-Type

2014-07-10 Thread Willy Tarreau
Hi Dan,

On Fri, Jul 11, 2014 at 01:09:32AM +, Daniel Dubovik wrote:
 Hi Willy,
 
 I built a new package with the patch, and my test cases are passing now.
 
 Just wanted to say thanks for the super quick turn around on this issue!

Great, thank you for the quick feedback!

Willy




POST with x-www-form-urlencoded Content-Type

2014-07-09 Thread Daniel Dubovik
Hello all,

I am attempting to balance traffic to a number of backend instances.  I am 
balancing based off the Host header, and for the most part everything is 
working.  When testing a bit more today, I came across some weird behavior, and 
am hoping someone can help out.  When POSTing to a site, if it is done using 
the Content-Type application/x-www-form-urlencoded, and has actual data, 
HAProxy falls back to a roundrobin balancing scheme.  POSTing using a 
Content-Type of multipart/form-data, however, works just fine.  Oddly, 
application/x-www-form-urlencoded with no actual data, also works as expected.


Log line I receive when posting with data, using multipart/form-data:
Jul  9 11:40:06 xxx haproxy[28084]: 172.19.46.89:52564 
[09/Jul/2014:11:40:06.238] fromvarnish fromvarnish/port_10945 0/0/0/45/45 200 
426 - -  2/2/0/1/0 0/0 
{web.2014-07-09-08-28-39.xxx.com|multipart/form-data; 
boundary=155819574760c61e} POST /posttome.php
HTTP/1.1

Note, it picked a backend that I would expect.

Curl command used to generate the above log:
curl -i -F submit=submit -F firstname=  -H Host: 
web.2014-07-09-08-28-39.egyitnews.mobi http://10.224.67.9/posttome.php


Log line I receive when posting with out data, using 
application/x-www-form-urlencoded
Jul  9 11:41:11 xxx haproxy[28084]: 172.19.46.89:52572 
[09/Jul/2014:11:41:11.457] fromvarnish fromvarnish/port_10945 0/0/0/2/2 200 401 
- -  2/2/0/1/0 0/0 
{web.2014-07-09-08-28-39.xx.com|application/x-www-form-urlencoded} POST 
/posttome.php HTTP/1.1

Note, same backend is picked.  This is the ideal behavior.

Curl command used to generate the above log:
curl -i --data-urlencode '' -H Host: web.2014-07-09-08-28-39.egyitnews.mobi 
http://10.224.67.9/posttome.php

Log line I receive when posting data, using application/x-www-form-url-encoded
Jul  9 11:40:39 xxx haproxy[28084]: 172.19.46.89:52569 
[09/Jul/2014:11:40:39.635] fromvarnish fromvarnish/port_10004 0/0/0/1/1 200 330 
- -  2/2/0/1/0 0/0 
{web.2014-07-09-08-28-39.xx.com|application/x-www-form-urlencoded} POST 
/posttome.php HTTP/1.1
Jul  9 11:46:29 xxx haproxy[28084]: 172.19.46.89:52597 
[09/Jul/2014:11:46:29.703] fromvarnish fromvarnish/port_10005 0/0/0/1/1 200 330 
- -  2/2/0/1/0 0/0 
{web.2014-07-09-08-28-39.xx.com|application/x-www-form-urlencoded} POST 
/posttome.php HTTP/1.1
Jul  9 11:46:36 xxx haproxy[28084]: 172.19.46.89:52600 
[09/Jul/2014:11:46:36.829] fromvarnish fromvarnish/port_10006 0/0/0/1/1 200 330 
- -  2/2/0/1/0 0/0 
{web.2014-07-09-08-28-39.xx.com|application/x-www-form-urlencoded} POST 
/posttome.php HTTP/1.1


Note, in this one, it picked a different backend each time, in a roundrobin 
manner

Curl command used to generate the above log:
curl -i --data-urlencode a=b -H Host: web.2014-07-09-08-28-39.egyitnews.mobi 
http://10.224.67.9/posttome.php

My configuration is as follows:

global
log /dev/loglocal0 debug
log 127.0.0.1   local1 notice
maxconn 4096
uid 99
gid 99
#daemon
debug
#quiet

defaults
log global
modehttp
option  httplog
option  dontlognull
#retries3
#option redispatch
maxconn 2000
timeout connect 5000
timeout client  5
timeout server  5

listen stats
bind :81
stats enable
stats uri /

listen fromvarnish
capture request  header Host len 63
capture request header Content-Type len 100
option http-keep-alive

#frontend fromvarnish
bind *:80
#   default_backend toapache

#backend toapache
option forwardfor
balance hdr(Host)
hash-type map-based djb2

server port_1 10.224.67.9:1
server port_10001 10.224.67.9:10001
server port_10002 10.224.67.9:10002
server port_10003 10.224.67.9:10003
server port_10004 10.224.67.9:10004
.
.
.
server port_10996 10.224.67.9:10996
server port_10997 10.224.67.9:10997
server port_10998 10.224.67.9:10998
server port_10999 10.224.67.9:10999
http-response set-header X-Port %s

I disabled retries and redispatch, thinking that there was some issue on the 
backend, I tried it using either a listen or a frontend-backend pair, and 
receive the same results.

I attempted to look at an strace of the two x-www-form-urlencoded behaviors 
(with and without content), the results of that are:

12:01:42.011403 recvfrom(2, POST /posttome.php HTTP/1.1\r\nUser-Agent: 
curl/7.35.0\r\nAccept: */*\r\nHost: 
web.2014-07-09-08-28-39.egyitnews.mobi\r\nContent-Length: 3\r\nContent-Type: 
application/x-www-form-urlencoded\r\n\r\na=b, 8192, 0, NULL, NULL) = 186

12:01:42.011804 sendto(3, POST /posttome.php HTTP/1.1\r\nUser-Agent: 
curl/7.35.0\r\nAccept: */*\r\nHost: 
web.2014-07-09-08-28-39.egyitnews.mobi\r\nContent-Length: 3\r\nContent-Type: