From 61672c780540bd5bb8e12d4fa399aa5c2aa4e355 Mon Sep 17 00:00:00 2001 From: Deomid Ryabkov Date: Mon, 25 Apr 2016 16:40:38 +0100 Subject: [PATCH] Properly handle keep-alive connections HTTP/1.1 connections are keep-alive by default, HTTP/1.0 are KA only if explicitly requested. PUBLISHED_FROM=cb2070c2d4e4be6beeab4ae5914b8a01b04bc0cb --- examples/restful_server/restful_server.c | 25 +++++++++--------- mongoose.c | 33 ++++++++++++++---------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/examples/restful_server/restful_server.c b/examples/restful_server/restful_server.c index 27ada98b..73a8c904 100644 --- a/examples/restful_server/restful_server.c +++ b/examples/restful_server/restful_server.c @@ -22,7 +22,7 @@ static void handle_sum_call(struct mg_connection *nc, struct http_message *hm) { /* Compute the result and send it back as a JSON object */ result = strtod(n1, NULL) + strtod(n2, NULL); mg_printf_http_chunk(nc, "{ \"result\": %lf }", result); - mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */ + mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */ } static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { @@ -31,14 +31,14 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { switch (ev) { case MG_EV_HTTP_REQUEST: if (mg_vcmp(&hm->uri, "/api/v1/sum") == 0) { - handle_sum_call(nc, hm); /* Handle RESTful call */ + handle_sum_call(nc, hm); /* Handle RESTful call */ } else if (mg_vcmp(&hm->uri, "/printcontent") == 0) { char buf[100] = {0}; memcpy(buf, hm->body.p, - sizeof(buf) - 1 < hm->body.len? sizeof(buf) - 1 : hm->body.len); + sizeof(buf) - 1 < hm->body.len ? sizeof(buf) - 1 : hm->body.len); printf("%s\n", buf); } else { - mg_serve_http(nc, hm, s_http_server_opts); /* Serve static content */ + mg_serve_http(nc, hm, s_http_server_opts); /* Serve static content */ } break; default: @@ -57,6 +57,12 @@ int main(int argc, char *argv[]) { mg_mgr_init(&mgr, NULL); + /* Use current binary directory as document root */ + if (argc > 0 && ((cp = strrchr(argv[0], DIRSEP)) != NULL)) { + *cp = '\0'; + s_http_server_opts.document_root = argv[0]; + } + /* Process command line options to customize HTTP server */ for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-D") == 0 && i + 1 < argc) { @@ -110,17 +116,10 @@ int main(int argc, char *argv[]) { #endif mg_set_protocol_http_websocket(nc); - s_http_server_opts.document_root = "."; s_http_server_opts.enable_directory_listing = "yes"; - /* Use current binary directory as document root */ - if (argc > 0 && ((cp = strrchr(argv[0], '/')) != NULL || - (cp = strrchr(argv[0], '/')) != NULL)) { - *cp = '\0'; - s_http_server_opts.document_root = argv[0]; - } - - printf("Starting RESTful server on port %s\n", s_http_port); + printf("Starting RESTful server on port %s, serving %s\n", s_http_port, + s_http_server_opts.document_root); for (;;) { mg_mgr_poll(&mgr, 1000); } diff --git a/mongoose.c b/mongoose.c index e47f6377..e142a403 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4127,9 +4127,10 @@ static const char *mg_version_header = "Mongoose/" MG_VERSION; enum mg_http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT }; struct mg_http_proto_data_file { - FILE *fp; /* Opened file. */ - int64_t cl; /* Content-Length. How many bytes to send. */ - int64_t sent; /* How many bytes have been already sent. */ + FILE *fp; /* Opened file. */ + int64_t cl; /* Content-Length. How many bytes to send. */ + int64_t sent; /* How many bytes have been already sent. */ + int keepalive; /* Keep connection open after sending. */ enum mg_http_proto_data_type type; }; @@ -4812,10 +4813,8 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { mg_send(nc, buf, n); pd->file.sent += n; } else { + if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE; mg_http_free_proto_data_file(&pd->file); -#ifdef MG_DISABLE_HTTP_KEEP_ALIVE - nc->flags |= MG_F_SEND_AND_CLOSE; -#endif } } else if (pd->file.type == DATA_PUT) { struct mbuf *io = &nc->recv_mbuf; @@ -4827,10 +4826,8 @@ static void mg_http_transfer_file_data(struct mg_connection *nc) { pd->file.sent += n; } if (n == 0 || pd->file.sent >= pd->file.cl) { + if (!pd->file.keepalive) nc->flags |= MG_F_SEND_AND_CLOSE; mg_http_free_proto_data_file(&pd->file); -#ifdef MG_DISABLE_HTTP_KEEP_ALIVE - nc->flags |= MG_F_SEND_AND_CLOSE; -#endif } } #ifndef MG_DISABLE_CGI @@ -5946,6 +5943,17 @@ static void mg_http_send_file2(struct mg_connection *nc, const char *path, } } +#ifndef MG_DISABLE_HTTP_KEEP_ALIVE + { + struct mg_str *conn_hdr = mg_get_http_header(hm, "Connection"); + if (conn_hdr != NULL) { + pd->file.keepalive = (mg_vcasecmp(conn_hdr, "keep-alive") == 0); + } else { + pd->file.keepalive = (mg_vcmp(&hm->proto, "HTTP/1.1") == 0); + } + } +#endif + mg_http_construct_etag(etag, sizeof(etag), st); mg_gmt_time_string(current_time, sizeof(current_time), &t); mg_gmt_time_string(last_modified, sizeof(last_modified), &st->st_mtime); @@ -5963,14 +5971,13 @@ static void mg_http_send_file2(struct mg_connection *nc, const char *path, "Last-Modified: %s\r\n" "Accept-Ranges: bytes\r\n" "Content-Type: %.*s\r\n" -#ifdef MG_DISABLE_HTTP_KEEP_ALIVE - "Connection: close\r\n" -#endif + "Connection: %s\r\n" "Content-Length: %" SIZE_T_FMT "\r\n" "%sEtag: %s\r\n\r\n", current_time, last_modified, (int) mime_type.len, mime_type.p, - (size_t) cl, range, etag); + (pd->file.keepalive ? "keep-alive" : "close"), (size_t) cl, range, + etag); pd->file.cl = cl; pd->file.type = DATA_FILE;