From 9704797fa2441b39603b78c68619f1ce94fc0f11 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 17 Apr 2023 08:52:10 +0200 Subject: [PATCH] BUG/MEDIUM: http-ana: Properly switch the request in tunnel mode on upgrade Since the commit f2b02cfd9 ("MAJOR: http-ana: Review error handling during HTTP payload forwarding"), during the payload forwarding, we are analyzing a side, we stop to test the opposite side. It means when the HTTP request forwarding analyzer is called, we no longer check the response side and vice versa. Unfortunately, since then, the HTTP tunneling is broken after a protocol upgrade. On the response is switch in TUNNEL mode. The request remains in DONE state. As a consequence, data received from the server are forwarded to the client but not data received from the client. To fix the bug, when both sides are in DONE state, both are switched in same time in TUNNEL mode if it was requested. It is performed in the same way in http_end_request() and http_end_response(). This patch should fix the issue #2125. It is 2.8-specific. No backport needed. --- reg-tests/http-messaging/websocket.vtc | 8 +++++++- src/http_ana.c | 13 ++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/reg-tests/http-messaging/websocket.vtc b/reg-tests/http-messaging/websocket.vtc index 5f4b960e8e..aed55fe515 100644 --- a/reg-tests/http-messaging/websocket.vtc +++ b/reg-tests/http-messaging/websocket.vtc @@ -27,7 +27,10 @@ server s1 { -hdr "connection: upgrade" \ -hdr "upgrade: websocket" \ -hdr "sec-websocket-accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" -} -repeat 2 -start + + recv 4 + send "PONG" +} -start # non-conformant server: no websocket key server s2 { @@ -124,6 +127,9 @@ client c1 -connect ${hap_fe1_sock} { expect resp.http.connection == "upgrade" expect resp.http.upgrade == "websocket" expect resp.http.sec-websocket-accept == "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" + + send "PING" + recv 4 } -run # missing websocket key diff --git a/src/http_ana.c b/src/http_ana.c index 8828e6b12b..9097856ffa 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -2089,10 +2089,9 @@ 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 < 300) || txn->status == 101 || - !(msg->flags & HTTP_MSGF_XFER_LEN)) { + if (!(txn->flags & TX_CON_WANT_TUN) && !(msg->flags & HTTP_MSGF_XFER_LEN)) { + /* One-side tunnel */ msg->msg_state = HTTP_MSG_TUNNEL; - goto ending; } else { msg->msg_state = HTTP_MSG_DONE; @@ -4255,8 +4254,10 @@ static void http_end_request(struct stream *s) /* Tunnel mode will not have any analyser so it needs to * poll for reads. */ - channel_auto_read(chn); + channel_auto_read(&s->req); txn->req.msg_state = HTTP_MSG_TUNNEL; + channel_auto_read(&s->res); + txn->rsp.msg_state = HTTP_MSG_TUNNEL; } else { /* we're not expecting any new data to come for this @@ -4363,7 +4364,9 @@ static void http_end_response(struct stream *s) * direction, and sometimes for a close to be effective. */ if (txn->flags & TX_CON_WANT_TUN) { - channel_auto_read(chn); + channel_auto_read(&s->req); + txn->req.msg_state = HTTP_MSG_TUNNEL; + channel_auto_read(&s->res); txn->rsp.msg_state = HTTP_MSG_TUNNEL; } else { -- 2.39.5