diff options
author | Jo-Philipp Wich <jo@mein.io> | 2020-10-01 14:59:09 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2020-10-04 22:59:11 +0200 |
commit | 0f38b0370718518e66dabeaa5522f546cb459393 (patch) | |
tree | 7ba991ecba724a36002f04f416c7983801077319 /client.c | |
parent | 88ba2fa7b414f3f63e66d1708f5bda9465e0ee89 (diff) | |
download | uhttpd2-0f38b0370718518e66dabeaa5522f546cb459393.tar.gz |
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 <jo@mein.io>
Diffstat (limited to 'client.c')
-rw-r--r-- | client.c | 6 |
1 files changed, 5 insertions, 1 deletions
@@ -396,6 +396,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; @@ -460,10 +461,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; } } |