From: Christopher Faulet Date: Mon, 7 Dec 2020 17:10:32 +0000 (+0100) Subject: BUG/MINOR: http: Establish a tunnel for all 2xx responses to a CONNECT X-Git-Tag: v2.4-dev4~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c75668ebff81176f2d3974872af7df4d1decf817;p=thirdparty%2Fhaproxy.git BUG/MINOR: http: Establish a tunnel for all 2xx responses to a CONNECT 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. --- diff --git a/src/h1_htx.c b/src/h1_htx.c index 734f9cbce7..30e2b229e8 100644 --- a/src/h1_htx.c +++ b/src/h1_htx.c @@ -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); diff --git a/src/http_ana.c b/src/http_ana.c index 5dfd41bde6..db98a54692 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -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; diff --git a/src/mux_h1.c b/src/mux_h1.c index f50b9d8444..2bb5328107 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -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. */