]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: http: Establish a tunnel for all 2xx responses to a CONNECT
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 7 Dec 2020 17:10:32 +0000 (18:10 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 18 Dec 2020 14:05:57 +0000 (15:05 +0100)
As stated in the rfc7231, section 4.3.6, an HTTP tunnel via a CONNECT method
is successfully established if the server replies with any 2xx status
code. However, only 200 responses are considered as valid. With this patch,
any 2xx responses are now considered to estalish the tunnel.

This patch may be backported on demand to all stable versions and adapted
for the legacy HTTP. It works this way since a very long time and nobody
complains.

src/h1_htx.c
src/http_ana.c
src/mux_h1.c

index 734f9cbce7664f2cad9274531016a3fe204b7136..30e2b229e833a48100e8a1adfb599416f4a5eb14 100644 (file)
@@ -278,7 +278,7 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
                return 0;
        }
 
-       if (((h1m->flags & H1_MF_METH_CONNECT) && code == 200) || code == 101) {
+       if (((h1m->flags & H1_MF_METH_CONNECT) && code >= 200 && code < 300) || code == 101) {
                /* Switch successful replies to CONNECT requests and
                 * protocol switching to tunnel mode. */
                h1_set_tunnel_mode(h1m);
index 5dfd41bde61cd3ee5fc3607071ffab1a7120117d..db98a546923ebdb8cd4a948769274209683120ba 100644 (file)
@@ -1635,7 +1635,7 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
                http_capture_headers(htx, s->res_cap, sess->fe->rsp_cap);
 
        /* Skip parsing if no content length is possible. */
-       if (unlikely((txn->meth == HTTP_METH_CONNECT && txn->status == 200) ||
+       if (unlikely((txn->meth == HTTP_METH_CONNECT && txn->status >= 200 && txn->status < 300) ||
                     txn->status == 101)) {
                /* Either we've established an explicit tunnel, or we're
                 * switching the protocol. In both cases, we're very unlikely
@@ -2132,7 +2132,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
        if (msg->msg_state >= HTTP_MSG_ENDING)
                goto ending;
 
-       if ((txn->meth == HTTP_METH_CONNECT && txn->status == 200) || txn->status == 101 ||
+       if ((txn->meth == HTTP_METH_CONNECT && txn->status >= 200 && txn->status < 300) || txn->status == 101 ||
            (!(msg->flags & HTTP_MSGF_XFER_LEN) && !HAS_RSP_DATA_FILTERS(s))) {
                msg->msg_state = HTTP_MSG_ENDING;
                goto ending;
@@ -2187,7 +2187,7 @@ int http_response_forward_body(struct stream *s, struct channel *res, int an_bit
                }
        }
 
-       if ((txn->meth == HTTP_METH_CONNECT && txn->status == 200) || txn->status == 101 ||
+       if ((txn->meth == HTTP_METH_CONNECT && txn->status >= 200 && txn->status < 300) || txn->status == 101 ||
            !(msg->flags & HTTP_MSGF_XFER_LEN)) {
                msg->msg_state = HTTP_MSG_TUNNEL;
                goto ending;
index f50b9d8444047a7bbf19f3b29af2ca3d38b3c569..2bb532810734c898ac8f6dbaf4b0d38b1c5b2fdd 100644 (file)
@@ -934,7 +934,7 @@ static void h1_set_cli_conn_mode(struct h1s *h1s, struct h1m *h1m)
 
        if (h1m->flags & H1_MF_RESP) {
                /* Output direction: second pass */
-               if ((h1s->meth == HTTP_METH_CONNECT && h1s->status == 200) ||
+               if ((h1s->meth == HTTP_METH_CONNECT && h1s->status >= 200 && h1s->status < 300) ||
                    h1s->status == 101) {
                        /* Either we've established an explicit tunnel, or we're
                         * switching the protocol. In both cases, we're very unlikely to
@@ -994,7 +994,7 @@ static void h1_set_srv_conn_mode(struct h1s *h1s, struct h1m *h1m)
 
        if (h1m->flags & H1_MF_RESP) {
                /* Input direction: second pass */
-               if ((h1s->meth == HTTP_METH_CONNECT && h1s->status == 200) ||
+               if ((h1s->meth == HTTP_METH_CONNECT && h1s->status >= 200 && h1s->status < 300) ||
                    h1s->status == 101) {
                        /* Either we've established an explicit tunnel, or we're
                         * switching the protocol. In both cases, we're very unlikely to
@@ -1817,8 +1817,8 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
                                if ((h1s->meth != HTTP_METH_CONNECT &&
                                     (h1m->flags & (H1_MF_VER_11|H1_MF_RESP|H1_MF_CLEN|H1_MF_CHNK|H1_MF_XFER_LEN)) ==
                                     (H1_MF_VER_11|H1_MF_XFER_LEN)) ||
-                                   (h1s->status >= 200 && h1s->status != 204 && h1s->status != 304 &&
-                                    h1s->meth != HTTP_METH_HEAD && !(h1s->meth == HTTP_METH_CONNECT && h1s->status == 200) &&
+                                   (h1s->status >= 200 && h1s->status != 204 && h1s->status != 304 && h1s->meth != HTTP_METH_HEAD &&
+                                    !(h1s->meth == HTTP_METH_CONNECT && h1s->status >= 200 && h1s->status < 300) &&
                                     (h1m->flags & (H1_MF_VER_11|H1_MF_RESP|H1_MF_CLEN|H1_MF_CHNK|H1_MF_XFER_LEN)) ==
                                     (H1_MF_VER_11|H1_MF_RESP|H1_MF_XFER_LEN))) {
                                        /* chunking needed but header not seen */
@@ -1862,7 +1862,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun
                                        h1_set_req_tunnel_mode(h1s);
                                }
                                else if ((h1m->flags & H1_MF_RESP) &&
-                                        ((h1s->meth == HTTP_METH_CONNECT && h1s->status == 200) || h1s->status == 101)) {
+                                        ((h1s->meth == HTTP_METH_CONNECT && h1s->status >= 200 && h1s->status < 300) || h1s->status == 101)) {
                                        /* a successful reply to a CONNECT or a protocol switching is sent
                                         * to the client. Switch the response to tunnel mode.
                                         */