Hi again Ludovico,

so I ran some tests here with latest 1.5. I telnet to haproxy, send
"GET /?t=10000 HTTP/1.1" then quit. It forwards to a server which
waits 10s before responding.

First, without "option abortonclose" :

17:47:40.174784 accept4(7, {sa_family=AF_INET, sin_port=htons(53833), 
sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK) = 12
17:47:40.174879 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:47:40.174927 accept4(7, 0x7fff89a6c8d0, [128], SOCK_NONBLOCK) = -1 EAGAIN 
(Resource temporarily unavailable)
17:47:40.174994 recvfrom(12, 0x743234, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:47:40.175043 epoll_ctl(3, EPOLL_CTL_ADD, 12, {EPOLLIN|0x2000, {u32=12, 
u64=12}}) = 0
17:47:40.175075 epoll_wait(3, {}, 200, 1000) = 0
17:47:41.176196 epoll_wait(3, {}, 200, 1000) = 0
17:47:42.177325 epoll_wait(3, {}, 200, 1000) = 0
17:47:43.178458 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:47:44.071505 recvfrom(12, "GET /?t=10000 HTTP/1.1\r\n", 7000, 0, NULL, NULL) 
= 24
17:47:44.071564 setsockopt(12, SOL_TCP, TCP_QUICKACK, [1], 4) = 0
17:47:44.071612 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:47:44.411719 recvfrom(12, "\r\n", 6976, 0, NULL, NULL) = 2
17:47:44.411809 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 13
17:47:44.411841 fcntl(13, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
17:47:44.411864 setsockopt(13, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:47:44.411891 connect(13, {sa_family=AF_INET, sin_port=htons(8080), 
sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in 
progress)
17:47:44.411969 epoll_wait(3, {}, 200, 0) = 0
17:47:44.411998 sendto(13, "GET /?t=10000 HTTP/1.1\r\n\r\n", 26, 
MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 26
17:47:44.412047 epoll_wait(3, {}, 200, 0) = 0
17:47:44.412071 recvfrom(13, 0x745224, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:47:44.412096 epoll_ctl(3, EPOLL_CTL_ADD, 13, {EPOLLIN|0x2000, {u32=13, 
u64=13}}) = 0
17:47:44.412121 epoll_wait(3, {}, 200, 1000) = 0
17:47:45.413235 epoll_wait(3, {{EPOLLIN|0x2000, {u32=12, u64=12}}}, 200, 1000) 
= 1
17:47:46.288142 recvfrom(12, "", 7000, 0, NULL, NULL) = 0

=> the close was received

17:47:46.288210 epoll_ctl(3, EPOLL_CTL_DEL, 12, {0, {u32=12, u64=12}}) = 0
17:47:46.288242 epoll_wait(3, {}, 200, 1000) = 0
17:47:47.289369 epoll_wait(3, {}, 200, 1000) = 0

... but not forwarded, as expected.

Now with "option abortonclose" :

17:50:30.406154 accept4(7, {sa_family=AF_INET, sin_port=htons(53838), 
sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK) = 12
17:50:30.406247 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:50:30.406297 accept4(7, 0x7fff407d3740, [128], SOCK_NONBLOCK) = -1 EAGAIN 
(Resource temporarily unavailable)
17:50:30.406352 recvfrom(12, 0x743234, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:50:30.406415 epoll_ctl(3, EPOLL_CTL_ADD, 12, {EPOLLIN|0x2000, {u32=12, 
u64=12}}) = 0
17:50:30.406444 epoll_wait(3, {}, 200, 1000) = 0
17:50:31.407562 epoll_wait(3, {}, 200, 1000) = 0
17:50:32.408696 epoll_wait(3, {}, 200, 1000) = 0
17:50:33.409768 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:50:33.451660 recvfrom(12, "GET /?t=10000 HTTP/1.1\r\n", 7000, 0, NULL, NULL) 
= 24
17:50:33.451715 setsockopt(12, SOL_TCP, TCP_QUICKACK, [1], 4) = 0
17:50:33.451762 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:50:33.736088 recvfrom(12, "\r\n", 6976, 0, NULL, NULL) = 2
17:50:33.736186 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 13
17:50:33.736222 fcntl(13, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
17:50:33.736246 setsockopt(13, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:50:33.736272 connect(13, {sa_family=AF_INET, sin_port=htons(8080), 
sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in 
progress)
17:50:33.736349 epoll_wait(3, {}, 200, 0) = 0
17:50:33.736378 sendto(13, "GET /?t=10000 HTTP/1.1\r\n\r\n", 26, 
MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 26
17:50:33.736427 epoll_wait(3, {}, 200, 0) = 0
17:50:33.736451 recvfrom(13, 0x745224, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:50:33.736475 epoll_ctl(3, EPOLL_CTL_ADD, 13, {EPOLLIN|0x2000, {u32=13, 
u64=13}}) = 0
17:50:33.736500 epoll_wait(3, {{EPOLLIN|0x2000, {u32=12, u64=12}}}, 200, 1000) 
= 1
17:50:34.378879 recvfrom(12, "", 7000, 0, NULL, NULL) = 0

==> close was received

17:50:34.378929 shutdown(13, 1 /* send */) = 0

==> and immediately forwarded.

17:50:34.378992 epoll_ctl(3, EPOLL_CTL_DEL, 12, {0, {u32=12, u64=12}}) = 0
17:50:34.379043 epoll_wait(3, {}, 200, 1000) = 0
17:50:35.380170 epoll_wait(3, {}, 200, 1000) = 0
17:50:36.381305 epoll_wait(3, {}, 200, 1000) = 0

==> the server didn't consider it, as is confirmed here :

$ netstat -atn|grep CLO
tcp        0      0 127.0.0.1:8080          127.0.0.1:36255         CLOSE_WAIT 
tcp        0      0 127.0.0.1:18080         127.0.0.1:53838         CLOSE_WAIT 

That's normal, this is httpterm and it doesn't monitor the connection while
it's waiting. But in your case it should definitely work. Or it means that
your server ignores the client abort. It would be nice if you could double-
check this.

If your server does indeed not support client-abort, then there's a
workaround. Haproxy 1.5 supports half-closed timeouts. You can simply
add a directive "timeout server-fin 1s" and it will automatically close
the server connection 1 second after sending it the close if the server
doesn't respond (and then report a server error) :

17:53:29.453519 accept4(7, {sa_family=AF_INET, sin_port=htons(53842), 
sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK) = 12
17:53:29.453614 setsockopt(12, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:53:29.453661 accept4(7, 0x7fffebe94c90, [128], SOCK_NONBLOCK) = -1 EAGAIN 
(Resource temporarily unavailable)
17:53:29.453729 recvfrom(12, 0x743234, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:53:29.453776 epoll_ctl(3, EPOLL_CTL_ADD, 12, {EPOLLIN|0x2000, {u32=12, 
u64=12}}) = 0
17:53:29.453806 epoll_wait(3, {}, 200, 1000) = 0
17:53:30.454907 epoll_wait(3, {}, 200, 1000) = 0
17:53:31.456039 epoll_wait(3, {}, 200, 1000) = 0
17:53:32.457171 epoll_wait(3, {}, 200, 1000) = 0
17:53:33.458305 epoll_wait(3, {}, 200, 1000) = 0
17:53:34.459441 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:53:35.084054 recvfrom(12, "GET /?t=10000 HTTP/1.1\r\n", 7000, 0, NULL, NULL) 
= 24
17:53:35.084111 setsockopt(12, SOL_TCP, TCP_QUICKACK, [1], 4) = 0
17:53:35.084158 epoll_wait(3, {{EPOLLIN, {u32=12, u64=12}}}, 200, 1000) = 1
17:53:35.209349 recvfrom(12, "\r\n", 6976, 0, NULL, NULL) = 2
17:53:35.209432 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 13
17:53:35.209463 fcntl(13, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
17:53:35.209486 setsockopt(13, SOL_TCP, TCP_NODELAY, [1], 4) = 0
17:53:35.209515 connect(13, {sa_family=AF_INET, sin_port=htons(8080), 
sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in 
progress)
17:53:35.209587 epoll_wait(3, {}, 200, 0) = 0
17:53:35.209617 sendto(13, "GET /?t=10000 HTTP/1.1\r\n\r\n", 26, 
MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 26
17:53:35.209666 epoll_wait(3, {}, 200, 0) = 0
17:53:35.209691 recvfrom(13, 0x745224, 7000, 0, 0, 0) = -1 EAGAIN (Resource 
temporarily unavailable)
17:53:35.209716 epoll_ctl(3, EPOLL_CTL_ADD, 13, {EPOLLIN|0x2000, {u32=13, 
u64=13}}) = 0
17:53:35.209741 epoll_wait(3, {}, 200, 1000) = 0
17:53:36.210858 epoll_wait(3, {{EPOLLIN|0x2000, {u32=12, u64=12}}}, 200, 1000) 
= 1
17:53:37.197936 recvfrom(12, "", 7000, 0, NULL, NULL) = 0

==> telnet closed

17:53:37.198006 shutdown(13, 1 /* send */) = 0

==> close transmitted to server

17:53:37.198053 epoll_ctl(3, EPOLL_CTL_DEL, 12, {0, {u32=12, u64=12}}) = 0
17:53:37.198094 epoll_wait(3, {}, 200, 1000) = 0
17:53:38.199233 setsockopt(13, SOL_SOCKET, SO_LINGER, {onoff=1, linger=0}, 8) = 0
17:53:38.199294 close(13)               = 0

==> got bored, aborted server connection

17:53:38.199359 epoll_wait(3, {}, 200, 0) = 0
17:53:38.199400 sendto(12, "HTTP/1.0 504 Gateway Time-out\r\nCache-Control: 
no-cache\r\nConnection: close\r\nContent-Type: 
text/html\r\n\r\n<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't 
respond in time.\n</body></html>\n", 194, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE, 
NULL, 0) = 194

==> and reported server error

17:53:38.199453 shutdown(12, 1 /* send */) = 0
17:53:38.199498 close(12)               = 0

==> and closed with the client.

I suspect it could match your needs if the normal solution doesn't work.
This *does* require abortonclose since you want the shutdown() to have been
done first. Please keep us updated.

Regards,
Willy


Reply via email to