Simplify the code that compresses HTTP replies. This also gives us the ability

to manipulate headers more easily. We now add "Connection: close" in more cases
where we force a closing of the connection.


git-svn-id: https://shellinabox.googlecode.com/svn/trunk@171 0da03de8-d603-11dd-86c2-0f8696b7b6f9
This commit is contained in:
zodiac 2009-08-15 22:55:02 +00:00
parent e3a4eb95e3
commit 161e848e23
7 changed files with 123 additions and 52 deletions

View file

@ -138,7 +138,7 @@
#define STDC_HEADERS 1
/* Most recent revision number in the version control system */
#define VCS_REVISION "170"
#define VCS_REVISION "171"
/* Version number of package */
#define VERSION "2.9"

2
configure vendored
View file

@ -2317,7 +2317,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $
ac_compiler_gnu=$ac_cv_c_compiler_gnu
VCS_REVISION=170
VCS_REVISION=171
cat >>confdefs.h <<_ACEOF

View file

@ -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.9, markus@shellinabox.com)
VCS_REVISION=170
VCS_REVISION=171
AC_SUBST(VCS_REVISION)
AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
[Most recent revision number in the version control system])

View file

@ -1892,7 +1892,7 @@ VT100.prototype.toggleBell = function() {
};
VT100.prototype.about = function() {
alert("VT100 Terminal Emulator " + "2.9 (revision 170)" +
alert("VT100 Terminal Emulator " + "2.9 (revision 171)" +
"\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com");
};

View file

@ -66,6 +66,8 @@
#ifdef HAVE_STRLCAT
#define strncat(a,b,c) ({ char *_a = (a); strlcat(_a, (b), (c)+1); _a; })
#endif
#define max(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); \
_a > _b ? _a : _b; })
#include "libhttp/httpconnection.h"
#include "logging/logging.h"
@ -488,6 +490,58 @@ static int httpAcceptsEncoding(struct HttpConnection *http,
}
#endif
static void removeHeader(char *header, int *headerLength, const char *id) {
check(header);
check(headerLength);
check(*headerLength >= 0);
check(id);
check(strchr(id, ':'));
int idLength = strlen(id);
if (idLength <= 0) {
return;
}
for (char *ptr = header; header + *headerLength - ptr >= idLength; ) {
char *end = ptr;
do {
end = memchr(end, '\n', header + *headerLength - end);
if (end == NULL) {
end = header + *headerLength;
} else {
++end;
}
} while (end < header + *headerLength && *end == ' ');
if (!strncasecmp(ptr, id, idLength)) {
memmove(ptr, end, header + *headerLength - end);
*headerLength -= end - ptr;
} else {
ptr = end;
}
}
}
static void addHeader(char **header, int *headerLength, const char *fmt, ...) {
check(header);
check(headerLength);
check(*headerLength >= 0);
check(strstr(fmt, "\r\n"));
va_list ap;
va_start(ap, fmt);
char *tmp = vStringPrintf(NULL, fmt, ap);
va_end(ap);
int tmpLength = strlen(tmp);
if (*headerLength >= 2 && !memcmp(*header + *headerLength - 2, "\r\n", 2)) {
*headerLength -= 2;
}
check(*header = realloc(*header, *headerLength + tmpLength + 2));
memcpy(*header + *headerLength, tmp, tmpLength);
memcpy(*header + *headerLength + tmpLength, "\r\n", 2);
*headerLength += tmpLength + 2;
free(tmp);
}
void httpTransfer(struct HttpConnection *http, char *msg, int len) {
check(msg);
check(len >= 0);
@ -502,8 +556,11 @@ void httpTransfer(struct HttpConnection *http, char *msg, int len) {
ieBug++;
}
char *header = NULL;
int headerLength = 0;
int bodyOffset = 0;
int compress = 0;
char *contentLength = NULL;
if (!http->totalWritten) {
// Perform some basic sanity checks. This does not necessarily catch all
// possible problems, though.
@ -549,12 +606,6 @@ void httpTransfer(struct HttpConnection *http, char *msg, int len) {
// lines
if (*line != ' ' && *line != '\t') {
check(memchr(line, ':', eol - line));
// Remember where we saw the Content-Length header. We need to edit
// it, if we end up sending compressed data
if (!strncasecmp(line, "Content-Length:", 15)) {
contentLength = line;
}
}
}
lastLine = line;
@ -562,41 +613,34 @@ void httpTransfer(struct HttpConnection *http, char *msg, int len) {
line = eol + 1;
}
if (compress) {
#ifdef HAVE_ZLIB
// Create a copy of msg, and edit existing Content-Length line
// out of header.
char *compressed, *ptr;
check(compressed = malloc(len + 100));
if (contentLength) {
memcpy(compressed, msg, contentLength - msg);
char *part2 = strchr(contentLength, '\n');
check(part2++);
memcpy(compressed + (contentLength - msg), part2, line - part2);
ptr = compressed + (contentLength - msg) +
(line - part2);
} else {
memcpy(compressed, msg, line - msg);
ptr = compressed + (line - msg);
if (ieBug || compress) {
if (l >= 2 && !memcmp(line, "\r\n", 2)) {
line += 2;
l -= 2;
}
headerLength = line - msg;
bodyOffset = headerLength;
check(header = malloc(headerLength));
memcpy(header, msg, headerLength);
}
if (ieBug) {
removeHeader(header, &headerLength, "connection:");
addHeader(&header, &headerLength, "Connection: close\r\n");
}
// Add new Content-Encoding and new Content-Length lines. Leave enough
// space to later edit the actual length back in.
memcpy(ptr,
"Content-Encoding: deflate\r\n"
"Content-Length: \r\n\r\n",
66);
contentLength = ptr + 42;
ptr += 66;
if (compress) {
#ifdef HAVE_ZLIB
// Compress the message
char *compressed;
check(compressed = malloc(len));
check(len >= bodyOffset + 2);
z_stream strm = { .zalloc = Z_NULL,
.zfree = Z_NULL,
.opaque = Z_NULL,
.avail_in = l - 2,
.next_in = (unsigned char *)line + 2,
.avail_out = len - (ptr - compressed),
.next_out = (unsigned char *)ptr
.avail_out = len,
.next_out = (unsigned char *)compressed
};
if (deflateInit(&strm, Z_DEFAULT_COMPRESSION) == Z_OK) {
if (deflate(&strm, Z_FINISH) == Z_STREAM_END) {
@ -605,9 +649,11 @@ void httpTransfer(struct HttpConnection *http, char *msg, int len) {
free(msg);
msg = compressed;
len -= strm.avail_out;
snprintf(contentLength, 21, "%20lu",
(unsigned long)(len - (ptr - compressed)));
contentLength[20] = '\r';
bodyOffset = 0;
removeHeader(header, &headerLength, "content-length:");
removeHeader(header, &headerLength, "content-encoding:");
addHeader(&header, &headerLength, "Content-Length: %d\r\n", len);
addHeader(&header, &headerLength, "Content-Encoding: deflate\r\n");
} else {
free(compressed);
}
@ -619,25 +665,50 @@ void httpTransfer(struct HttpConnection *http, char *msg, int len) {
}
}
http->totalWritten += len;
if (!len) {
free(msg);
http->totalWritten += headerLength + (len - bodyOffset);
if (!headerLength) {
free(header);
} else if (http->msg) {
check(http->msg = realloc(http->msg,
http->msgLength - http->msgOffset + len));
http->msgLength - http->msgOffset +
max(http->msgOffset, headerLength)));
if (http->msgOffset) {
memmove(http->msg, http->msg + http->msgOffset,
http->msgLength - http->msgOffset);
http->msgLength -= http->msgOffset;
http->msgOffset = 0;
}
memcpy(http->msg + http->msgLength, msg, len);
http->msgLength += len;
memcpy(http->msg + http->msgLength, header, headerLength);
http->msgLength += headerLength;
free(header);
} else {
check(!http->msgOffset);
http->msg = header;
http->msgLength = headerLength;
}
if (len <= bodyOffset) {
free(msg);
} else if (http->msg) {
check(http->msg = realloc(http->msg,
http->msgLength - http->msgOffset +
max(http->msgOffset, len - bodyOffset)));
if (http->msgOffset) {
memmove(http->msg, http->msg + http->msgOffset,
http->msgLength - http->msgOffset);
http->msgLength -= http->msgOffset;
http->msgOffset = 0;
}
memcpy(http->msg + http->msgLength, msg + bodyOffset, len - bodyOffset);
http->msgLength += len - bodyOffset;
free(msg);
} else {
check(!http->msgOffset);
if (bodyOffset) {
memmove(msg, msg + bodyOffset, len - bodyOffset);
}
http->msg = msg;
http->msgLength = len;
http->msgLength = len - bodyOffset;
}
// The caller can suspend the connection, so that it can send an
@ -686,7 +757,7 @@ void httpTransfer(struct HttpConnection *http, char *msg, int len) {
}
}
if (http->sslHndl && ieBug) {
if (ieBug) {
httpCloseRead(http);
}
}

View file

@ -355,7 +355,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) {
};
ShellInABox.prototype.about = function() {
alert("Shell In A Box version " + "2.9 (revision 170)" +
alert("Shell In A Box version " + "2.9 (revision 171)" +
"\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com" +
(typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?

View file

@ -1892,7 +1892,7 @@ VT100.prototype.toggleBell = function() {
};
VT100.prototype.about = function() {
alert("VT100 Terminal Emulator " + "2.9 (revision 170)" +
alert("VT100 Terminal Emulator " + "2.9 (revision 171)" +
"\nCopyright 2008-2009 by Markus Gutschke\n" +
"For more information check http://shellinabox.com");
};