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.
This commit is contained in:
Christopher Faulet 2021-03-22 15:07:51 +01:00
parent ceab1ed86c
commit f0d7eb2f4f
2 changed files with 25 additions and 11 deletions

View File

@ -2176,23 +2176,27 @@ int stream_set_backend(struct stream *s, struct proxy *be)
&s->si[0].wait_event); &s->si[0].wait_event);
if (conn_upgrade_mux_fe(conn, cs, &s->req.buf, ist(""), PROTO_MODE_HTTP) == -1) if (conn_upgrade_mux_fe(conn, cs, &s->req.buf, ist(""), PROTO_MODE_HTTP) == -1)
return 0; 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) { if (strcmp(conn->mux->name, "H2") == 0) {
/* For HTTP/2, destroy the conn_stream, /* For HTTP/2, destroy the conn_stream,
* disable logging, and pretend that we * disable logging, and abort the stream
* failed, to that the stream is * process. Thus it will be silently
* silently destroyed. The new mux * destroyed. The new mux will create
* will create new streams. * new streams.
*/ */
cs_free(cs); cs_free(cs);
si_detach_endpoint(&s->si[0]); si_detach_endpoint(&s->si[0]);
s->logs.logwait = 0; s->logs.logwait = 0;
s->logs.level = 0; s->logs.level = 0;
s->flags |= SF_IGNORE; channel_abort(&s->req);
return 0; 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) { else if (IS_HTX_STRM(s) && be->mode != PR_MODE_HTTP) {

View File

@ -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 /* To ensure correct connection accounting on the backend, we
* have to assign one if it was not set (eg: a listen). This * have to assign one if it was not set (eg: a listen). This
* measure also takes care of correctly setting the default * 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)) if (!stream_set_backend(s, fe->defbe.be ? fe->defbe.be : s->be))
goto sw_failed; 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 */ /* we don't want to run the TCP or HTTP filters again if the backend has not changed */