mirror of https://github.com/nealey/eris.git
Fix second mime-type, add break-fnord script
This commit is contained in:
parent
f8c2f7604b
commit
451db45dad
4
CHANGES
4
CHANGES
|
@ -1,4 +1,8 @@
|
||||||
2:
|
2:
|
||||||
|
Remove Accept header parsing: it was broken and the result was
|
||||||
|
that the Accept header had no effect
|
||||||
|
Remove the .gz trick: I never used it, but I would not be averse
|
||||||
|
to adding it back if people liked it
|
||||||
Rename to "eris httpd" to acknowledge fork
|
Rename to "eris httpd" to acknowledge fork
|
||||||
Add regression test suite
|
Add regression test suite
|
||||||
Replace compile-time options with command-line ones
|
Replace compile-time options with command-line ones
|
||||||
|
|
46
README
46
README
|
@ -1,17 +1,18 @@
|
||||||
Eris HTTPD is a part of Dirtbags Capture The Flag
|
Eris HTTPD is a part of Dirtbags Capture The Flag
|
||||||
(http://dirtbags.net/ctf/). As I was adding more and more patches
|
(http://dirtbags.net/ctf/). As I was adding more and more patches
|
||||||
against fnord 1.10 (http://www.fefe.de), I decided to fork fnord into
|
against fnord 1.10 (http://www.fefe.de/), I decided to fork fnord into
|
||||||
a new project. Fnord's author, Fefe, approved of the fork.
|
a new project. Fnord's author approved of the fork.
|
||||||
|
|
||||||
The differences between eris and fnord are:
|
Significant differences between eris and fnord are:
|
||||||
|
|
||||||
* command-line arguments instead of compile-time defines
|
* command-line arguments instead of compile-time defines
|
||||||
* eliminated use of libowfat
|
* eliminated use of libowfat
|
||||||
* no build dependency of dietlibc
|
* no build dependency of dietlibc
|
||||||
* elimination of "old style symlink handling"
|
* elimination of "old style symlink handling"
|
||||||
* elimination of user switching (use tcpserver)
|
* elimination of user switching (you can use tcpserver -[ug])
|
||||||
* elimination of chroot code (use chroot)
|
* elimination of chroot code (you can use chroot)
|
||||||
* several bugfixes (which have been sent to the fnord mail list)
|
* several bugfixes (sent to the fnord mail list)
|
||||||
|
* removal of (non-functional) content-negotiation
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -30,16 +31,16 @@ user agent with spaces replaced by underscores, the next token (none) is
|
||||||
the Referer HTTP header or "none" if none was given, and the rest of
|
the Referer HTTP header or "none" if none was given, and the rest of
|
||||||
each line is the decoded requested URL.
|
each line is the decoded requested URL.
|
||||||
|
|
||||||
eris httpd does simple virtual hosting. If the Host: HTTP header is
|
eris does simple virtual hosting. If the Host: HTTP header is there,
|
||||||
there, eris will try to chdir to a directory of that name, i.e. if the
|
eris will try to chdir to a directory of that name, i.e. if the client
|
||||||
client asks for "/" on host "www.fefe.de:80", eris will look for
|
asks for "/" on host "www.fefe.de", eris will look for
|
||||||
"www.fefe.de:80/index.html". Eris will also try the directory
|
"www.fefe.de/index.html". Eris will also try the directory "default"
|
||||||
"default" if no specific directory for the virtual host was there. If
|
if no specific directory for the virtual host was there. If the
|
||||||
the directory is a dangling symlink and eris was compiled with
|
directory is a dangling symlink, eris will redirect the whole site.
|
||||||
-DREDIRECT (default), eris will redirect the whole site. Examples:
|
Examples:
|
||||||
|
|
||||||
lrwxrwxrwx 1 leitner users 19 May 5 01:09 www.foo.de:80 -> http://www.baz.de/
|
lrwxrwxrwx 1 leitner users 19 May 5 01:09 www.foo.de -> http://www.baz.de/
|
||||||
lrwxrwxrwx 1 leitner users 20 May 5 01:12 www.bar.de:80 -> =http://www.baz.de/
|
lrwxrwxrwx 1 leitner users 20 May 5 01:12 www.bar.de -> =http://www.baz.de/
|
||||||
|
|
||||||
http://www.foo.de/blub.html will be redirected to http://www.baz.de/blub.html.
|
http://www.foo.de/blub.html will be redirected to http://www.baz.de/blub.html.
|
||||||
http://www.bar.de/blub.html will be redirected to http://www.baz.de/.
|
http://www.bar.de/blub.html will be redirected to http://www.baz.de/.
|
||||||
|
@ -59,18 +60,19 @@ symlink must point to a full URL, i.e.
|
||||||
|
|
||||||
ln -s ftp://foobar.math.fu-berlin.de/pub/dietlibc/dietlibc-0.11.tar.bz2 dietlibc-0.11.tar.bz2
|
ln -s ftp://foobar.math.fu-berlin.de/pub/dietlibc/dietlibc-0.11.tar.bz2 dietlibc-0.11.tar.bz2
|
||||||
|
|
||||||
eris implements in-place substitution of * to *.gz
|
|
||||||
if the file is available and the client supports the mime-type and
|
|
||||||
content-encoding. That means you can save substantial bandwidth by
|
|
||||||
having an index.html.gz for each index.html, as most clients can
|
|
||||||
transparently decode gzipped files.
|
|
||||||
|
|
||||||
eris will change dots at the start of file or directory names to colons
|
eris will change dots at the start of file or directory names to colons
|
||||||
in the query before trying to answer them.
|
in the query before trying to answer them.
|
||||||
|
|
||||||
eris understands and implements keep-alive connections.
|
eris understands and implements keep-alive connections.
|
||||||
|
|
||||||
eris can use sendfile on Linux to enable zero-copy TCP.
|
eris will use sendfile on Linux to enable zero-copy TCP.
|
||||||
|
|
||||||
|
If eris is given the -a option, it look for a file named ".http-auth"
|
||||||
|
in the root of the host directory. If it's found, eris will run it as
|
||||||
|
".http-auth $host $url" with the environment variable
|
||||||
|
"HTTP_AUTHORIZATION" set to the "Authorization" header sent by the
|
||||||
|
client. If the program returns 0, access will be granted; if it
|
||||||
|
returns 1, eris will return a 401 response.
|
||||||
|
|
||||||
If eris is given the -c option, it will regard files
|
If eris is given the -c option, it will regard files
|
||||||
whose names end with ".cgi" as CGI programs and try to execute them.
|
whose names end with ".cgi" as CGI programs and try to execute them.
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
## Breaking fnord 1.10
|
||||||
|
##
|
||||||
|
## Run this as "HTTPD=../eris ./break-fnord.sh" if you'd like to
|
||||||
|
## run these tests against a built eris HTTPD. It will fail the
|
||||||
|
## Accept test since eris ignores this.
|
||||||
|
|
||||||
|
if [ "$1" = "clean" ]; then
|
||||||
|
rm -rf fnord-1.10
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set HTTPD= to test something else
|
||||||
|
case ${HTTPD:=./fnord} in
|
||||||
|
*fnord)
|
||||||
|
: ${HTTPD_IDX:=$HTTPD-idx}
|
||||||
|
: ${HTTPD_CGI:=$HTTPD-cgi}
|
||||||
|
;;
|
||||||
|
*eris)
|
||||||
|
: ${HTTPD_IDX:=$HTTPD -d}
|
||||||
|
: ${HTTPD_CGI:=$HTTPD -c}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
title() {
|
||||||
|
printf "%-50s: " "$1"
|
||||||
|
tests=$(expr $tests + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
successes=0
|
||||||
|
pass () {
|
||||||
|
echo 'pass'
|
||||||
|
successes=$(expr $successes + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
failures=0
|
||||||
|
fail () {
|
||||||
|
echo 'fail'
|
||||||
|
failures=$(expr $failures + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if [ ! -f fnord-1.10.tar.bz2 ]; then
|
||||||
|
wget http://www.fefe.de/fnord/fnord-1.10.tar.bz2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f fnord-1.10/httpd.c ]; then
|
||||||
|
rm -rf fnord-1.10
|
||||||
|
bzcat fnord-1.10.tar.bz2 | tar xf -
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd fnord-1.10
|
||||||
|
make DIET=
|
||||||
|
|
||||||
|
if [ ! -d default ]; then
|
||||||
|
mkdir default
|
||||||
|
echo james > default/index.html
|
||||||
|
touch default/a
|
||||||
|
cat <<EOD > default/a.cgi
|
||||||
|
#! /bin/sh
|
||||||
|
echo 'Content-type: text/plain'
|
||||||
|
ls / > /dev/null # delay a little
|
||||||
|
echo
|
||||||
|
echo james
|
||||||
|
EOD
|
||||||
|
chmod +x default/a.cgi
|
||||||
|
mkdir empty:80
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOD
|
||||||
|
|
||||||
|
|
||||||
|
HTTPD: $HTTPD
|
||||||
|
CGI: $HTTPD_CGI
|
||||||
|
IDX: $HTTPD_IDX
|
||||||
|
-----------------------------------------
|
||||||
|
EOD
|
||||||
|
|
||||||
|
# 1. Should return directory listing of /; instead segfaults
|
||||||
|
title "Directory indexing of /"
|
||||||
|
printf 'GET / HTTP/1.0\r\nHost: empty\r\n\r\n' | $HTTPD_IDX 2>/dev/null | grep -q 200 && pass || fail
|
||||||
|
|
||||||
|
# 2. Should output \r\n\r\n; instead outputs \r\n\n
|
||||||
|
title "CGI output bare newlines"
|
||||||
|
printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | grep -qU '^\r$' && pass || fail
|
||||||
|
|
||||||
|
# 3. Should process both requests; instead drops second
|
||||||
|
title "Multiple requests in one packet"
|
||||||
|
printf 'GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive\r\n\r\nGET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive\r\n\r\n' | $HTTPD 2>/dev/null | grep -c '^HTTP/1.' | grep -q 2 && pass || fail
|
||||||
|
|
||||||
|
# 4. Should return 406 Not Acceptable; instead ignores Accept header
|
||||||
|
title "Accept header"
|
||||||
|
printf 'GET / HTTP/1.0\r\nAccept: nothing\r\n\r\n' | $HTTPD 2>/dev/null | grep 406 && pass || fail
|
||||||
|
|
||||||
|
# 5. Should serve second request as default MIME-Type (text/plain); instead uses previous mime type
|
||||||
|
title "Second MIME-Type"
|
||||||
|
(printf 'GET / HTTP/1.1\r\nHost: a\r\nConnection: keep-alive\r\n\r\n'
|
||||||
|
ls / > /dev/null # Delay required to work around test #3
|
||||||
|
printf 'GET /a HTTP/1.1\r\nHost: a\r\nConnection: keep-alive\r\n\r\n') | $HTTPD 2>/dev/null | grep -q 'text/plain\|application/octet-stream' && pass || fail
|
||||||
|
|
||||||
|
cat <<EOD
|
||||||
|
-----------------------------------------
|
||||||
|
$successes of $tests tests passed ($failures failed).
|
||||||
|
EOD
|
||||||
|
|
||||||
|
exit $failures
|
200
eris.c
200
eris.c
|
@ -668,8 +668,7 @@ header(char *buf, int buflen, const char *hname)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *encoding = 0;
|
static const char *mimetype;
|
||||||
static char *mimetype = "application/octet-stream";
|
|
||||||
|
|
||||||
static struct mimeentry {
|
static struct mimeentry {
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@ -710,108 +709,32 @@ static struct mimeentry {
|
||||||
"xpm", "image/x-xpixmap"}, {
|
"xpm", "image/x-xpixmap"}, {
|
||||||
"xwd", "image/x-xwindowdump"}, {
|
"xwd", "image/x-xwindowdump"}, {
|
||||||
"ico", "image/x-icon"}, {
|
"ico", "image/x-icon"}, {
|
||||||
0}};
|
0, 0}};
|
||||||
|
|
||||||
|
static const char *default_mimetype = "application/octet-stream";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* try to find out MIME type and content encoding. This is called twice,
|
* Determine MIME type from file extension
|
||||||
* once for the actual URL and once for URL.gz. If the actual URL already
|
|
||||||
* ende with .gz, return application/octet-stream to make sure the client
|
|
||||||
* can download the file even if he does not support gzip encoding
|
|
||||||
*/
|
*/
|
||||||
static void
|
static const char *
|
||||||
getmimetype(char *url, int explicit)
|
getmimetype(char *url)
|
||||||
{
|
{
|
||||||
char save;
|
char *ext = strrchr(url, '.');
|
||||||
int ext;
|
|
||||||
ext = strlen(url);
|
|
||||||
while (ext > 0 && url[ext] != '.' && url[ext] != '/')
|
if (ext) {
|
||||||
--ext;
|
int i;
|
||||||
if (url[ext] == '.') {
|
|
||||||
++ext;
|
ext++;
|
||||||
if (!strcmp(url + ext, "bz2"))
|
for (i = 0; mimetab[i].name; ++i) {
|
||||||
goto octetstream;
|
if (!strcmp(mimetab[i].name, ext)) {
|
||||||
if (!strcmp(url + ext, "gz")) {
|
return mimetab[i].type;
|
||||||
if (!encoding) {
|
}
|
||||||
if (explicit)
|
|
||||||
goto octetstream;
|
|
||||||
encoding = "gzip";
|
|
||||||
save = url[ext - 1];
|
|
||||||
url[ext - 1] = 0;
|
|
||||||
getmimetype(url, explicit);
|
|
||||||
url[ext - 1] = save;
|
|
||||||
} else
|
|
||||||
octetstream:
|
|
||||||
mimetype = "application/octet-stream";
|
|
||||||
} else {
|
|
||||||
int i;
|
|
||||||
for (i = 0; mimetab[i].name; ++i)
|
|
||||||
if (!strcmp(mimetab[i].name, url + ext)) {
|
|
||||||
mimetype = (char *) mimetab[i].type;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return default_mimetype;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
matchcommalist(const char *needle, const char *haystack)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* needle: "text/html", haystack: the accept header, "text/html,
|
|
||||||
* text/plain\r\n"
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* return nonzero if match was found
|
|
||||||
*/
|
|
||||||
int len = strlen(needle);
|
|
||||||
|
|
||||||
DUMP_s(needle);
|
|
||||||
DUMP_s(haystack);
|
|
||||||
if (strncmp(needle, haystack, len))
|
|
||||||
return 0;
|
|
||||||
switch (haystack[len]) {
|
|
||||||
case ';':
|
|
||||||
case ',':
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
case 0:
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
findincommalist(const char *needle, const char *haystack)
|
|
||||||
{
|
|
||||||
const char *accept;
|
|
||||||
|
|
||||||
DUMP_s(needle);
|
|
||||||
DUMP_s(haystack);
|
|
||||||
for (accept = haystack; accept;) {
|
|
||||||
/*
|
|
||||||
* format: foo/bar,
|
|
||||||
*/
|
|
||||||
const char *tmp = accept;
|
|
||||||
int final;
|
|
||||||
while (*tmp) {
|
|
||||||
if (*tmp == ';')
|
|
||||||
break;
|
|
||||||
else if (*tmp == ',')
|
|
||||||
break;
|
|
||||||
++tmp;
|
|
||||||
}
|
|
||||||
final = (*tmp == 0 || *tmp == ';');
|
|
||||||
DUMP_s(accept);
|
|
||||||
if (matchcommalist("*/*", accept))
|
|
||||||
break;
|
|
||||||
if (matchcommalist(haystack, accept))
|
|
||||||
break;
|
|
||||||
accept = tmp + 1;
|
|
||||||
if (final)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* timerfc function Copyright 1996, Michiel Boland.
|
* timerfc function Copyright 1996, Michiel Boland.
|
||||||
|
@ -1001,45 +924,14 @@ static struct stat st;
|
||||||
* try to return a file
|
* try to return a file
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
doit(char *headerbuf, size_t headerlen, char *url, int explicit)
|
doit(char *headerbuf, size_t headerlen, char *url)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
char *accept;
|
char *accept;
|
||||||
|
|
||||||
while (url[0] == '/')
|
while (url[0] == '/')
|
||||||
++url;
|
++url;
|
||||||
getmimetype(url, explicit);
|
mimetype = getmimetype(url);
|
||||||
{
|
|
||||||
char *b = headerbuf;
|
|
||||||
int l = headerlen;
|
|
||||||
for (;;) {
|
|
||||||
char *h = header(b, l, "Accept");
|
|
||||||
|
|
||||||
DUMP_p(h);
|
|
||||||
DUMP_s(h);
|
|
||||||
DUMP_s(mimetype);
|
|
||||||
if (!h)
|
|
||||||
goto ok;
|
|
||||||
if (findincommalist(mimetype, h)) {
|
|
||||||
DUMP();
|
|
||||||
goto ok;
|
|
||||||
}
|
|
||||||
l -= (h - b) + 1;
|
|
||||||
b = h + 1;
|
|
||||||
}
|
|
||||||
DUMP();
|
|
||||||
retcode = 406;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
ok:
|
|
||||||
DUMP();
|
|
||||||
if (encoding) { /* see if client accepts the encoding */
|
|
||||||
char *tmp =
|
|
||||||
header(headerbuf, headerlen, "Accept-Encoding");
|
|
||||||
if (!tmp || !strstr(tmp, "gzip")) {
|
|
||||||
retcode = 406;
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((fd = open(url, O_RDONLY)) >= 0) {
|
if ((fd = open(url, O_RDONLY)) >= 0) {
|
||||||
if (fstat(fd, &st))
|
if (fstat(fd, &st))
|
||||||
goto bad;
|
goto bad;
|
||||||
|
@ -1048,9 +940,6 @@ doit(char *headerbuf, size_t headerlen, char *url, int explicit)
|
||||||
*/
|
*/
|
||||||
if (S_ISDIR(st.st_mode))
|
if (S_ISDIR(st.st_mode))
|
||||||
goto bad;
|
goto bad;
|
||||||
/*
|
|
||||||
* see if the peer accepts MIME type
|
|
||||||
*/
|
|
||||||
/*
|
/*
|
||||||
* see if the document has been changed
|
* see if the document has been changed
|
||||||
*/
|
*/
|
||||||
|
@ -1502,6 +1391,7 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
char headerbuf[MAXHEADERLEN];
|
char headerbuf[MAXHEADERLEN];
|
||||||
char *nurl,
|
char *nurl,
|
||||||
*origurl;
|
*origurl;
|
||||||
|
int doauth = 0;
|
||||||
int docgi = 0;
|
int docgi = 0;
|
||||||
int dirlist = 0;
|
int dirlist = 0;
|
||||||
int redirect = 0;
|
int redirect = 0;
|
||||||
|
@ -1511,8 +1401,11 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
{
|
{
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
while (-1 != (opt = getopt(argc, argv, "cdrp"))) {
|
while (-1 != (opt = getopt(argc, argv, "acdrp"))) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
|
case 'a':
|
||||||
|
doauth = 1;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
docgi = 1;
|
docgi = 1;
|
||||||
break;
|
break;
|
||||||
|
@ -1539,7 +1432,6 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
get_ucspi_env();
|
get_ucspi_env();
|
||||||
|
|
||||||
handlenext:
|
handlenext:
|
||||||
encoding = 0;
|
|
||||||
|
|
||||||
alarm(READTIMEOUT);
|
alarm(READTIMEOUT);
|
||||||
|
|
||||||
|
@ -1741,8 +1633,8 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef AUTH
|
|
||||||
{
|
if (doauth) {
|
||||||
char *auth_script = ".http-auth";
|
char *auth_script = ".http-auth";
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
|
@ -1756,12 +1648,10 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
badrequest(500, "Internal Server Error",
|
badrequest(500, "Internal Server Error",
|
||||||
"Server Resource problem.");
|
"Server Resource problem.");
|
||||||
} else if (child == 0) {
|
} else if (child == 0) {
|
||||||
const char *argv[5] =
|
|
||||||
{ auth_script, host, url, authorization, NULL };
|
|
||||||
|
|
||||||
dup2(2, 1);
|
dup2(2, 1);
|
||||||
execve(auth_script, argv, envp);
|
setenv("HTTP_AUTHORIZATION", authorization, 1);
|
||||||
_exit(1);
|
execl(auth_script, auth_script, host, url, NULL);
|
||||||
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
int status;
|
int status;
|
||||||
pid_t childr;
|
pid_t childr;
|
||||||
|
@ -1786,7 +1676,7 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* AUTH */
|
|
||||||
nurl = url + strlen(url);
|
nurl = url + strlen(url);
|
||||||
if (nurl > url)
|
if (nurl > url)
|
||||||
--nurl;
|
--nurl;
|
||||||
|
@ -1847,27 +1737,10 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
|
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
if ((fd = doit(headerbuf, headerlen, url, 1)) >= 0) { /* file
|
if ((fd = doit(headerbuf, headerlen, url)) >= 0) {
|
||||||
* was
|
|
||||||
* there */
|
|
||||||
/*
|
/*
|
||||||
* look if file.gz is also there and acceptable
|
* file was there
|
||||||
*/
|
*/
|
||||||
int ul = strlen(url);
|
|
||||||
char *fnord = alloca(ul + 4);
|
|
||||||
int fd2;
|
|
||||||
char *oldencoding = encoding;
|
|
||||||
|
|
||||||
strcpy(fnord, url);
|
|
||||||
strcpy(fnord + ul, ".gz");
|
|
||||||
fd2 = doit(headerbuf, headerlen, fnord, 0);
|
|
||||||
if (fd2 >= 0) { /* yeah! */
|
|
||||||
url = fnord;
|
|
||||||
close(fd);
|
|
||||||
fd = fd2;
|
|
||||||
} else {
|
|
||||||
encoding = oldencoding;
|
|
||||||
}
|
|
||||||
retcode = 200;
|
retcode = 200;
|
||||||
dolog(st.st_size);
|
dolog(st.st_size);
|
||||||
if (rangestart || rangeend != st.st_size)
|
if (rangestart || rangeend != st.st_size)
|
||||||
|
@ -1885,9 +1758,6 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
fputs("Connection: Keep-Alive\r\n", stdout);
|
fputs("Connection: Keep-Alive\r\n", stdout);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (encoding) {
|
|
||||||
printf("Content-Encoding: %s\r\n", encoding);
|
|
||||||
}
|
|
||||||
printf("Content-Length: %llu\r\n",
|
printf("Content-Length: %llu\r\n",
|
||||||
(unsigned long long) (rangeend - rangestart));
|
(unsigned long long) (rangeend - rangestart));
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue