Respect "Connection: close" if sent by the browser.

git-svn-id: https://shellinabox.googlecode.com/svn/trunk@123 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
zodiac@gmail.com 2009-06-21 18:51:14 +00:00
parent db631d5e35
commit 2c090c8beb
8 changed files with 74 additions and 40 deletions

View file

@ -70,6 +70,9 @@
/* Define to 1 if you have the <stdlib.h> header file. */ /* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1 #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 <strings.h> header file. */ /* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1 #define HAVE_STRINGS_H 1
@ -129,7 +132,7 @@
#define STDC_HEADERS 1 #define STDC_HEADERS 1
/* Most recent revision number in the version control system */ /* Most recent revision number in the version control system */
#define VCS_REVISION "122" #define VCS_REVISION "123"
/* Version number of package */ /* Version number of package */
#define VERSION "2.8" #define VERSION "2.8"

View file

@ -69,6 +69,9 @@
/* Define to 1 if you have the <stdlib.h> header file. */ /* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H #undef HAVE_STDLIB_H
/* Define to 1 if you have the `strcasestr' function. */
#undef HAVE_STRCASESTR
/* Define to 1 if you have the <strings.h> header file. */ /* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H #undef HAVE_STRINGS_H

6
configure vendored
View file

@ -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 ac_compiler_gnu=$ac_cv_c_compiler_gnu
VCS_REVISION=122 VCS_REVISION=123
cat >>confdefs.h <<_ACEOF 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 do
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5

View file

@ -2,7 +2,7 @@ AC_PREREQ(2.57)
dnl This is the one location where the authoritative version number is stored dnl This is the one location where the authoritative version number is stored
AC_INIT(shellinabox, 2.8, markus@shellinabox.com) AC_INIT(shellinabox, 2.8, markus@shellinabox.com)
VCS_REVISION=122 VCS_REVISION=123
AC_SUBST(VCS_REVISION) AC_SUBST(VCS_REVISION)
AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
[Most recent revision number in the version control system]) [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]) AC_CHECK_FUNCS([strlcat])
dnl Prefer thread-safe functions, if available 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 dnl We prefer ptsname_r(), but will settle for ptsname() if necessary
AC_TRY_LINK([#ifndef _XOPEN_SOURCE AC_TRY_LINK([#ifndef _XOPEN_SOURCE

View file

@ -1500,7 +1500,7 @@ VT100.prototype.toggleBell = function() {
}; };
VT100.prototype.about = 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" + "\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com"); "For more information check http://shellinabox.com");
}; };

View file

@ -43,6 +43,7 @@
// The most up-to-date version of this program is always available from // The most up-to-date version of this program is always available from
// http://shellinabox.com // http://shellinabox.com
#define _GNU_SOURCE
#include "config.h" #include "config.h"
#include <errno.h> #include <errno.h>
@ -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) { static int httpFinishCommand(struct HttpConnection *http) {
int rc = HTTP_DONE; int rc = HTTP_DONE;
if (http->callback && !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_SUSPEND);
check(rc != HTTP_PARTIAL_REPLY); check(rc != HTTP_PARTIAL_REPLY);
http->callback = NULL; http->callback = NULL;
http->arg = NULL; http->arg = NULL;
if (rc == HTTP_ERROR) { if (rc == HTTP_ERROR) {
httpCloseRead(http); 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()) { if (logIsInfo()) {
check(http->method); check(http->method);
check(http->path); check(http->path);
check(http->version); check(http->version);
if (http->peerName) { if (http->peerName) {
time_t t = currentTime; time_t t = currentTime;
struct tm *ltime; struct tm *ltime;
check (ltime = localtime(&t)); check (ltime = localtime(&t));
char timeBuf[80]; char timeBuf[80];
char lengthBuf[40]; char lengthBuf[40];
check(strftime(timeBuf, sizeof(timeBuf), check(strftime(timeBuf, sizeof(timeBuf),
@ -225,7 +248,7 @@ static int httpFinishCommand(struct HttpConnection *http) {
if (http->totalWritten > 0) { if (http->totalWritten > 0) {
snprintf(lengthBuf, sizeof(lengthBuf), "%d", http->totalWritten); snprintf(lengthBuf, sizeof(lengthBuf), "%d", http->totalWritten);
} else { } else {
*lengthBuf = '\000'; *lengthBuf = '\000';
strncat(lengthBuf, "-", sizeof(lengthBuf)-1); strncat(lengthBuf, "-", sizeof(lengthBuf)-1);
} }
info("%s - - %s \"%s %s %s\" %d %s", info("%s - - %s \"%s %s %s\" %d %s",
@ -260,7 +283,9 @@ static char *getPeerName(int fd, int *port, int numericHosts) {
if (port) { if (port) {
*port = ntohs(((struct sockaddr_in *)&peerAddr)->sin_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) { static void httpSetState(struct HttpConnection *http, int state) {
@ -619,7 +644,7 @@ static int httpHandleCommand(struct HttpConnection *http,
} }
if (query) { if (query) {
http->query = strdup(query + 1); check(http->query = strdup(query + 1));
} }
return h->handler(http, h->arg); return h->handler(http, h->arg);
} }
@ -645,61 +670,61 @@ static int httpParseCommand(struct HttpConnection *http, int offset,
if (firstSpace < 1 || lastSpace < 0) { if (firstSpace < 1 || lastSpace < 0) {
bad_request: bad_request:
if (!http->method) { if (!http->method) {
http->method = strdup(""); check(http->method = strdup(""));
} }
if (!http->path) { if (!http->path) {
http->path = strdup(""); check(http->path = strdup(""));
} }
if (!http->version) { if (!http->version) {
http->version = strdup(""); check(http->version = strdup(""));
} }
httpSendReply(http, 400, "Bad Request", NO_MSG); httpSendReply(http, 400, "Bad Request", NO_MSG);
httpSetState(http, COMMAND); httpSetState(http, COMMAND);
return 0; return 0;
} }
check(!http->method); check(!http->method);
check(http->method = malloc(firstSpace + 1)); check(http->method = malloc(firstSpace + 1));
int i = offset; int i = offset;
int j = 0; int j = 0;
for (; j < firstSpace; j++) { for (; j < firstSpace; j++) {
int ch = httpGetChar(http, buf, bytes, &i); int ch = httpGetChar(http, buf, bytes, &i);
if (ch >= 'a' && ch <= 'z') { 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);
check(http->path = malloc(lastSpace - firstSpace)); check(http->path = malloc(lastSpace - firstSpace));
j = 0; j = 0;
while (i < offset + lastSpace) { while (i < offset + lastSpace) {
int ch = httpGetChar(http, buf, bytes, &i); int ch = httpGetChar(http, buf, bytes, &i);
if ((ch != ' ' && ch != '\t') || j) { if ((ch != ' ' && ch != '\t') || j) {
http->path[j++] = ch; http->path[j++] = ch;
} }
} }
http->path[j] = '\000'; http->path[j] = '\000';
if (*http->path != '/' && if (*http->path != '/' &&
(strcmp(http->method, "OPTIONS") || strcmp(http->path, "*"))) { (strcmp(http->method, "OPTIONS") || strcmp(http->path, "*"))) {
goto bad_request; goto bad_request;
} }
check(!http->version); check(!http->version);
check(http->version = malloc(lineLength - lastSpace + 1)); check(http->version = malloc(lineLength - lastSpace + 1));
j = 0; j = 0;
while (i < offset + lineLength) { while (i < offset + lineLength) {
int ch = httpGetChar(http, buf, bytes, &i); int ch = httpGetChar(http, buf, bytes, &i);
if (ch == '\r') { if (ch == '\r') {
break; break;
} }
if (ch >= 'a' && ch <= 'z') { if (ch >= 'a' && ch <= 'z') {
ch &= ~0x20; ch &= ~0x20;
} }
if ((ch != ' ' && ch != '\t') || j) { if ((ch != ' ' && ch != '\t') || j) {
http->version[j] = ch; http->version[j] = ch;
j++; j++;
} }
} }
http->version[j] = '\000'; http->version[j] = '\000';
if (memcmp(http->version, "HTTP/", 5) || if (memcmp(http->version, "HTTP/", 5) ||
(http->version[5] < '1' || http->version[5] > '9')) { (http->version[5] < '1' || http->version[5] > '9')) {
goto bad_request; goto bad_request;
@ -748,7 +773,7 @@ static int httpParseHeaders(struct HttpConnection *http,
struct ServerConnection *connection = httpGetServerConnection(http); struct ServerConnection *connection = httpGetServerConnection(http);
switch (rc) { switch (rc) {
case HTTP_DONE: case HTTP_DONE:
case HTTP_ERROR: case HTTP_ERROR: {
if (http->expecting < 0 || rc == HTTP_ERROR) { if (http->expecting < 0 || rc == HTTP_ERROR) {
httpCloseRead(http); httpCloseRead(http);
} }
@ -759,7 +784,7 @@ static int httpParseHeaders(struct HttpConnection *http,
serverSetTimeout(connection, CONNECTION_TIMEOUT); serverSetTimeout(connection, CONNECTION_TIMEOUT);
} }
httpSetState(http, http->expecting ? DISCARD_PAYLOAD : COMMAND); httpSetState(http, http->expecting ? DISCARD_PAYLOAD : COMMAND);
break; break; }
case HTTP_READ_MORE: case HTTP_READ_MORE:
http->isSuspended = 0; http->isSuspended = 0;
http->isPartialReply = 0; http->isPartialReply = 0;

View file

@ -355,7 +355,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) {
}; };
ShellInABox.prototype.about = function() { 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" + "\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com" + "For more information check http://shellinabox.com" +
(typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ? (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?

View file

@ -1500,7 +1500,7 @@ VT100.prototype.toggleBell = function() {
}; };
VT100.prototype.about = 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" + "\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com"); "For more information check http://shellinabox.com");
}; };