From c75668ebff81176f2d3974872af7df4d1decf817 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 7 Dec 2020 18:10:32 +0100 Subject: [PATCH] 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. --- src/h1_htx.c | 2 +- src/http_ana.c | 6 +++--- src/mux_h1.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/h1_htx.c b/src/h1_htx.c index 734f9cbce..30e2b229e 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 5dfd41bde..db98a5469 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 f50b9d844..2bb532810 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. */