]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: http: Be sure to process all the data received from a server
authorChristopher Faulet <cfaulet@qualys.com>
Fri, 19 Jun 2015 07:00:58 +0000 (09:00 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 28 Dec 2015 15:49:36 +0000 (16:49 +0100)
When the response body is forwarded, if the server closes the input before the
end, an error is thrown. But if the data processing is too slow, all data could
already be received and pending in the input buffer. So this is a bug to stop
processing in this context. The server doesn't really closed the input before
the end.

As an example, this could happen when HAProxy is configured to do compression
offloading. If the server closes the connection explicitly after the response
(keep-alive disabled by the server) and if HAProxy receives the data faster than
they are compressed, then the response could be truncated.

This patch fixes the bug by checking if some pending data remain in the input
buffer before returning an error. If yes, the processing continues.

src/proto_http.c

index 8c476c7c03877764a750623c8274aab5d8e1d7f1..46b304f62772f8f665e150ea80ee8243ee2687b9 100644 (file)
@@ -7155,12 +7155,15 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
        if (res->flags & CF_SHUTR) {
                if ((s->req.flags & (CF_SHUTR|CF_SHUTW)) == (CF_SHUTR|CF_SHUTW))
                        goto aborted_xfer;
-               if (!(s->flags & SF_ERR_MASK))
-                       s->flags |= SF_ERR_SRVCL;
-               s->be->be_counters.srv_aborts++;
-               if (objt_server(s->target))
-                       objt_server(s->target)->counters.srv_aborts++;
-               goto return_bad_res_stats_ok;
+               /* If we have some pending data, we continue the processing */
+               if (!buffer_pending(res->buf)) {
+                       if (!(s->flags & SF_ERR_MASK))
+                               s->flags |= SF_ERR_SRVCL;
+                       s->be->be_counters.srv_aborts++;
+                       if (objt_server(s->target))
+                               objt_server(s->target)->counters.srv_aborts++;
+                       goto return_bad_res_stats_ok;
+               }
        }
 
        /* we need to obey the req analyser, so if it leaves, we must too */