From: Manu Nicolas Date: Thu, 3 Sep 2026 14:10:54 +0000 (+0000) Subject: BUG/MEDIUM: http-ana: apply tunnel timeout with data filters X-Git-Tag: v3.5-dev7~51 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=6b81d9a01d8afd33d58c956363b03e806ae7ce29;p=haproxy.git BUG/MEDIUM: http-ana: apply tunnel timeout with data filters The tunnel timeout is installed by process_stream() only once all analysers are gone. HTTP data filters keep their transfer and end analysers attached after a protocol upgrade. A stream using, for example, set-bandwidth-limit therefore remains on its client and server timeouts even though both HTTP messages are in tunnel mode. A short client timeout can close a WebSocket before its heartbeat. Apply the per-stream tunnel timeout when the second HTTP message enters tunnel mode. Data-filter analysers remain active and continue to process tunneled data. It should be backported as far as 2.6. --- diff --git a/reg-tests/http-messaging/websocket.vtc b/reg-tests/http-messaging/websocket.vtc index 3990ddb9a..6414ebf93 100644 --- a/reg-tests/http-messaging/websocket.vtc +++ b/reg-tests/http-messaging/websocket.vtc @@ -28,6 +28,7 @@ server s1 { recv 4 send "PONG" + expect_close } -start # non-conformant server: no websocket key @@ -111,6 +112,13 @@ haproxy hap -conf { listen fe1 bind "fd@${fe1}" + timeout client 100ms + timeout server 100ms + timeout tunnel 1s + filter bwlim-in upload default-limit 1m default-period 1s + filter bwlim-out download default-limit 1m default-period 1s + http-request set-bandwidth-limit upload + http-request set-bandwidth-limit download server s1 ${s1_addr}:${s1_port} listen fe2 @@ -141,8 +149,10 @@ client c1 -connect ${hap_fe1_sock} { expect resp.http.upgrade == "websocket" expect resp.http.sec-websocket-accept == "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" + delay 0.2 send "PING" recv 4 + expect_close } -run # missing websocket key diff --git a/src/http_ana.c b/src/http_ana.c index f11352975..bcfa4849d 100644 --- a/src/http_ana.c +++ b/src/http_ana.c @@ -4588,14 +4588,14 @@ static void http_end_request(struct stream *s) * direction, and sometimes for a close to be effective. */ if (txn->flags & TX_CON_WANT_TUN) { - /* Tunnel mode will not have any analyser so it needs to - * poll for reads. - */ + /* Tunnel mode needs to poll for reads. */ channel_auto_read(&s->req); txn->req.msg_state = HTTP_MSG_TUNNEL; s->scb->flags &= ~SC_FL_NOHALF; if (txn->rsp.msg_state != HTTP_MSG_TUNNEL) s->res.flags |= CF_WAKE_ONCE; + else if (s->tunnel_timeout) + s->scf->ioto = s->scb->ioto = s->tunnel_timeout; } else { /* we're not expecting any new data to come for this @@ -4708,6 +4708,8 @@ static void http_end_response(struct stream *s) txn->rsp.msg_state = HTTP_MSG_TUNNEL; if (txn->req.msg_state != HTTP_MSG_TUNNEL) s->req.flags |= CF_WAKE_ONCE; + else if (s->tunnel_timeout) + s->scf->ioto = s->scb->ioto = s->tunnel_timeout; } else { /* we're not expecting any new data to come for this