Browse Source

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>
Jo-Philipp Wich 3 years ago
parent
commit
0f38b03707
1 changed files with 5 additions and 1 deletions
  1. 5 1
      client.c

+ 5 - 1
client.c

@@ -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;
 	}
 }