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:
parent
db631d5e35
commit
2c090c8beb
8 changed files with 74 additions and 40 deletions
5
config.h
5
config.h
|
@ -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"
|
||||||
|
|
|
@ -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
6
configure
vendored
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ?
|
||||||
|
|
|
@ -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");
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue