]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: http: Fix blocked HTTP/1.0 responses when compression is enabled
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 30 Mar 2017 08:54:35 +0000 (10:54 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 31 Mar 2017 12:40:42 +0000 (14:40 +0200)
When the compression filter is enabled, if a HTTP/1.0 response is received (no
content-length and no transfer-encoding), no data are forwarded to the client
because of a bug and the transaction is blocked indefinitly.

The bug comes from the fact we need to synchronize the end of the request and
the response because of the compression filter. This inhibits the infinite
forwarding of data. But for these responses, the compression is not
activated. So the response body is not analyzed. This leads to a deadlock.

The solution is to enable the analyze of the response body in all cases and
handle this one to enable the infinite forwarding. All other cases should
already by handled.

This fix should be backported to 1.7.

src/proto_http.c

index acfb26c34621b027e72bde79f9b9becb4dd326d2..24d034ae03a8870dc3f6654a5a2c6b76efc12f77 100644 (file)
@@ -6826,11 +6826,9 @@ int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, s
        }
 
  skip_header_mangling:
-       if ((msg->flags & HTTP_MSGF_XFER_LEN) || HAS_DATA_FILTERS(s, rep) ||
-           (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN) {
-               rep->analysers &= ~AN_RES_FLT_XFER_DATA;
-               rep->analysers |= AN_RES_HTTP_XFER_BODY;
-       }
+       /* Always enter in the body analyzer */
+       rep->analysers &= ~AN_RES_FLT_XFER_DATA;
+       rep->analysers |= AN_RES_HTTP_XFER_BODY;
 
        /* if the user wants to log as soon as possible, without counting
         * bytes from the server, then this is the right moment. We have
@@ -6982,11 +6980,11 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
 
        /* When TE: chunked is used, we need to get there again to parse
         * remaining chunks even if the server has closed, so we don't want to
-        * set CF_DONTCLOSE. Similarly, if the body length is undefined, if
-        * keep-alive is set on the client side or if there are filters
-        * registered on the stream, we don't want to forward a close
+        * set CF_DONTCLOSE. Similarly, if keep-alive is set on the client side
+        * or if there are filters registered on the stream, we don't want to
+        * forward a close
         */
-       if ((msg->flags & HTTP_MSGF_TE_CHNK) || !(msg->flags & HTTP_MSGF_XFER_LEN) ||
+       if ((msg->flags & HTTP_MSGF_TE_CHNK) ||
            HAS_DATA_FILTERS(s, res) ||
            (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
            (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)
@@ -7003,6 +7001,14 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
        if ((msg->flags & HTTP_MSGF_TE_CHNK) || (msg->flags & HTTP_MSGF_COMPRESSING))
                res->flags |= CF_EXPECT_MORE;
 
+       /* If there is neither content-length, nor transfer-encoding header
+        * _AND_ there is no data filtering, we can safely forward all data
+        * indefinitely. */
+       if (!(msg->flags & HTTP_MSGF_XFER_LEN) && !HAS_DATA_FILTERS(s, res)) {
+               buffer_flush(res->buf);
+               channel_forward_forever(res);
+       }
+
        /* the stream handler will take care of timeouts and errors */
        return 0;