From 2c090c8beb09a7480f2ec5cd925b54bdaba08295 Mon Sep 17 00:00:00 2001 From: "zodiac@gmail.com" Date: Sun, 21 Jun 2009 18:51:14 +0000 Subject: [PATCH] Respect "Connection: close" if sent by the browser. git-svn-id: https://shellinabox.googlecode.com/svn/trunk@123 0da03de8-d603-11dd-86c2-0f8696b7b6f9 --- config.h | 5 +- config.h.in | 3 ++ configure | 6 ++- configure.ac | 5 +- demo/vt100.js | 2 +- libhttp/httpconnection.c | 89 ++++++++++++++++++++++------------- shellinabox/shell_in_a_box.js | 2 +- shellinabox/vt100.js | 2 +- 8 files changed, 74 insertions(+), 40 deletions(-) diff --git a/config.h b/config.h index a140e67..9e4a64f 100644 --- a/config.h +++ b/config.h @@ -70,6 +70,9 @@ /* Define to 1 if you have the header file. */ #define HAVE_STDLIB_H 1 +/* Define to 1 if you have the `strcasestr' function. */ +#define HAVE_STRCASESTR 1 + /* Define to 1 if you have the header file. */ #define HAVE_STRINGS_H 1 @@ -129,7 +132,7 @@ #define STDC_HEADERS 1 /* Most recent revision number in the version control system */ -#define VCS_REVISION "122" +#define VCS_REVISION "123" /* Version number of package */ #define VERSION "2.8" diff --git a/config.h.in b/config.h.in index 7045939..0be5561 100644 --- a/config.h.in +++ b/config.h.in @@ -69,6 +69,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the `strcasestr' function. */ +#undef HAVE_STRCASESTR + /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H diff --git a/configure b/configure index 215ae73..c7363a3 100755 --- a/configure +++ b/configure @@ -2037,7 +2037,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -VCS_REVISION=122 +VCS_REVISION=123 cat >>confdefs.h <<_ACEOF @@ -11743,7 +11743,9 @@ done -for ac_func in getgrgid_r getgrnam_r getpwnam_r getpwuid_r openpty + +for ac_func in getgrgid_r getgrnam_r getpwnam_r getpwuid_r openpty \ + strcasestr do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 diff --git a/configure.ac b/configure.ac index fab433e..097c11a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.57) dnl This is the one location where the authoritative version number is stored AC_INIT(shellinabox, 2.8, markus@shellinabox.com) -VCS_REVISION=122 +VCS_REVISION=123 AC_SUBST(VCS_REVISION) AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", [Most recent revision number in the version control system]) @@ -33,7 +33,8 @@ dnl Use strlcat() instead of strncat() to avoid spurious warnings AC_CHECK_FUNCS([strlcat]) dnl Prefer thread-safe functions, if available -AC_CHECK_FUNCS([getgrgid_r getgrnam_r getpwnam_r getpwuid_r openpty]) +AC_CHECK_FUNCS([getgrgid_r getgrnam_r getpwnam_r getpwuid_r openpty \ + strcasestr ]) dnl We prefer ptsname_r(), but will settle for ptsname() if necessary AC_TRY_LINK([#ifndef _XOPEN_SOURCE diff --git a/demo/vt100.js b/demo/vt100.js index 2080500..4bbc7b7 100644 --- a/demo/vt100.js +++ b/demo/vt100.js @@ -1500,7 +1500,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.8 (revision 122)" + + alert("VT100 Terminal Emulator " + "2.8 (revision 123)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); }; diff --git a/libhttp/httpconnection.c b/libhttp/httpconnection.c index 33361cd..f22e443 100644 --- a/libhttp/httpconnection.c +++ b/libhttp/httpconnection.c @@ -43,6 +43,7 @@ // The most up-to-date version of this program is always available from // http://shellinabox.com +#define _GNU_SOURCE #include "config.h" #include @@ -198,26 +199,48 @@ static void httpCloseRead(struct HttpConnection *http) { } } +#ifndef HAVE_STRCASESTR +static char *strcasestr(const char *haystack, const char *needle) { + // This algorithm is O(len(haystack)*len(needle)). Much better algorithms + // are available, but this code is much simpler and performance is not + // critical for our workloads. + int len = strlen(needle); + do { + if (!strncasecmp(haystack, needle, len)) { + return haystack; + } + } while (*haystack++); + return NULL; +} +#endif + static int httpFinishCommand(struct HttpConnection *http) { - int rc = HTTP_DONE; + int rc = HTTP_DONE; if (http->callback && !http->done) { - rc = http->callback(http, http->arg, NULL, 0); + rc = http->callback(http, http->arg, NULL, 0); check(rc != HTTP_SUSPEND); check(rc != HTTP_PARTIAL_REPLY); - http->callback = NULL; - http->arg = NULL; + http->callback = NULL; + http->arg = NULL; if (rc == HTTP_ERROR) { httpCloseRead(http); } } + if (!http->closed) { + const char *con = getFromHashMap(&http->header, "connection"); + if ((con && strcasestr(con, "close")) || + !http->version || strcmp(http->version, "HTTP/1.1") < 0) { + httpCloseRead(http); + } + } if (logIsInfo()) { check(http->method); check(http->path); check(http->version); if (http->peerName) { - time_t t = currentTime; + time_t t = currentTime; struct tm *ltime; - check (ltime = localtime(&t)); + check (ltime = localtime(&t)); char timeBuf[80]; char lengthBuf[40]; check(strftime(timeBuf, sizeof(timeBuf), @@ -225,7 +248,7 @@ static int httpFinishCommand(struct HttpConnection *http) { if (http->totalWritten > 0) { snprintf(lengthBuf, sizeof(lengthBuf), "%d", http->totalWritten); } else { - *lengthBuf = '\000'; + *lengthBuf = '\000'; strncat(lengthBuf, "-", sizeof(lengthBuf)-1); } info("%s - - %s \"%s %s %s\" %d %s", @@ -260,7 +283,9 @@ static char *getPeerName(int fd, int *port, int numericHosts) { if (port) { *port = ntohs(((struct sockaddr_in *)&peerAddr)->sin_port); } - return strdup(host); + char *ret; + check(ret = strdup(host)); + return ret; } static void httpSetState(struct HttpConnection *http, int state) { @@ -619,7 +644,7 @@ static int httpHandleCommand(struct HttpConnection *http, } if (query) { - http->query = strdup(query + 1); + check(http->query = strdup(query + 1)); } return h->handler(http, h->arg); } @@ -645,61 +670,61 @@ static int httpParseCommand(struct HttpConnection *http, int offset, if (firstSpace < 1 || lastSpace < 0) { bad_request: if (!http->method) { - http->method = strdup(""); + check(http->method = strdup("")); } if (!http->path) { - http->path = strdup(""); + check(http->path = strdup("")); } if (!http->version) { - http->version = strdup(""); + check(http->version = strdup("")); } httpSendReply(http, 400, "Bad Request", NO_MSG); httpSetState(http, COMMAND); return 0; } check(!http->method); - check(http->method = malloc(firstSpace + 1)); - int i = offset; - int j = 0; + check(http->method = malloc(firstSpace + 1)); + int i = offset; + int j = 0; for (; j < firstSpace; j++) { - int ch = httpGetChar(http, buf, bytes, &i); + int ch = httpGetChar(http, buf, bytes, &i); if (ch >= 'a' && ch <= 'z') { - ch &= ~0x20; + ch &= ~0x20; } - http->method[j] = ch; + http->method[j] = ch; } - http->method[j] = '\000'; + http->method[j] = '\000'; check(!http->path); - check(http->path = malloc(lastSpace - firstSpace)); - j = 0; + check(http->path = malloc(lastSpace - firstSpace)); + j = 0; while (i < offset + lastSpace) { - int ch = httpGetChar(http, buf, bytes, &i); + int ch = httpGetChar(http, buf, bytes, &i); if ((ch != ' ' && ch != '\t') || j) { - http->path[j++] = ch; + http->path[j++] = ch; } } - http->path[j] = '\000'; + http->path[j] = '\000'; if (*http->path != '/' && (strcmp(http->method, "OPTIONS") || strcmp(http->path, "*"))) { goto bad_request; } check(!http->version); - check(http->version = malloc(lineLength - lastSpace + 1)); - j = 0; + check(http->version = malloc(lineLength - lastSpace + 1)); + j = 0; while (i < offset + lineLength) { - int ch = httpGetChar(http, buf, bytes, &i); + int ch = httpGetChar(http, buf, bytes, &i); if (ch == '\r') { break; } if (ch >= 'a' && ch <= 'z') { - ch &= ~0x20; + ch &= ~0x20; } if ((ch != ' ' && ch != '\t') || j) { - http->version[j] = ch; + http->version[j] = ch; j++; } } - http->version[j] = '\000'; + http->version[j] = '\000'; if (memcmp(http->version, "HTTP/", 5) || (http->version[5] < '1' || http->version[5] > '9')) { goto bad_request; @@ -748,7 +773,7 @@ static int httpParseHeaders(struct HttpConnection *http, struct ServerConnection *connection = httpGetServerConnection(http); switch (rc) { case HTTP_DONE: - case HTTP_ERROR: + case HTTP_ERROR: { if (http->expecting < 0 || rc == HTTP_ERROR) { httpCloseRead(http); } @@ -759,7 +784,7 @@ static int httpParseHeaders(struct HttpConnection *http, serverSetTimeout(connection, CONNECTION_TIMEOUT); } httpSetState(http, http->expecting ? DISCARD_PAYLOAD : COMMAND); - break; + break; } case HTTP_READ_MORE: http->isSuspended = 0; http->isPartialReply = 0; diff --git a/shellinabox/shell_in_a_box.js b/shellinabox/shell_in_a_box.js index 0d75eff..51435ae 100644 --- a/shellinabox/shell_in_a_box.js +++ b/shellinabox/shell_in_a_box.js @@ -355,7 +355,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) { }; ShellInABox.prototype.about = function() { - alert("Shell In A Box version " + "2.8 (revision 122)" + + alert("Shell In A Box version " + "2.8 (revision 123)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com" + (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ? diff --git a/shellinabox/vt100.js b/shellinabox/vt100.js index 2080500..4bbc7b7 100644 --- a/shellinabox/vt100.js +++ b/shellinabox/vt100.js @@ -1500,7 +1500,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.8 (revision 122)" + + alert("VT100 Terminal Emulator " + "2.8 (revision 123)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); };