]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: h2: check that the connection is still valid at the end of init()
authorWilly Tarreau <w@1wt.eu>
Wed, 3 Oct 2018 12:22:21 +0000 (14:22 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 3 Oct 2018 16:09:58 +0000 (18:09 +0200)
Since commit 7505f94f9 ("MEDIUM: h2: Don't use a wake() method anymore."),
the H2 mux's init() calls h2_process(). But this last one may detect an
early error and call h2_release(), destroying the connection, and return
-1. At this point we're screwed because the caller will still dereference
the connection for various things ranging from the configuration of the
proxy protocol header to the retries. We could simply return -1 here upon
failure but that's not enough since the stream layer really needs to keep
its connection structure allocated (to clean it up in session_kill_embryonic
or for example because it holds the destination address to reconnect to
when the connection goes to the backend). Thus the correct solution here is
to only schedule a wakeup of the I/O callback so that the init succeeds,
and that the connection is only handled later.

No backport is needed, this is 1.9-specific.

src/mux_h2.c

index b02f4c3136fd7bebf7fe1f05a21c512892c23ca8..62eb909b391d81aa1800b8b525548151bc233a9d 100644 (file)
@@ -381,6 +381,7 @@ static int h2c_frt_init(struct connection *conn)
        h2c->wait_list.task->process = h2_io_cb;
        h2c->wait_list.task->context = h2c;
        h2c->wait_list.wait_reason = 0;
+       LIST_INIT(&h2c->wait_list.list);
 
        h2c->ddht = hpack_dht_alloc(h2_settings_header_table_size);
        if (!h2c->ddht)
@@ -414,12 +415,10 @@ static int h2c_frt_init(struct connection *conn)
 
        if (t)
                task_queue(t);
-       conn_xprt_want_recv(conn);
-       LIST_INIT(&h2c->wait_list.list);
 
-       /* Try to read, if nothing is available yet we'll just subscribe */
-       if (h2_recv(h2c))
-               h2_process(h2c);
+       /* prepare to read something */
+       conn_xprt_want_recv(conn);
+       tasklet_wakeup(h2c->wait_list.task);
        return 0;
  fail:
        if (t)