BUG/MEDIUM: http: set DONTWAIT on data when switching to tunnel mode

Jaroslaw Bojar diagnosed an issue when haproxy switches to tunnel mode
after a transfer. The response data are sent with the MSG_MORE flag,
causing them to be needlessly queued in the kernel. In order to fix this,
we set the CF_NEVER_WAIT flag on the channels when switching to tunnel
mode.

One issue remained with client-side keep-alive : if the response is sent
before the end of the request, it suffers the same issue for the same
reason. This is easily addressed by setting the CF_SEND_DONTWAIT flag
on the channel when the response has been parsed and we're waiting for
the other side.

The same issue is present in 1.4 so the fix must be backported.
This commit is contained in:
Willy Tarreau 2012-10-20 10:38:09 +02:00
parent 566dc5545b
commit fc47f91c9c

View File

@ -3986,6 +3986,7 @@ int http_sync_req_state(struct session *s)
/* if any side switches to tunnel mode, the other one does too */ /* if any side switches to tunnel mode, the other one does too */
channel_auto_read(chn); channel_auto_read(chn);
txn->req.msg_state = HTTP_MSG_TUNNEL; txn->req.msg_state = HTTP_MSG_TUNNEL;
chn->flags |= CF_NEVER_WAIT;
goto wait_other_side; goto wait_other_side;
} }
@ -4019,6 +4020,7 @@ int http_sync_req_state(struct session *s)
*/ */
channel_auto_read(chn); channel_auto_read(chn);
txn->req.msg_state = HTTP_MSG_TUNNEL; txn->req.msg_state = HTTP_MSG_TUNNEL;
chn->flags |= CF_NEVER_WAIT;
} }
if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) { if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
@ -4105,6 +4107,7 @@ int http_sync_res_state(struct session *s)
/* if any side switches to tunnel mode, the other one does too */ /* if any side switches to tunnel mode, the other one does too */
channel_auto_read(chn); channel_auto_read(chn);
txn->rsp.msg_state = HTTP_MSG_TUNNEL; txn->rsp.msg_state = HTTP_MSG_TUNNEL;
chn->flags |= CF_NEVER_WAIT;
goto wait_other_side; goto wait_other_side;
} }
@ -4142,6 +4145,7 @@ int http_sync_res_state(struct session *s)
*/ */
channel_auto_read(chn); channel_auto_read(chn);
txn->rsp.msg_state = HTTP_MSG_TUNNEL; txn->rsp.msg_state = HTTP_MSG_TUNNEL;
chn->flags |= CF_NEVER_WAIT;
} }
if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) { if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
@ -4187,6 +4191,11 @@ int http_sync_res_state(struct session *s)
wait_other_side: wait_other_side:
http_silent_debug(__LINE__, s); http_silent_debug(__LINE__, s);
/* We force the response to leave immediately if we're waiting for the
* other side, since there is no pending shutdown to push it out.
*/
if (!channel_is_empty(chn))
chn->flags |= CF_SEND_DONTWAIT;
return txn->rsp.msg_state != old_state || chn->flags != old_flags; return txn->rsp.msg_state != old_state || chn->flags != old_flags;
} }