From 05c687e251ec5e5e83f7f028b6ca2a151a15cb15 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Thu, 27 Sep 2018 02:20:01 +0300 Subject: [PATCH] Fix handling of keepalive HTTP requests/responses Clean the HTTP connection state when ia request/response has been fully buffered and handler invoked. Fixes https://github.com/cesanta/mongoose/issues/971 CL: mg: Fix handling of keepalive HTTP requests/responses PUBLISHED_FROM=70c854aa306aacb9161f6ee48841f38dc0312e6b --- mongoose.c | 25 +++++++++++++++++++++++-- src/mg_http.c | 25 +++++++++++++++++++++++-- test/unit_test.c | 2 +- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/mongoose.c b/mongoose.c index 3f593e79..589ec7fa 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6616,6 +6616,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, } } else { /* We did receive all HTTP body. */ + int request_done = 1; int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; char addr[32]; mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), @@ -6627,8 +6628,28 @@ void mg_http_handler(struct mg_connection *nc, int ev, mg_http_call_endpoint_handler(nc, trigger_ev, hm); mbuf_remove(io, hm->message.len); pd->rcvd -= hm->message.len; - if (io->len > 0) { - goto again; +#if MG_ENABLE_FILESYSTEM + /* We don't have a generic mechanism of communicating that we are done + * responding to a request (should probably add one). But if we are + * serving + * a file, we are definitely not done. */ + if (pd->file.fp != NULL) request_done = 0; +#endif +#if MG_ENABLE_HTTP_CGI + /* If this is a CGI request, we are not done either. */ + if (pd->cgi.cgi_nc != NULL) request_done = 0; +#endif + if (request_done) { + /* This request is done but we may receive another on this connection. + */ + mg_http_conn_destructor(pd); + nc->proto_data = NULL; + if (io->len > 0) { + /* We already have data for the next one, restart parsing. */ + pd = mg_http_get_proto_data(nc); + pd->rcvd = io->len; + goto again; + } } } } diff --git a/src/mg_http.c b/src/mg_http.c index dcf4c22d..af94b731 100644 --- a/src/mg_http.c +++ b/src/mg_http.c @@ -869,6 +869,7 @@ void mg_http_handler(struct mg_connection *nc, int ev, } } else { /* We did receive all HTTP body. */ + int request_done = 1; int trigger_ev = nc->listener ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY; char addr[32]; mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), @@ -880,8 +881,28 @@ void mg_http_handler(struct mg_connection *nc, int ev, mg_http_call_endpoint_handler(nc, trigger_ev, hm); mbuf_remove(io, hm->message.len); pd->rcvd -= hm->message.len; - if (io->len > 0) { - goto again; +#if MG_ENABLE_FILESYSTEM + /* We don't have a generic mechanism of communicating that we are done + * responding to a request (should probably add one). But if we are + * serving + * a file, we are definitely not done. */ + if (pd->file.fp != NULL) request_done = 0; +#endif +#if MG_ENABLE_HTTP_CGI + /* If this is a CGI request, we are not done either. */ + if (pd->cgi.cgi_nc != NULL) request_done = 0; +#endif + if (request_done) { + /* This request is done but we may receive another on this connection. + */ + mg_http_conn_destructor(pd); + nc->proto_data = NULL; + if (io->len > 0) { + /* We already have data for the next one, restart parsing. */ + pd = mg_http_get_proto_data(nc); + pd->rcvd = io->len; + goto again; + } } } } diff --git a/test/unit_test.c b/test/unit_test.c index 2cf5aa1e..cde8df8a 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -2069,7 +2069,7 @@ static const char *test_http(void) { nc->user_data = mime2; /* Run event loop. Use more cycles to let file download complete. */ - poll_until(&mgr, 5, c_str_ne, status, (void *) ""); + poll_until(&mgr, 15, c_str_ne, status, (void *) ""); mg_mgr_free(&mgr); /* Check that test buffer has been filled by the callback properly. */