For some reason, I have to use tcp mode even though I’m making all calls over HTTP (read: Docker Engine API)
I got into a very specific problem, and after hours of debugging, I found out that it seems some TCP connections are forwarded as it is by HAProxy to a backend without going through frontend block. To support this, a lot of times I don’t even see logs in TCP mode when I make new server requests. Here’s a working config which works absolutely fine:
defaults
log global
mode http
option tcplog
timeout connect 5s
timeout client 5s
timeout server 5s
frontend www
bind :2376
tcp-request inspect-delay 100ms
acl headertest hdr(sessionid) -i test
tcp-request content accept if headertest
tcp-request content reject
default_backend servers
This works fine if I want to block any request with sessionid header other than ‘test’. Now consider the tcp mode config file:
defaults
log global
mode tcp
option tcplog
timeout connect 5s
timeout client 5s
timeout server 5s
frontend www
bind :2376
tcp-request inspect-delay 100ms
acl headertest hdr(sessionid) -i test
tcp-request content accept if headertest
tcp-request content reject
default_backend servers
Reproducing this bug:
- Switch it to TCP
- First I give an HTTP request with sessionid ‘test1’ which fails would fail because of condition.
- Next I give it HTTP request with sessionid ‘test’ which passes, as expected
- Finally give it a HTTP request ‘test1’ again, it passes! It shows the webpage, and no log entry is generated, although I can verify that the request was received on backend.
Check this:
ALSO: NO LOG ENTRY IS GENERATED FOR THE 3rd request, hence, I believe it never passes through the frontend block.
Why is that? I’ve spent a lot of hours reading the docs, and this should not be the behavior. Clearly, it states that it is possible to read HTTP data in TCP mode in docs (HAProxy version 2.0.28 - Configuration Manual) as the docs say and I quote:
It is perfectly possible to match layer 7 contents with “tcp-request content” rules, since HTTP-specific ACL matches are able to preliminarily parse the contents of a buffer before extracting the required data.