summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-10-01 14:59:09 +0200
committerJo-Philipp Wich <jo@mein.io>2020-11-20 22:49:34 +0100
commit3abcc89103799aaa79870fffcd58ec4370815024 (patch)
tree70078f1ca0d2a2dcad9fbcbc01928f13d7562524
parent975dce23257e713e5e52eb87b194513eb81110a5 (diff)
downloaduhttpd2-openwrt-19.07.tar.gz
client: fix spurious keepalive connection timeoutsopenwrt-19.07
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 <jo@mein.io> (cherry picked from commit 0f38b0370718518e66dabeaa5522f546cb459393)
-rw-r--r--client.c6
1 files changed, 5 insertions, 1 deletions
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;
}
}