From 14041d4dc7b60500de8ab760ca9e6cc55ccc524c Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 22 Sep 2012 20:36:36 +0000 Subject: Adds support for keep-alive connections to webserver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5178 42af7a65-404d-4744-a932-0658087f49c3 --- apps/ChangeLog.txt | 2 ++ apps/include/netutils/httpd.h | 3 ++ apps/netutils/webserver/Kconfig | 18 ++++++++++ apps/netutils/webserver/httpd.c | 76 ++++++++++++++++++++++++++++++++++------- 4 files changed, 86 insertions(+), 13 deletions(-) diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt index c5b8dec92..46ccccc7f 100644 --- a/apps/ChangeLog.txt +++ b/apps/ChangeLog.txt @@ -338,3 +338,5 @@ Both from Kate. * apps/netutils/webserver/httpd.c: Improvements to HTTP parser from Kate. + * apps/netutils/webserver/httpd.c: Add support for Keep-alive connections + (from Kate). diff --git a/apps/include/netutils/httpd.h b/apps/include/netutils/httpd.h index 031840802..20ddff278 100644 --- a/apps/include/netutils/httpd.h +++ b/apps/include/netutils/httpd.h @@ -109,6 +109,9 @@ struct httpd_state { char ht_buffer[HTTPD_IOBUFFER_SIZE]; /* recv() buffer */ char ht_filename[HTTPD_MAX_FILENAME]; /* filename from GET command */ +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + bool ht_keepalive; /* Connection: keep-alive */ +#endif struct httpd_fs_file ht_file; /* Fake file data to send */ int ht_sockfd; /* The socket descriptor from accept() */ char *ht_scriptptr; diff --git a/apps/netutils/webserver/Kconfig b/apps/netutils/webserver/Kconfig index edca8dfdd..69a39510d 100644 --- a/apps/netutils/webserver/Kconfig +++ b/apps/netutils/webserver/Kconfig @@ -117,4 +117,22 @@ config NETUTILS_HTTPD_MMAP representation. endchoice + +config NETUTILS_HTTPD_KEEPALIVE_DISABLE + bool "Keepalive Disable" + default y if !NETUTILS_HTTPD_TIMEOUT + default n if NETUTILS_HTTPD_TIMEOUT + ---help--- + Disabled HTTP keep-alive for HTTP clients. Keep-alive permits a + client to make multiple requests over the same connection, rather + than closing and opening a new socket for each request. + + This depends on the content-length being known, and is automatically + disabled for situations where that header isn't produced (i.e. + scripting, CGI). Keep-alive is also disabled for certain error + responses. + + Keep-alive should normally be disabled if timeouts are enabled, + otherwise a rogue HTTP client could block the httpd indefinitely. + endif diff --git a/apps/netutils/webserver/httpd.c b/apps/netutils/webserver/httpd.c index ebcf300b6..d7dae55da 100644 --- a/apps/netutils/webserver/httpd.c +++ b/apps/netutils/webserver/httpd.c @@ -104,6 +104,16 @@ # define CONFIG_NETUTILS_HTTPD_TIMEOUT 0 #endif +/* If timeouts are not enabled, then keep-alive is disabled. This is to + * prevent a rogue HTTP client from blocking the httpd indefinitely. + */ + +#if !defined(CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE) +# if CONFIG_NETUTILS_HTTPD_TIMEOUT == 0 +# define CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE +# endif +#endif + #if !defined(CONFIG_NETUTILS_HTTPD_SENDFILE) && !defined(CONFIG_NETUTILS_HTTPD_MMAP) # ifndef CONFIG_NETUTILS_HTTPD_INDEX # ifndef CONFIG_NETUTILS_HTTPD_SCRIPT_DISABLE @@ -372,6 +382,12 @@ static int send_headers(struct httpd_state *pstate, int status, int len) { (void) snprintf(cl, sizeof cl, "Content-Length: %d\r\n", len); } +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + else + { + pstate->ht_keepalive = false; + } +#endif if (status == 413) { @@ -383,12 +399,17 @@ static int send_headers(struct httpd_state *pstate, int status, int len) #ifndef CONFIG_NETUTILS_HTTPD_SERVERHEADER_DISABLE "Server: uIP/NuttX http://nuttx.org/\r\n" #endif - "Connection: close\r\n" + "Connection: %s\r\n" "Content-type: %s\r\n" "%s" "\r\n", status, status >= 400 ? "Error" : "OK", +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + pstate->ht_keepalive ? "keep-alive" : "close", +#else + "close", +#endif mime, len >= 0 ? cl : ""); @@ -407,6 +428,13 @@ static int httpd_senderror(struct httpd_state *pstate, int status) status = 500; } +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + if (status != 404) + { + pstate->ht_keepalive = false; + } +#endif + (void) snprintf(pstate->ht_filename, sizeof pstate->ht_filename, "%s/%d.html", CONFIG_NETUTILS_HTTPD_ERRPATH, status); @@ -456,6 +484,9 @@ static int httpd_sendfile(struct httpd_state *pstate) f = httpd_cgi(pstate->ht_filename); if (f != NULL) { +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + pstate->ht_keepalive = false; +#endif f(pstate, pstate->ht_filename); return OK; @@ -474,6 +505,9 @@ static int httpd_sendfile(struct httpd_state *pstate) if (ptr != NULL && strncmp(ptr, ".shtml", strlen(".shtml")) == 0) { +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + pstate->ht_keepalive = false; +#endif if (send_headers(pstate, 200, -1) != OK) { goto done; @@ -594,7 +628,7 @@ static inline int httpd_parse(struct httpd_state *pstate) if (0 != strcmp(v, " HTTP/1.0") && 0 != strcmp(v, " HTTP/1.1")) { - ndbg("[%d] HTTP/%d.%d not supported\n", major, minor); + ndbg("[%d] HTTP version not supported\n"); return 505; } @@ -638,7 +672,12 @@ static inline int httpd_parse(struct httpd_state *pstate) ndbg("[%d] non-zero request length\n"); return 413; } - +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + else if (0 == strcasecmp(start, "Connection") && 0 == strcasecmp(v, "keep-alive")) + { + pstate->ht_keepalive = true; + } +#endif break; case STATE_BODY: @@ -650,7 +689,7 @@ static inline int httpd_parse(struct httpd_state *pstate) /* Shuffle down for the next block */ memmove(pstate->ht_buffer, start, o - start); - o -= start; + o -= (start - pstate->ht_buffer); } while (state != STATE_BODY); @@ -695,17 +734,28 @@ static void *httpd_handler(void *arg) memset(pstate, 0, sizeof(struct httpd_state)); pstate->ht_sockfd = sockfd; - /* Then handle the next httpd command */ - - status = httpd_parse(pstate); - if (status >= 400) +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE + do { - ret = httpd_senderror(pstate, status); - } - else - { - ret = httpd_sendfile(pstate); + pstate->ht_keepalive = false; +#endif + + /* Then handle the next httpd command */ + + status = httpd_parse(pstate); + if (status >= 400) + { + ret = httpd_senderror(pstate, status); + } + else + { + ret = httpd_sendfile(pstate); + } + +#ifndef CONFIG_NETUTILS_HTTPD_KEEPALIVE_DISABLE } + while (pstate->ht_keepalive); +#endif /* End of command processing -- Clean up and exit */ -- cgit v1.2.3