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.
This commit is contained in:
Christopher Faulet 2023-04-17 08:52:10 +02:00
parent a21ca74e83
commit 9704797fa2
2 changed files with 15 additions and 6 deletions

View File

@ -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

View File

@ -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 {