From 2442f68dd32809571b6eee4242a8e8bb93dabd0a Mon Sep 17 00:00:00 2001 From: Olivier Houchard Date: Sat, 1 Dec 2018 17:03:38 +0100 Subject: [PATCH] BUG/MEDIUM: Special-case http_proxy when dealing with outgoing connections. http_proxy is special, because it creates its connection and conn_stream earlier. So in assign_server(), check that the connection associated with the conn_stream has a destination address set, and in connect_server(), use the connection and the conn_stream already attached to the stream_interface, instead of looking for a connection in the session, and creating a new conn_stream. --- src/backend.c | 79 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/src/backend.c b/src/backend.c index 150ea7cde..404c5b38e 100644 --- a/src/backend.c +++ b/src/backend.c @@ -744,10 +744,16 @@ int assign_server(struct stream *s) else if (s->be->options & (PR_O_DISPATCH | PR_O_TRANSP)) { s->target = &s->be->obj_type; } - else if ((s->be->options & PR_O_HTTP_PROXY) && - conn && is_addr(&conn->addr.to)) { - /* in proxy mode, we need a valid destination address */ - s->target = &s->be->obj_type; + else if ((s->be->options & PR_O_HTTP_PROXY)) { + conn = cs_conn(objt_cs(s->si[1].end)); + + if (conn && is_addr(&conn->addr.to)) { + /* in proxy mode, we need a valid destination address */ + s->target = &s->be->obj_type; + } else { + err = SRV_STATUS_NOSRV; + goto out; + } } else { err = SRV_STATUS_NOSRV; @@ -1109,33 +1115,45 @@ int connect_server(struct stream *s) struct connection *cli_conn = NULL; struct connection *srv_conn = NULL; struct connection *old_conn = NULL; - struct conn_stream *srv_cs; + struct conn_stream *srv_cs = NULL; struct server *srv; int reuse = 0; int err; int i; - for (i = 0; i < MAX_SRV_LIST; i++) { - if (s->sess->srv_list[i].target == s->target) { - list_for_each_entry(srv_conn, &s->sess->srv_list[i].list, - session_list) { - if (conn_xprt_ready(srv_conn) && - srv_conn->mux && (srv_conn->mux->avail_streams(srv_conn) > 0)) { - reuse = 1; + if (!(s->be->options & PR_O_HTTP_PROXY)) { + for (i = 0; i < MAX_SRV_LIST; i++) { + if (s->sess->srv_list[i].target == s->target) { + list_for_each_entry(srv_conn, &s->sess->srv_list[i].list, + session_list) { + if (conn_xprt_ready(srv_conn) && + srv_conn->mux && (srv_conn->mux->avail_streams(srv_conn) > 0)) { + reuse = 1; + break; + } + } + } + } + if (!srv_conn) { + for (i = 0; i < MAX_SRV_LIST; i++) { + if (!LIST_ISEMPTY(&s->sess->srv_list[i].list)) { + srv_conn = LIST_ELEM(&s->sess->srv_list[i].list, + struct connection *, session_list); break; } } } - } - if (!srv_conn) { - for (i = 0; i < MAX_SRV_LIST; i++) { - if (!LIST_ISEMPTY(&s->sess->srv_list[i].list)) { - srv_conn = LIST_ELEM(&s->sess->srv_list[i].list, - struct connection *, session_list); - break; - } - } + } else { + /* http_proxy is special, we can't just reuse any connection, + * as the destination may be different. We should have created + * a connection and a conn_stream earlier, so get the + * connection from the conn_stream. + */ + srv_cs = objt_cs(s->si[1].end); + old_conn = srv_conn = cs_conn(srv_cs); + if (old_conn) + reuse = 1; } old_conn = srv_conn; @@ -1227,14 +1245,19 @@ int connect_server(struct stream *s) srv_conn = conn_new(); srv_cs = NULL; } else { - if (srv_conn->mux->avail_streams(srv_conn) == 1) { - /* No more streams available, remove it from the list */ - LIST_DEL(&srv_conn->list); - LIST_INIT(&srv_conn->list); + /* We already created a cs earlier when using http_proxy, so + * only create a new one if we don't have one already. + */ + if (!srv_cs) { + if (srv_conn->mux->avail_streams(srv_conn) == 1) { + /* No more streams available, remove it from the list */ + LIST_DEL(&srv_conn->list); + LIST_INIT(&srv_conn->list); + } + srv_cs = srv_conn->mux->attach(srv_conn); + if (srv_cs) + si_attach_cs(&s->si[1], srv_cs); } - srv_cs = srv_conn->mux->attach(srv_conn); - if (srv_cs) - si_attach_cs(&s->si[1], srv_cs); } if (srv_conn && old_conn != srv_conn) { srv_conn->owner = s->sess;