From 3abcc89103799aaa79870fffcd58ec4370815024 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 1 Oct 2020 14:59:09 +0200 Subject: client: fix spurious keepalive connection timeouts When an uhttpd dispatch_handler provides a data_done callback which is synchroneously finishing the request through ops->request_done(), the calling client_poll_post_data() procedure incorrectly resets the resulting client state from CLIENT_STATE_INIT to CLIENT_STATE_DONE which causes the next uh_client_read_cb() invocation to bail out since no callback is available for the CLIENT_STATE_DONE state, effectively discarding the just received inbound request and sending the persistent connection state into a deadlock sitation where the http client waits for a response to its just sent request and uhttpd for further data to read. Fix this issue by only setting CLIENT_STATE_DONE if the data_done callback has not modified the state in the meanwhile. Signed-off-by: Jo-Philipp Wich (cherry picked from commit 0f38b0370718518e66dabeaa5522f546cb459393) --- client.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client.c b/client.c index 2a2393f..204cebc 100644 --- a/client.c +++ b/client.c @@ -395,6 +395,7 @@ void client_poll_post_data(struct client *cl) { struct dispatch *d = &cl->dispatch; struct http_request *r = &cl->request; + enum client_state st; char *buf; int len; @@ -459,10 +460,13 @@ void client_poll_post_data(struct client *cl) buf = ustream_get_read_buf(cl->us, &len); if (!r->content_length && !r->transfer_chunked && cl->state != CLIENT_STATE_DONE) { + st = cl->state; + if (cl->dispatch.data_done) cl->dispatch.data_done(cl); - cl->state = CLIENT_STATE_DONE; + if (cl->state == st) + cl->state = CLIENT_STATE_DONE; } } -- cgit v1.2.1