mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-09 23:39:55 +00:00
BUG/MEDIUM: http: don't disable lingering on requests with tunnelled responses
The HTTP forwarding engine needs to disable lingering on requests in case the connection to the server has to be suddenly closed due to http-server-close being used, so that we don't accumulate lethal TIME_WAIT sockets on the outgoing side. A problem happens when the server doesn't advertise a response size, because the response message quickly goes through the MSG_DONE and MSG_TUNNEL states, and once the client has transferred all of its data, it turns to MSG_DONE and immediately sets NOLINGER and closes before the server has a chance to respond. The problem is that this destroys some of the pending DATA being uploaded, the server doesn't receive all of them, detects an error and closes. This early NOLINGER is inappropriate in this situation because it happens before the response is transmitted. This state transition to MSG_TUNNEL doesn't happen when the response size is known since we stay in MSG_DATA (and related states) during all the transfer. Given that the issue is only related to connections not advertising a response length and that by definition these connections cannot be reused, there's no need for NOLINGER when the response's transfer length is not known, which can be verified when entering the CLOSED state. That's what this patch does. This fix needs to be backported to 1.8 and very likely to 1.7 and older as it affects the very rare case where a client immediately closes after the last uploaded byte (typically a script). However given that the risk of occurrence in HTTP/1 is extremely low, it is probably wise to wait before backporting it before 1.8.
This commit is contained in:
parent
13e4e94dae
commit
805935147a
@ -4523,6 +4523,10 @@ int http_sync_req_state(struct stream *s)
|
||||
|
||||
if (txn->req.msg_state == HTTP_MSG_CLOSED) {
|
||||
http_msg_closed:
|
||||
/* if we don't know whether the server will close, we need to hard close */
|
||||
if (txn->rsp.flags & HTTP_MSGF_XFER_LEN)
|
||||
s->si[1].flags |= SI_FL_NOLINGER; /* we want to close ASAP */
|
||||
|
||||
/* see above in MSG_DONE why we only do this in these states */
|
||||
if (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL) &&
|
||||
((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) &&
|
||||
@ -4535,7 +4539,6 @@ int http_sync_req_state(struct stream *s)
|
||||
/* Here, we are in HTTP_MSG_DONE or HTTP_MSG_TUNNEL */
|
||||
if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
|
||||
/* if we've just closed an output, let's switch */
|
||||
s->si[1].flags |= SI_FL_NOLINGER; /* we want to close ASAP */
|
||||
txn->req.msg_state = HTTP_MSG_CLOSING;
|
||||
goto http_msg_closing;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user