From f0d7eb2f4f3112a363e35fd040614a2af1179e43 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 22 Mar 2021 15:07:51 +0100 Subject: [PATCH] MINOR: stream: Don't trigger errors on destructive HTTP upgrades When a TCP stream is upgraded to H2 stream, a destructive upgrade is performed. It means the TCP stream is silently released while a new one is created. It is of course more complicated but it is what we observe from the stream point of view. That was performed by returning an error when the backend was set. It is neither really elegant nor accurate. So now, instead of returning an error from stream_set_backend() in case of destructive HTTP upgrades, the TCP stream processing is aborted and no error is reported. However, the result is more or less the same. --- src/proxy.c | 22 +++++++++++++--------- src/stream.c | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/proxy.c b/src/proxy.c index 335bbafe0..c9a038413 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -2176,23 +2176,27 @@ int stream_set_backend(struct stream *s, struct proxy *be) &s->si[0].wait_event); if (conn_upgrade_mux_fe(conn, cs, &s->req.buf, ist(""), PROTO_MODE_HTTP) == -1) return 0; + + s->req.flags &= ~(CF_READ_PARTIAL|CF_AUTO_CONNECT); + s->req.total = 0; + s->flags |= SF_IGNORE; if (strcmp(conn->mux->name, "H2") == 0) { /* For HTTP/2, destroy the conn_stream, - * disable logging, and pretend that we - * failed, to that the stream is - * silently destroyed. The new mux - * will create new streams. + * disable logging, and abort the stream + * process. Thus it will be silently + * destroyed. The new mux will create + * new streams. */ cs_free(cs); si_detach_endpoint(&s->si[0]); s->logs.logwait = 0; s->logs.level = 0; - s->flags |= SF_IGNORE; - return 0; + channel_abort(&s->req); + channel_abort(&s->res); + s->req.analysers &= AN_REQ_FLT_END; + s->req.analyse_exp = TICK_ETERNITY; + return 1; } - s->req.flags &= ~(CF_READ_PARTIAL|CF_AUTO_CONNECT); - s->req.total = 0; - s->flags |= SF_IGNORE; } } else if (IS_HTX_STRM(s) && be->mode != PR_MODE_HTTP) { diff --git a/src/stream.c b/src/stream.c index b0c2bab37..9ef292d92 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1109,11 +1109,21 @@ static int process_switching_rules(struct stream *s, struct channel *req, int an /* To ensure correct connection accounting on the backend, we * have to assign one if it was not set (eg: a listen). This * measure also takes care of correctly setting the default - * backend if any. + * backend if any. Don't do anything if an upgrade is already in + * progress. */ - if (!(s->flags & SF_BE_ASSIGNED)) + if (!(s->flags & (SF_BE_ASSIGNED|SF_IGNORE))) if (!stream_set_backend(s, fe->defbe.be ? fe->defbe.be : s->be)) goto sw_failed; + + /* No backend assigned but no error reported. It happens when a + * TCP stream is upgraded to HTTP/2. + */ + if ((s->flags & (SF_BE_ASSIGNED|SF_IGNORE)) == SF_IGNORE) { + DBG_TRACE_DEVEL("leaving with no backend because of a destructive upgrade", STRM_EV_STRM_ANA, s); + return 0; + } + } /* we don't want to run the TCP or HTTP filters again if the backend has not changed */