|
From c0d56134320e507c82952f3d2a03f76b701945cb Mon Sep 17 00:00:00 2001
|
|
From: Willy Tarreau <w@1wt.eu>
|
|
Date: Wed, 18 Nov 2015 11:59:55 +0100
|
|
Subject: [PATCH 04/10] BUG/MEDIUM: http: switch the request channel to
|
|
no-delay once done.
|
|
|
|
There's an issue when sending POST data that came in a second packet,
|
|
the CF_NEVER_WAIT flag is not always set on the request channel, while
|
|
the server is waiting for the request. We must always set this flag in
|
|
this case since we're not going to shut down after sending, contrary
|
|
to the response side.
|
|
|
|
Note that option http-no-delay works around this issue.
|
|
|
|
Reproducer :
|
|
|
|
listen px
|
|
mode http
|
|
timeout client 10s
|
|
timeout server 5s
|
|
timeout connect 3s
|
|
option http-server-close
|
|
#option http-no-delay
|
|
bind :8001
|
|
server s1 127.0.0.1:8003
|
|
|
|
$ (printf "POST / HTTP/1.1\r\nTransfer-encoding: chunked\r\n\r\n"; sleep 0.01; printf "10\r\nAZERTYUIOPQSDFGH\r\n0\r\n\r\n") | nc6 0 8001
|
|
|
|
Before this fix :
|
|
|
|
12:03:31.946763 epoll_wait(3, {{EPOLLIN, {u32=5, u64=5}}}, 200, 1000) = 1
|
|
12:03:32.634175 accept4(5, {sa_family=AF_INET, sin_port=htons(53849), sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK) = 6
|
|
12:03:32.634318 setsockopt(6, SOL_TCP, TCP_NODELAY, [1], 4) = 0
|
|
12:03:32.634434 accept4(5, 0x7ffccfbb2cf0, [128], SOCK_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
|
|
12:03:32.634574 recvfrom(6, "POST / HTTP/1.1\r\nTransfer-encodi"..., 8192, 0, NULL, NULL) = 47
|
|
12:03:32.634809 setsockopt(6, SOL_TCP, TCP_QUICKACK, [1], 4) = 0
|
|
12:03:32.634952 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 7
|
|
12:03:32.635031 fcntl(7, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
|
|
12:03:32.635089 setsockopt(7, SOL_TCP, TCP_NODELAY, [1], 4) = 0
|
|
12:03:32.635153 connect(7, {sa_family=AF_INET, sin_port=htons(8003), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
|
|
12:03:32.635315 epoll_wait(3, {}, 200, 0) = 0
|
|
12:03:32.635394 sendto(7, "POST / HTTP/1.1\r\nTransfer-encodi"..., 66, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 66
|
|
12:03:32.635527 recvfrom(6, 0x7f0224e66024, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
|
|
12:03:32.635651 epoll_ctl(3, EPOLL_CTL_ADD, 6, {EPOLLIN|0x2000, {u32=6, u64=6}}) = 0
|
|
12:03:32.635782 epoll_wait(3, {}, 200, 0) = 0
|
|
12:03:32.635842 recvfrom(7, 0x7f0224e66024, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
|
|
12:03:32.635924 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN|0x2000, {u32=7, u64=7}}) = 0
|
|
12:03:32.636027 epoll_wait(3, {{EPOLLIN, {u32=6, u64=6}}}, 200, 1000) = 1
|
|
12:03:32.644892 recvfrom(6, "10\r\nAZERTYUIOPQSDFGH\r\n0\r\n\r\n", 8192, 0, NULL, NULL) = 27
|
|
12:03:32.645016 epoll_wait(3, {}, 200, 0) = 0
|
|
12:03:32.645105 sendto(7, "10\r\nAZERTYUIOPQSDFGH\r\n0\r\n\r\n", 27, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE, NULL, 0) = 27
|
|
|
|
After the fix :
|
|
|
|
11:59:12.538617 connect(7, {sa_family=AF_INET, sin_port=htons(8003), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 EINPROGRESS (Operation now in progress)
|
|
11:59:12.538787 epoll_wait(3, {}, 200, 0) = 0
|
|
11:59:12.538867 sendto(7, "POST / HTTP/1.1\r\nTransfer-encodi"..., 66, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 66
|
|
11:59:12.539031 recvfrom(6, 0x7f832ce45024, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
|
|
11:59:12.539161 epoll_ctl(3, EPOLL_CTL_ADD, 6, {EPOLLIN|0x2000, {u32=6, u64=6}}) = 0
|
|
11:59:12.539259 epoll_wait(3, {}, 200, 0) = 0
|
|
11:59:12.539337 recvfrom(7, 0x7f832ce45024, 8192, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
|
|
11:59:12.539421 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN|0x2000, {u32=7, u64=7}}) = 0
|
|
11:59:12.539499 epoll_wait(3, {{EPOLLIN, {u32=6, u64=6}}}, 200, 1000) = 1
|
|
11:59:12.548519 recvfrom(6, "10\r\nAZERTYUIOPQSDFGH\r\n0\r\n\r\n", 8192, 0, NULL, NULL) = 27
|
|
11:59:12.548844 epoll_wait(3, {}, 200, 0) = 0
|
|
11:59:12.549012 sendto(7, "10\r\nAZERTYUIOPQSDFGH\r\n0\r\n\r\n", 27, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 27
|
|
11:59:12.549454 epoll_wait(3, {}, 200, 1000) = 0
|
|
|
|
This fix must be backported to 1.6, 1.5 and 1.4.
|
|
(cherry picked from commit 7f876a1eeb14ffae708327aad8a0b4b029da5e26)
|
|
(cherry picked from commit 712a5339f384db62796aa4d4901e091dd7fd24dd)
|
|
---
|
|
src/proto_http.c | 9 +++++++--
|
|
1 file changed, 7 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/proto_http.c b/src/proto_http.c
|
|
index e7e1785..b32e778 100644
|
|
--- a/src/proto_http.c
|
|
+++ b/src/proto_http.c
|
|
@@ -5001,6 +5001,13 @@ int http_sync_req_state(struct session *s)
|
|
*/
|
|
chn->cons->flags |= SI_FL_NOHALF;
|
|
|
|
+ /* In any case we've finished parsing the request so we must
|
|
+ * disable Nagle when sending data because 1) we're not going
|
|
+ * to shut this side, and 2) the server is waiting for us to
|
|
+ * send pending data.
|
|
+ */
|
|
+ chn->flags |= CF_NEVER_WAIT;
|
|
+
|
|
if (txn->rsp.msg_state == HTTP_MSG_ERROR)
|
|
goto wait_other_side;
|
|
|
|
@@ -5015,7 +5022,6 @@ int http_sync_req_state(struct session *s)
|
|
/* if any side switches to tunnel mode, the other one does too */
|
|
channel_auto_read(chn);
|
|
txn->req.msg_state = HTTP_MSG_TUNNEL;
|
|
- chn->flags |= CF_NEVER_WAIT;
|
|
goto wait_other_side;
|
|
}
|
|
|
|
@@ -5048,7 +5054,6 @@ int http_sync_req_state(struct session *s)
|
|
if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN) {
|
|
channel_auto_read(chn);
|
|
txn->req.msg_state = HTTP_MSG_TUNNEL;
|
|
- chn->flags |= CF_NEVER_WAIT;
|
|
}
|
|
}
|
|
|
|
--
|
|
2.4.10
|
|
|