diff --git a/include/haproxy/stconn.h b/include/haproxy/stconn.h index 9c7be5032..ff0de4354 100644 --- a/include/haproxy/stconn.h +++ b/include/haproxy/stconn.h @@ -51,6 +51,10 @@ int sc_reset_endp(struct stconn *sc); struct appctx *sc_applet_create(struct stconn *sc, struct applet *app); +void sc_conn_prepare_endp_upgrade(struct stconn *sc); +void sc_conn_abort_endp_upgrade(struct stconn *sc); +void sc_conn_commit_endp_upgrade(struct stconn *sc); + /* The se_fl_*() set of functions manipulate the stream endpoint flags from * the stream endpoint itself. The sc_ep_*() set of functions manipulate the * stream endpoint flags from the the stream connector (ex. stconn). diff --git a/src/stconn.c b/src/stconn.c index 5d4ed3ed4..02a8dc452 100644 --- a/src/stconn.c +++ b/src/stconn.c @@ -1943,3 +1943,35 @@ static int sc_applet_process(struct stconn *sc) appctx_wakeup(__sc_appctx(sc)); return 0; } + + +/* Prepares an endpoint upgrade. We don't now at this stage if the upgrade will + * succeed or not and if the stconn will be reused by the new endpoint. Thus, + * for now, only pretend the stconn is detached. + */ +void sc_conn_prepare_endp_upgrade(struct stconn *sc) +{ + BUG_ON(!sc_conn(sc) || !sc->app); + sc_ep_clr(sc, SE_FL_T_MUX); + sc_ep_set(sc, SE_FL_DETACHED); +} + +/* Endpoint upgrade failed. Retore the stconn state. */ +void sc_conn_abort_endp_upgrade(struct stconn *sc) +{ + sc_ep_set(sc, SE_FL_T_MUX); + sc_ep_clr(sc, SE_FL_DETACHED); +} + +/* Commit the endpoint upgrade. If stconn is attached, it means the new endpoint + * use it. So we do nothing. Otherwise, the stconn will be destroy with the + * overlying stream. So, it means we must commit the detach. +*/ +void sc_conn_commit_endp_upgrade(struct stconn *sc) +{ + if (!sc_ep_test(sc, SE_FL_DETACHED)) + return; + sc_detach_endp(&sc); + /* Because it was already set as detached, the sedesc must be preserved */ + BUG_ON(!sc->sedesc); +} diff --git a/src/stream.c b/src/stream.c index f3f776db6..2f698482f 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1485,10 +1485,15 @@ int stream_set_http_mode(struct stream *s, const struct mux_proto_list *mux_prot if (conn->mux->flags & MX_FL_NO_UPG) return 0; + + sc_conn_prepare_endp_upgrade(sc); if (conn_upgrade_mux_fe(conn, sc, &s->req.buf, (mux_proto ? mux_proto->token : ist("")), - PROTO_MODE_HTTP) == -1) + PROTO_MODE_HTTP) == -1) { + sc_conn_abort_endp_upgrade(sc); return 0; + } + sc_conn_commit_endp_upgrade(sc); s->req.flags &= ~(CF_READ_PARTIAL|CF_AUTO_CONNECT); s->req.total = 0;