From 6f049638b60499a1fbe6141daeb3fe7d84874dd6 Mon Sep 17 00:00:00 2001 From: Tom Dryer Date: Sun, 13 Jun 2021 13:33:42 -0700 Subject: [PATCH] Fix hung connection from consecutive requests A client making quick consecutive requests with keep-alive, such as `ab` with `-k`, can cause the connection to become hung. This happens because of an optimization in `http_poll` function. When a connection state becomes `DONE`, `httpd_poll` recycles the connection and immediately calls `poll_recv_request`. However, it doesn't handle this resulting in the connection state becoming `DONE` again. If this occurs, the state stays in `DONE`, and the further calls to `httpd_poll` ignore the connection. Fix this by calling `poll_recv_request` in a loop until the state is no longer `DONE`. --- darkhttpd.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/darkhttpd.c b/darkhttpd.c index 268628a..2a30b6c 100644 --- a/darkhttpd.c +++ b/darkhttpd.c @@ -2495,7 +2495,7 @@ static void httpd_poll(void) { LIST_FOREACH_SAFE(conn, &connlist, entries, next) { switch (conn->state) { case DONE: - /* do nothing */ + /* do nothing, no connection should be left in this state */ break; case RECV_REQUEST: @@ -2578,16 +2578,17 @@ static void httpd_poll(void) { } /* Handling SEND_REPLY could have set the state to done. */ - if (conn->state == DONE) { + while (conn->state == DONE) { /* clean out finished connection */ if (conn->conn_close) { LIST_REMOVE(conn, entries); free_connection(conn); free(conn); + break; } else { recycle_connection(conn); /* and go right back to recv_request without going through - * select() again. + * select() again, until state is not DONE */ poll_recv_request(conn); }