mirror of https://github.com/nealey/eris.git
Compare commits
59 Commits
Author | SHA1 | Date |
---|---|---|
Neale Pickett | 16e32a6d59 | |
Neale Pickett | 49b1797df5 | |
musvaage | ce6b071398 | |
Neale Pickett | 2acfd4cf2d | |
Neale Pickett | d524cc02d5 | |
Neale Pickett | 2e1a3eb867 | |
Neale Pickett | 48dbc0e8e0 | |
Neale Pickett | 673aed81a2 | |
Neale Pickett | 855815099a | |
Neale Pickett | f63b3f1732 | |
Neale Pickett | 6dd03561d6 | |
Neale Pickett | 48bb066488 | |
Neale Pickett | 77c3ed33dd | |
Neale Pickett | 86a75813e3 | |
Neale Pickett | c3ddfae1ff | |
Neale Pickett | bdb9f0ac05 | |
Neale Pickett | b3c4786482 | |
Neale Pickett | 9de87a3e36 | |
Neale Pickett | ecad076ec6 | |
Neale Pickett | 86757101eb | |
Neale Pickett | 68452c56fa | |
Neale Pickett | aab1b7496b | |
Neale Pickett | 6121939bf0 | |
Neale Pickett | 7a4ac95441 | |
Neale Pickett | 76c46f481e | |
Neale Pickett | c329e9ad8a | |
Neale Pickett | 8cb25b363d | |
Neale Pickett | 502347d9df | |
Neale Pickett | 0b4f892169 | |
Neale Pickett | 297d6ec919 | |
Neale Pickett | c968d41b16 | |
Neale Pickett | eb9de7b610 | |
Neale Pickett | 4e2e46dfdb | |
Neale Pickett | 4b54e2b2f3 | |
Neale Pickett | e46094d637 | |
Neale Pickett | d70528481f | |
Neale Pickett | 90660eae48 | |
Neale Pickett | 78dec35acd | |
Neale Pickett | 47ab2f0833 | |
Neale Pickett | 1edc4dff77 | |
Neale Pickett | 747cd86e65 | |
Neale Pickett | c73f0b6d0d | |
Neale Pickett | b9d6c8ce98 | |
Neale Pickett | f0cd1af781 | |
Neale Pickett | 25600693cc | |
Neale Pickett | 1a707fea54 | |
Neale Pickett | c520aa22ae | |
Neale Pickett | aaf9c85731 | |
Neale Pickett | 9683c12bbd | |
Neale Pickett | f56fbd7477 | |
Neale Pickett | 6af696b8ec | |
Neale Pickett | b4cb8c1e96 | |
Neale Pickett | dcb83f3e47 | |
Neale Pickett | ef9e02251d | |
Neale Pickett | 9f2749512f | |
Neale Pickett | d63e957ee3 | |
Neale Pickett | 19950e5b3b | |
Neale Pickett | 81d2a1a5d7 | |
Neale Pickett | 49f6374ff0 |
|
@ -0,0 +1,2 @@
|
|||
*.o
|
||||
version.h
|
252
CHANGES
252
CHANGES
|
@ -1,127 +1,175 @@
|
|||
fix punctuation and typo
|
||||
|
||||
4.4:
|
||||
Also log when called from stunnel
|
||||
|
||||
4.3.1:
|
||||
Add .webm mime type
|
||||
|
||||
4.3:
|
||||
Very stupid CONNECT handling mechanism.
|
||||
|
||||
4.2:
|
||||
Remove some bugs in CGI's "Status:" code (reported by Alyssa Milburn).
|
||||
Make extract_header_field less fragile (reported by Alyssa Milburn).
|
||||
Possibly fix fake_sendfile (reported by Alyssa Milburn).
|
||||
|
||||
4.1:
|
||||
Fix 0.9 not detected with query_string (Alyssa Milburn).
|
||||
|
||||
4.0:
|
||||
Fix directory traversal vulnerability (Alyssa Milburn).
|
||||
|
||||
3.1.4:
|
||||
Have 304 (Not Modified) responses generate a log entry.
|
||||
|
||||
3.1.3:
|
||||
Have directory indexes generate a log entry.
|
||||
Remove nop -a option.
|
||||
Add some accessories in contrib/
|
||||
|
||||
3.1.2:
|
||||
Change how version is extracted from CHANGES, to deal with
|
||||
build systems that set CFLAGS.
|
||||
Stop hating Ryan Finnie.
|
||||
|
||||
3.1.1:
|
||||
Restructure code to make it easier to package for Debian.
|
||||
I hate you so much right now, Ryan Finnie.
|
||||
|
||||
3.1:
|
||||
Add -. flag to disable vhosting
|
||||
Support server push CGI
|
||||
Handle busybox tcpsvd
|
||||
Changed formatting of directory indexing
|
||||
Handle read timeout
|
||||
Fix if-modified-since bug with keepalive connections
|
||||
Change to CGI's directory on exec
|
||||
|
||||
3.0:
|
||||
More or less a ground-up rewrite. A few fnord parts remain
|
||||
here and there.
|
||||
More or less a ground-up rewrite. A few fnord parts remain
|
||||
here and there.
|
||||
|
||||
2.0:
|
||||
Replace poll with select, which is more portable and may be
|
||||
slightly faster; however, it's only called for CGI and by
|
||||
that point you've lost quite a bit in terms of speed
|
||||
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
|
||||
Add regression test suite
|
||||
Replace compile-time options with command-line ones
|
||||
Fix segfault with directory listing of /
|
||||
Replace buffer_1 and buffer_2 with stdio
|
||||
Replace libowfat with libc
|
||||
Add all patches from (defunct) Debian package
|
||||
Fix if-modified-since date parsing
|
||||
Make text content-types use charset=UTF-8
|
||||
Change default content-type to application/octet-stream
|
||||
Makefile no longer overrides CC and CPP from parent makes
|
||||
Don't send Content-type if there's no content
|
||||
New maintainer: Neale Pickett <neale@woozle.org>
|
||||
Replace poll with select, which is more portable and may be
|
||||
slightly faster; however, it's only called for CGI and by
|
||||
that point you've lost quite a bit in terms of speed
|
||||
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
|
||||
Add regression test suite
|
||||
Replace compile-time options with command-line ones
|
||||
Fix segfault with directory listing of /
|
||||
Replace buffer_1 and buffer_2 with stdio
|
||||
Replace libowfat with libc
|
||||
Add all patches from (defunct) Debian package
|
||||
Fix if-modified-since date parsing
|
||||
Make text content-types use charset=UTF-8
|
||||
Change default content-type to application/octet-stream
|
||||
Makefile no longer overrides CC and CPP from parent makes
|
||||
Don't send Content-type if there's no content
|
||||
New maintainer: Neale Pickett <neale@woozle.org>
|
||||
|
||||
1.10:
|
||||
have fallback in case sendfile fails
|
||||
have fallback in case sendfile fails
|
||||
|
||||
1.9:
|
||||
chdir to cgi's base dir (Kuba Winnicki)
|
||||
set HTTP_ACCEPT_ENCODING environment variable (Kuba Winnicki)
|
||||
We actually should export all HTTP headers as HTTP_[header]
|
||||
Any takers?
|
||||
Try not to send error message HTTP headers if we already sent the
|
||||
headers from the CGI (Kuba Winnicki)
|
||||
<ims -> <=ims (Gerrit Pape)
|
||||
64-bit file I/O cleanliness
|
||||
fix HTTP ranges (Joachim Berdal Haga via Gerrit Pape)
|
||||
chdir to cgi's base dir (Kuba Winnicki)
|
||||
set HTTP_ACCEPT_ENCODING environment variable (Kuba Winnicki)
|
||||
We actually should export all HTTP headers as HTTP_[header]
|
||||
Any takers?
|
||||
Try not to send error message HTTP headers if we already sent the
|
||||
headers from the CGI (Kuba Winnicki)
|
||||
<ims -> <=ims (Gerrit Pape)
|
||||
64-bit file I/O cleanliness
|
||||
fix HTTP ranges (Joachim Berdal Haga via Gerrit Pape)
|
||||
|
||||
1.8:
|
||||
keep current environment in CGI (Laurent Bercot)
|
||||
make fnord-conf use the UID and not the user name (Fridtjof Busse)
|
||||
fix typo in buffer_putulonglong (Gerrit Pape)
|
||||
fix CGI POST off-by-two typo (Mark Hopf)
|
||||
fix gif->png conversion (Thomas Seck)
|
||||
remove == bashism from fnord-conf (Thomas Seck)
|
||||
add bittorrent mime type
|
||||
make authorization data available to CGIs for GET, too (Paul Jarc)
|
||||
fix conversion of host name to lower case (Gerrit Pape)
|
||||
add small test cgi: cgi-post.c
|
||||
fix CGI POST bug (Moe Wibble)
|
||||
fix CGI PATH_TRANSLATED bug (Nicolas George)
|
||||
add optional authentication support (Nicolas George, see README.auth)
|
||||
make sure error messages are text/html
|
||||
move /. -> /: conversion before demangling so it can actually be
|
||||
used as security measure for installations that don't use chroot
|
||||
keep current environment in CGI (Laurent Bercot)
|
||||
make fnord-conf use the UID and not the user name (Fridtjof Busse)
|
||||
fix typo in buffer_putulonglong (Gerrit Pape)
|
||||
fix CGI POST off-by-two typo (Mark Hopf)
|
||||
fix gif->png conversion (Thomas Seck)
|
||||
remove == bashism from fnord-conf (Thomas Seck)
|
||||
add bittorrent mime type
|
||||
make authorization data available to CGIs for GET, too (Paul Jarc)
|
||||
fix conversion of host name to lower case (Gerrit Pape)
|
||||
add small test cgi: cgi-post.c
|
||||
fix CGI POST bug (Moe Wibble)
|
||||
fix CGI PATH_TRANSLATED bug (Nicolas George)
|
||||
add optional authentication support (Nicolas George, see README.auth)
|
||||
make sure error messages are text/html
|
||||
move /. -> /: conversion before demangling so it can actually be
|
||||
used as security measure for installations that don't use chroot
|
||||
|
||||
1.7:
|
||||
add .mov and .qt for quicktime, .mpg for video/mpeg and .wav for audio/x-wav
|
||||
add mmap based file serving (should do zero-copy tcp just like sendfile)
|
||||
add Pragma: no-cache to CGI responses
|
||||
fix (apparently not exploitable) buffer overrun in do_cgi
|
||||
This bug was found by Ralf Wildenhues. To my knowledge it is
|
||||
impossible to exploit this bug on any platform known to me.
|
||||
fix (harmless) access to uninitialized data
|
||||
add .mov and .qt for quicktime, .mpg for video/mpeg and .wav for audio/x-wav
|
||||
add mmap based file serving (should do zero-copy tcp just like sendfile)
|
||||
add Pragma: no-cache to CGI responses
|
||||
fix (apparently not exploitable) buffer overrun in do_cgi
|
||||
This bug was found by Ralf Wildenhues. To my knowledge it is
|
||||
impossible to exploit this bug on any platform known to me.
|
||||
fix (harmless) access to uninitialized data
|
||||
|
||||
1.6:
|
||||
add support for $PATH_INFO in CGI environment.
|
||||
add .pac for netscape proxy autoconfig
|
||||
add .sig for application/pgp-signature
|
||||
add support for $PATH_INFO in CGI environment.
|
||||
add .pac for netscape proxy autoconfig
|
||||
add .sig for application/pgp-signature
|
||||
|
||||
1.5:
|
||||
fix write timeout handling (found by Lukas Beeler)
|
||||
fix fnord-conf to use the symbolic account name in run script
|
||||
(Sebastian D.B. Krause)
|
||||
fix write timeout handling (found by Lukas Beeler)
|
||||
fix fnord-conf to use the symbolic account name in run script
|
||||
(Sebastian D.B. Krause)
|
||||
|
||||
1.4:
|
||||
add dangling symlink based whole-host redirection (see README). This
|
||||
has the advantage that it can serve normal sites and redirect sites
|
||||
on the same IP.
|
||||
add support for non-TCP UCSPI environments (like ucspi-ssl). Please
|
||||
get the latest version of my ucspi-tcp IPv6 patch as I violated the
|
||||
UCSPI spec with all versions before 0.88-diff11.
|
||||
change logging from "127.0.0.1 200 23 Links_(0.96;_Unix) none /index.html"
|
||||
to "127.0.0.1 200 23 localhost Links_(0.96;_Unix) none /index.html"
|
||||
(i.e. include the Host: header). Suggested by Thomas Bader.
|
||||
add "immediate mode". If you give fnord a command line argument, it
|
||||
will change to that directory and if no "default" directory is
|
||||
given, it will assume there are no virtual hosts and serve from the
|
||||
current directory. I have a shell script called "http" that does
|
||||
tcpserver -RHl localhost 0 8000 /home/leitner/bin/fnord-idx .
|
||||
to share some directory on my hard drive with some poor Windows
|
||||
users without npoll (http://www.fefe.de/ncp/). fnord-idx is a new
|
||||
target (a fnord with DIR_LIST) that is auto-built by make.
|
||||
add dangling symlink based whole-host redirection (see README). This
|
||||
has the advantage that it can serve normal sites and redirect sites
|
||||
on the same IP.
|
||||
add support for non-TCP UCSPI environments (like ucspi-ssl). Please
|
||||
get the latest version of my ucspi-tcp IPv6 patch as I violated the
|
||||
UCSPI spec with all versions before 0.88-diff11.
|
||||
change logging from "127.0.0.1 200 23 Links_(0.96;_Unix) none /index.html"
|
||||
to "127.0.0.1 200 23 localhost Links_(0.96;_Unix) none /index.html"
|
||||
(i.e. include the Host: header). Suggested by Thomas Bader.
|
||||
add "immediate mode". If you give fnord a command line argument, it
|
||||
will change to that directory and if no "default" directory is
|
||||
given, it will assume there are no virtual hosts and serve from the
|
||||
current directory. I have a shell script called "http" that does
|
||||
tcpserver -RHl localhost 0 8000 /home/leitner/bin/fnord-idx .
|
||||
to share some directory on my hard drive with some poor Windows
|
||||
users without npoll (http://www.fefe.de/ncp/). fnord-idx is a new
|
||||
target (a fnord with DIR_LIST) that is auto-built by make.
|
||||
|
||||
1.3:
|
||||
make directory listings use non-proportional fonts (thanks, Antonio Dias)
|
||||
fnord will now optionally (default: enabled) normalize the incoming
|
||||
host name, i.e. "www.domain.com" -> "www.domain.com:80". That
|
||||
should cut down on the number of symbolic links. ;)
|
||||
remove timeout error message. fnord will not drop the connection
|
||||
without error message. Mozilla used to display the error message
|
||||
when the user caused another request on the connection with the
|
||||
timeout.
|
||||
Uwe Ohse found two more compilation problems.
|
||||
make directory listings use non-proportional fonts (thanks, Antonio Dias)
|
||||
fnord will now optionally (default: enabled) normalize the incoming
|
||||
host name, i.e. "www.domain.com" -> "www.domain.com:80". That
|
||||
should cut down on the number of symbolic links. ;)
|
||||
remove timeout error message. fnord will not drop the connection
|
||||
without error message. Mozilla used to display the error message
|
||||
when the user caused another request on the connection with the
|
||||
timeout.
|
||||
Uwe Ohse found two more compilation problems.
|
||||
|
||||
1.2:
|
||||
Olaf: I changed my initial CGI-interface to NOT use the filesystem but
|
||||
two pipes.
|
||||
Add whole-host redirect (see README)
|
||||
Olaf: added direcory-lists and "index.cgi" support (normal CGI only !
|
||||
"nph-index.cgi" is not supported). Fixed some problematic parts in the
|
||||
CGI-interface (\n -> \r\n converter for http-header and CGI crash
|
||||
handling)
|
||||
Fix gzip encoding bug that only happened with keep-alive
|
||||
Olaf: I changed my initial CGI-interface to NOT use the filesystem but
|
||||
two pipes.
|
||||
Add whole-host redirect (see README)
|
||||
Olaf: added directory-lists and "index.cgi" support (normal CGI only !
|
||||
"nph-index.cgi" is not supported). Fixed some problematic parts in the
|
||||
CGI-interface (\n -> \r\n converter for http-header and CGI crash
|
||||
handling)
|
||||
Fix gzip encoding bug that only happened with keep-alive
|
||||
|
||||
1.1:
|
||||
ship with the parts from libowfat that we actually use
|
||||
minor speed-up. sendfile is a drag for very small files, so those are
|
||||
now sent through the same buffer the header is sent through. That
|
||||
sends the whole answer in one TCP packet if you are lucky, even
|
||||
without the TCP_CORK magic from Linux. Major speed-up for
|
||||
benchmarks ;)
|
||||
ship with the parts from libowfat that we actually use
|
||||
minor speed-up. sendfile is a drag for very small files, so those are
|
||||
now sent through the same buffer the header is sent through. That
|
||||
sends the whole answer in one TCP packet if you are lucky, even
|
||||
without the TCP_CORK magic from Linux. Major speed-up for
|
||||
benchmarks ;)
|
||||
|
||||
1.0:
|
||||
initial release
|
||||
initial release
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
FROM alpine
|
||||
|
||||
RUN apk --no-cache add s6-networking
|
||||
|
||||
RUN apk --no-cache add build-base
|
||||
COPY . /usr/local/src/eris
|
||||
RUN make -C /usr/local/src/eris
|
||||
RUN cp /usr/local/src/eris/eris /usr/bin
|
||||
RUN rm -rf /usr/local/src/eris
|
||||
RUN apk --no-cache del build-base
|
||||
|
||||
RUN addgroup -S -g 800 www
|
||||
RUN adduser -S -u 800 -G www www
|
||||
|
||||
RUN mkdir /www
|
||||
WORKDIR /www
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["s6-tcpserver", "-u", "80", "-g", "80", "0.0.0.0", "80", "/usr/bin/eris", "-."]
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
SSL with eris
|
||||
=============
|
||||
|
||||
Eris does not care what transport is in use: that job is left to the invoking
|
||||
program (e.g. tcpserver).
|
||||
|
||||
In the past you could use `sslio` with `tcpsvd`,
|
||||
but `sslio` has not been updated in a long time,
|
||||
and won't work with (at least) Chrome 39.
|
||||
|
||||
I recommend using stunnel,
|
||||
which also works with IPv6.
|
||||
You can invoke it like so:
|
||||
|
||||
#! /bin/sh
|
||||
cd /srv/www
|
||||
HTTPS=enabled; export HTTPS
|
||||
|
||||
exec stunnel -fd 3 3<<EOD
|
||||
foreground = yes
|
||||
setuid = http
|
||||
setgid = http
|
||||
debug = 4
|
||||
|
||||
[https]
|
||||
accept = ::443
|
||||
cert = /path/to/yourserver.crt
|
||||
key = /path/to/yourserver.key
|
||||
exec = /path/to/eris
|
||||
execargs = eris -c
|
||||
EOD
|
||||
|
||||
I set the `HTTPS` environment variable,
|
||||
so CGI can tell whether or not its connection is secure.
|
13
Makefile
13
Makefile
|
@ -1,14 +1,15 @@
|
|||
VERSION := $(shell head -n 1 CHANGES | tr -d :)
|
||||
|
||||
CFLAGS = -DFNORD='"eris/$(VERSION)"' -Wall -Werror
|
||||
CFLAGS = -Wall -Werror
|
||||
|
||||
all: eris
|
||||
|
||||
eris: eris.c strings.c mime.c time.c cgi.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
eris: eris.o strings.o mime.o timerfc.o
|
||||
|
||||
eris.o: version.h
|
||||
version.h: CHANGES
|
||||
awk -F : 'NR==1 {printf("const char *FNORD = \"eris/%s\";\n", $$1);}' $< > $@
|
||||
|
||||
test: eris
|
||||
sh ./test.sh
|
||||
|
||||
clean:
|
||||
rm -f *.[oa] eris
|
||||
rm -f *.[oa] version.h eris
|
||||
|
|
81
README
81
README
|
@ -1,81 +0,0 @@
|
|||
Eris HTTPD is a part of Dirtbags Capture The Flag
|
||||
(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
|
||||
a new project. Fnord's author approved of the fork.
|
||||
|
||||
Significant differences between eris and fnord are:
|
||||
|
||||
* command-line arguments instead of compile-time defines
|
||||
* eliminated use of libowfat
|
||||
* no build dependency of dietlibc
|
||||
* elimination of "old style symlink handling"
|
||||
* elimination of user switching (you can use tcpserver -[ug])
|
||||
* elimination of chroot code (you can use chroot)
|
||||
* several bugfixes (sent to the fnord mail list)
|
||||
* ignores Accept header (fnord does too)
|
||||
|
||||
----
|
||||
|
||||
Usage:
|
||||
|
||||
tcpserver -v -RHl localhost -u 1234 -g 1234 0 80 ./httpd
|
||||
|
||||
Will log to stderr in the form
|
||||
|
||||
127.0.0.1 200 23 localhost Links_(0.96;_Unix) none /index.html
|
||||
|
||||
where 127.0.0.1 is the client IP, 200 is the HTTP exit code, 23 is the
|
||||
size of the content that was served (or 0 for unsuccessful exit codes),
|
||||
localhost is the Host: header (the virtual host), the next token is the
|
||||
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
|
||||
each line is the decoded requested URL.
|
||||
|
||||
eris does simple virtual hosting. If the Host: HTTP header is there,
|
||||
eris will try to chdir to a directory of that name, i.e. if the client
|
||||
asks for "/" on host "www.fefe.de", eris will look for
|
||||
"www.fefe.de/index.html". Eris will also try the directory "default"
|
||||
if no specific directory for the virtual host was there. If the
|
||||
directory is a dangling symlink, eris will redirect the whole site.
|
||||
Examples:
|
||||
|
||||
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 -> =http://www.baz.de/
|
||||
|
||||
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/.
|
||||
|
||||
eris implements el-cheapo HTTP ranges (only byte ranges and only of the
|
||||
form x-y, not multiple ranges).
|
||||
|
||||
eris implements content type matching and Accepts: parsing, but the
|
||||
content type table is compiled in, i.e. to change it, you have to change
|
||||
the source code. Shouldn't be a problem because you _have_ the source
|
||||
code ;)
|
||||
|
||||
eris implements HTTP redirection. If a file is not found, but a
|
||||
dangling symlink is there under the same name, eris will issue a
|
||||
redirection to the contents of that symlink. To be RFC compliant, the
|
||||
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
|
||||
|
||||
eris will change dots at the start of file or directory names to colons
|
||||
in the query before trying to answer them.
|
||||
|
||||
eris understands and implements keep-alive connections.
|
||||
|
||||
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
|
||||
whose names end with ".cgi" as CGI programs and try to execute them.
|
||||
CGI programs starting with "nph-" will be handled as no-parse-header
|
||||
CGIs. Please see http://hoohoo.ncsa.uiuc.edu/cgi/interface.html for the
|
||||
CGI specification.
|
|
@ -0,0 +1,105 @@
|
|||
About
|
||||
=====
|
||||
|
||||
Eris is an HTTP/1.1 web server with CGI.
|
||||
It is very fast,
|
||||
uses very little memory,
|
||||
and has a tiny codebase which has been audited at least twice by gray-hat hackers.
|
||||
It relies on an external program,
|
||||
such as tcpserver or netcat,
|
||||
to handle networking,
|
||||
and expects to be run once for every connection.
|
||||
This may sound horrible,
|
||||
but it's actually pretty quick,
|
||||
especially since this architecture makes it trivial to use the
|
||||
`sendfile` call in Linux
|
||||
(added in 2003 as a reaction to Apache losing to IIS in benchmarks),
|
||||
which sends an open file directly to a socket,
|
||||
without having to context switch into userspace.
|
||||
|
||||
It conforms to the parts of HTTP/1.1 that appear to be important to clients.
|
||||
I have not found any HTTP/1.1 clients which have trouble with Eris,
|
||||
including curl, which breaks with fnord (the reason I began work on Eris).
|
||||
|
||||
Eris HTTPD is a part of [Dirtbags Capture The Flag](http://dirtbags.net/ctf/).
|
||||
After many patches against [fnord 1.10](http://www.fefe.de/),
|
||||
I decided to fork fnord into a new project.
|
||||
Fnord's author approved of the fork.
|
||||
|
||||
|
||||
Differences with fnord
|
||||
======================
|
||||
|
||||
Significant differences between eris and fnord are:
|
||||
|
||||
* command-line arguments instead of compile-time defines
|
||||
* eliminated use of libowfat
|
||||
* no build dependency of dietlibc
|
||||
* elimination of "old style symlink handling"
|
||||
* elimination of user switching (you can use tcpserver -[ug])
|
||||
* elimination of chroot code (you can use chroot)
|
||||
* several bugfixes (sent to the fnord mail list)
|
||||
* ignores Accept header (fnord also ignores it, but claims not to)
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Start with:
|
||||
|
||||
tcpserver -v -RHl localhost -u 1234 -g 1234 0 80 ./eris
|
||||
|
||||
There are many other ways to start eris.
|
||||
For example, you can run an HTTPS server with stunnel.
|
||||
|
||||
You just need something that launches eris with stdin and stdout connected to the client.
|
||||
|
||||
|
||||
Logging
|
||||
-------
|
||||
|
||||
Will log to stderr in the form
|
||||
|
||||
127.0.0.1 200 23 localhost Links_(0.96;_Unix) none /index.html
|
||||
|
||||
where 127.0.0.1 is the client IP, 200 is the HTTP exit code,
|
||||
23 is the size of the content that was served (or 0 for unsuccessful exit codes),
|
||||
localhost is the Host: header (the virtual host),
|
||||
the next token is the 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 each line is the decoded requested URL.
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
eris does simple virtual hosting. If the `Host:` HTTP header is there,
|
||||
eris will try to chdir to a directory of that name, i.e. if the client
|
||||
asks for "/" on host "www.fefe.de", eris will look for
|
||||
"www.fefe.de/index.html". Eris will also try the directory "default"
|
||||
if no specific directory for the virtual host was there.
|
||||
|
||||
eris implements el-cheapo HTTP ranges (only byte ranges and only of the
|
||||
form x-y, not multiple ranges).
|
||||
|
||||
eris will change dots at the start of file or directory names to colons
|
||||
in the query before trying to answer them.
|
||||
|
||||
eris understands and implements keep-alive connections.
|
||||
|
||||
eris will use sendfile on Linux to enable zero-copy TCP.
|
||||
|
||||
If eris is given the -c option, it will regard files
|
||||
whose names end with ".cgi" as CGI programs and try to execute them.
|
||||
Please see <http://hoohoo.ncsa.uiuc.edu/cgi/interface.html> for the CGI specification.
|
||||
|
||||
|
||||
About The Name
|
||||
==============
|
||||
|
||||
[Eris](http://en.wikipedia.org/wiki/Eris_%28dwarf_planet%29)
|
||||
is the most massive (heaviest) dwarf planet in the solar system.
|
||||
It's heavier than Pluto!
|
||||
|
||||
Its discovery is what spurred astronomers to finally define the word "planet",
|
||||
which resulted in Pluto being classified a dwarf planet.
|
||||
Otherwise, we would have to count Eris as a tenth planet.
|
|
@ -1,13 +1,9 @@
|
|||
#! /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.
|
||||
## Breaking fnord 1.11
|
||||
|
||||
if [ "$1" = "clean" ]; then
|
||||
rm -rf fnord-1.10
|
||||
rm -rf fnord-1.11
|
||||
fi
|
||||
|
||||
# Set HTTPD= to test something else
|
||||
|
@ -16,12 +12,9 @@ case ${HTTPD:=./fnord} in
|
|||
: ${HTTPD_IDX:=$HTTPD-idx}
|
||||
: ${HTTPD_CGI:=$HTTPD-cgi}
|
||||
;;
|
||||
*eris)
|
||||
: ${HTTPD_IDX:=$HTTPD -d}
|
||||
: ${HTTPD_CGI:=$HTTPD -c}
|
||||
;;
|
||||
esac
|
||||
|
||||
tests=0
|
||||
title() {
|
||||
printf "%-50s: " "$1"
|
||||
tests=$(expr $tests + 1)
|
||||
|
@ -44,16 +37,18 @@ d () {
|
|||
}
|
||||
|
||||
|
||||
if [ ! -f fnord-1.10.tar.bz2 ]; then
|
||||
wget http://www.fefe.de/fnord/fnord-1.10.tar.bz2
|
||||
if [ ! -f fnord-1.11.tar.bz2 ]; then
|
||||
wget http://www.fefe.de/fnord/fnord-1.11.tar.bz2
|
||||
fi
|
||||
|
||||
if [ ! -f fnord-1.10/httpd.c ]; then
|
||||
rm -rf fnord-1.10
|
||||
bzcat fnord-1.10.tar.bz2 | tar xf -
|
||||
if [ ! -f fnord-1.11/httpd.c ]; then
|
||||
rm -rf fnord-1.11
|
||||
bzcat fnord-1.11.tar.bz2 | tar xf -
|
||||
fi
|
||||
|
||||
cd fnord-1.10
|
||||
cd fnord-1.11
|
||||
|
||||
# Comment this out if you want to build with diet libc
|
||||
make DIET=
|
||||
|
||||
if [ ! -d default ]; then
|
||||
|
|
186
cgi.c
186
cgi.c
|
@ -1,186 +0,0 @@
|
|||
void
|
||||
sigchld(int sig)
|
||||
{
|
||||
while (waitpid(0, NULL, WNOHANG) > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
cgi_child(const char *relpath)
|
||||
{
|
||||
env("GATEWAY_INTERFACE", "CGI/1.1");
|
||||
env("SERVER_SOFTWARE", FNORD);
|
||||
env("REQUEST_URI", path);
|
||||
env("SERVER_NAME", host);
|
||||
env("SCRIPT_NAME", relpath);
|
||||
env("REMOTE_ADDR", remote_ip);
|
||||
env("REMOTE_PORT", remote_port);
|
||||
env("REMOTE_IDENT", remote_ident);
|
||||
if (content_length) {
|
||||
char cl[20];
|
||||
|
||||
snprintf(cl, sizeof cl, "%llu", (unsigned long long) content_length);
|
||||
env("CONTENT_LENGTH", cl);
|
||||
env("CONTENT_TYPE", content_type);
|
||||
}
|
||||
|
||||
execl(relpath, relpath, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
cgi_parent(int cin, int cout, int passthru)
|
||||
{
|
||||
char cgiheader[BUFFER_SIZE];
|
||||
size_t cgiheaderlen = 0;
|
||||
FILE *cinf = fdopen(cin, "rb");
|
||||
size_t size = 0;
|
||||
int header_sent = 0;
|
||||
|
||||
fcntl(cin, F_SETFL, O_NONBLOCK);
|
||||
signal(SIGCHLD, sigchld);
|
||||
signal(SIGPIPE, SIG_IGN); /* NO! no signal! */
|
||||
|
||||
while (1) {
|
||||
int nfds;
|
||||
fd_set rfds, wfds;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(cin, &rfds);
|
||||
nfds = cin;
|
||||
|
||||
if (content_length) {
|
||||
/* have post data */
|
||||
FD_SET(cout, &wfds);
|
||||
if (cout > nfds) {
|
||||
nfds = cout;
|
||||
}
|
||||
} else if (cout >= 0) {
|
||||
close(cout); /* no post data */
|
||||
cout = -1;
|
||||
}
|
||||
|
||||
if (-1 == select(nfds+1, &rfds, &wfds, NULL, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (FD_ISSET(cin, &rfds)) {
|
||||
if (passthru) {
|
||||
/* Pass everything through verbatim */
|
||||
size_t len;
|
||||
|
||||
/* Re-use this big buffer */
|
||||
len = fread(cgiheader, 1, sizeof cgiheader, cinf);
|
||||
if (0 == len) {
|
||||
/* CGI is done */
|
||||
break;
|
||||
}
|
||||
fwrite(cgiheader, 1, len, stdout);
|
||||
size += len;
|
||||
} else {
|
||||
/* Interpret header fields */
|
||||
size_t readlen = (sizeof cgiheader) - cgiheaderlen;
|
||||
|
||||
if (NULL == fgets(cgiheader + cgiheaderlen, readlen, cinf)) {
|
||||
/* EOF or error */
|
||||
badrequest(500, "CGI Error", "CGI output too weird");
|
||||
}
|
||||
cgiheaderlen = strlen(cgiheader);
|
||||
|
||||
if ('\n' == cgiheader[cgiheaderlen - 1]) {
|
||||
/* We read a whole line */
|
||||
size_t len;
|
||||
char *val;
|
||||
|
||||
len = extract_header_field(cgiheader, &val, 0);
|
||||
if (! len) {
|
||||
/* We've read the entire header block */
|
||||
passthru = 1;
|
||||
eoh();
|
||||
} else {
|
||||
if (! header_sent) {
|
||||
if (! strcasecmp(cgiheader, "Location")) {
|
||||
header(302, "CGI Redirect");
|
||||
fwrite(cgiheader, 1, cgiheaderlen, stdout);
|
||||
dolog(302, 0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
header(200, "OK");
|
||||
printf("Pragma: no-cache\r\n");
|
||||
|
||||
header_sent = 1;
|
||||
}
|
||||
printf("%s: %s\r\n", cgiheader, val);
|
||||
cgiheaderlen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (FD_ISSET(cout, &wfds)) {
|
||||
/*
|
||||
* write to cgi the post data
|
||||
*/
|
||||
if (content_length) {
|
||||
size_t len;
|
||||
char buf[BUFFER_SIZE];
|
||||
size_t nmemb = min(BUFFER_SIZE, content_length);
|
||||
|
||||
len = fread(buf, 1, nmemb, stdin);
|
||||
if (len < 1) {
|
||||
break;
|
||||
}
|
||||
content_length -= len;
|
||||
write(cout, buf, len);
|
||||
} else {
|
||||
close(cout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
dolog(200, size);
|
||||
cork(0);
|
||||
}
|
||||
|
||||
void
|
||||
serve_cgi(char *relpath)
|
||||
{
|
||||
int pid;
|
||||
int cin[2];
|
||||
int cout[2];
|
||||
|
||||
if (pipe(cin) || pipe(cout)) {
|
||||
badrequest(500, "Internal Server Error", "Server Resource problem.");
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (-1 == pid) {
|
||||
badrequest(500, "Internal Server Error", "Unable to fork.");
|
||||
}
|
||||
if (pid) {
|
||||
close(cin[1]);
|
||||
close(cout[0]);
|
||||
|
||||
/* Eris is not this smart yet */
|
||||
keepalive = 0;
|
||||
|
||||
alarm(CGI_TIMEOUT);
|
||||
cgi_parent(cin[0], cout[1], 0);
|
||||
|
||||
exit(0);
|
||||
} else {
|
||||
close(cwd);
|
||||
close(cout[1]);
|
||||
close(cin[0]);
|
||||
|
||||
dup2(cout[0], 0);
|
||||
dup2(cin[1], 1);
|
||||
|
||||
close(cout[0]);
|
||||
close(cin[1]);
|
||||
|
||||
cgi_child(relpath);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
This directory contains little wrappers to help make your life
|
||||
running a full Internet-facing web server (such as woozle.org)
|
||||
a little easier.
|
||||
|
||||
Quite a lot of web software these days is written to work with
|
||||
Apache and nothing else. PHP is a notable example: even PHP-CGI,
|
||||
as shipped on Debian, requires special environment variables that
|
||||
only Apache sets, and doesn't work with, e.g. mathopd, boa, busybox
|
||||
httpd, or eris.
|
|
@ -0,0 +1,31 @@
|
|||
/** g.cgi - CGI interface to cgit and git-http-backend
|
||||
*
|
||||
* This is a simple CGI to invoke cgit with a configuration
|
||||
* file of your choice. It will also invoke git-http-backend
|
||||
* if appropriate, which in my (very light) testing runs about
|
||||
* twice as fast as plain HTTP with git-update-server-info.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Set these to appropriate paths */
|
||||
#define CGIT_CONFIG "/home/neale/public_html/cgitrc"
|
||||
#define GIT_PROJECT_ROOT "/home/neale/projects"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *uri = getenv("REQUEST_URI");
|
||||
|
||||
if (uri && strstr(uri, "git-upload-pack")) {
|
||||
/* Use git-http-backend for great speed! */
|
||||
setenv("GIT_PROJECT_ROOT", GIT_PROJECT_ROOT, 1);
|
||||
execlp("git", "git", "http-backend", NULL);
|
||||
} else {
|
||||
setenv("CGIT_CONFIG", CGIT_CONFIG, 1);
|
||||
execlp("cgit", "cgit", NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#! /bin/sh
|
||||
|
||||
PORT=8888
|
||||
|
||||
if [ $# = 0 ]; then
|
||||
ARGS=-d
|
||||
fi
|
||||
|
||||
addr=$(ifconfig | awk -F '[: ]+' '/inet addr/ {print $4;}' \
|
||||
| grep -Fv 127.0.0.1 | head -n 1)
|
||||
|
||||
echo Listening on http://$addr:$PORT/
|
||||
|
||||
tcpsvd 0 $PORT eris -. $ARGS "$@"
|
7
mime.c
7
mime.c
|
@ -1,3 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "mime.h"
|
||||
|
||||
static struct mimeentry {
|
||||
const char *name,
|
||||
*type;
|
||||
|
@ -15,6 +19,7 @@ static struct mimeentry {
|
|||
"jpeg", "image/jpeg"}, {
|
||||
"jpg", "image/jpeg"}, {
|
||||
"svg", "image/svg+xml"}, {
|
||||
"webm", "video/webm"}, {
|
||||
"mpeg", "video/mpeg"}, {
|
||||
"mpg", "video/mpeg"}, {
|
||||
"avi", "video/x-msvideo"}, {
|
||||
|
@ -44,7 +49,7 @@ static const char *default_mimetype = "application/octet-stream";
|
|||
/*
|
||||
* Determine MIME type from file extension
|
||||
*/
|
||||
static const char *
|
||||
const char *
|
||||
getmimetype(char *url)
|
||||
{
|
||||
char *ext = strrchr(url, '.');
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __MIME_H__
|
||||
#define __MIME_H__
|
||||
|
||||
const char *getmimetype(char *url);
|
||||
|
||||
#endif
|
21
strings.c
21
strings.c
|
@ -1,3 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include "strings.h"
|
||||
|
||||
int
|
||||
endswith(char *haystack, char *needle)
|
||||
{
|
||||
|
@ -20,7 +24,7 @@ endswith(char *haystack, char *needle)
|
|||
}
|
||||
|
||||
/** Replace whitespace with underscores for logging */
|
||||
static void
|
||||
void
|
||||
sanitize(char *s)
|
||||
{
|
||||
if (!s) {
|
||||
|
@ -71,7 +75,7 @@ extract_header_field(char *buf, char **val, int cgi)
|
|||
}
|
||||
}
|
||||
|
||||
for (; (buf[len-1] == '\n') || (buf[len-1] == '\r'); len -= 1);
|
||||
for (; (len > 0) && ((buf[len-1] == '\n') || (buf[len-1] == '\r')); len -= 1);
|
||||
buf[len] = 0;
|
||||
|
||||
return len;
|
||||
|
@ -116,15 +120,10 @@ void
|
|||
url_esc(FILE *f, char *s)
|
||||
{
|
||||
for (; *s; s += 1) {
|
||||
switch (*s) {
|
||||
case '%':
|
||||
case 127:
|
||||
case -127 ... 31:
|
||||
fprintf(f, "%%%02x", *s);
|
||||
break;
|
||||
default:
|
||||
fputc(*s, f);
|
||||
break;
|
||||
if ((*s == '%') || (*s == 127) || (*s < 31)) {
|
||||
fprintf(f, "%%%02x", *s);
|
||||
} else {
|
||||
fputc(*s, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef __STRINGS_H__
|
||||
#define __STRINGS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int endswith(char *haystack, char *needle);
|
||||
void sanitize(char *s);
|
||||
size_t extract_header_field(char *buf, char **val, int cgi);
|
||||
int fromhex(int c);
|
||||
void html_esc(FILE *f, char *s);
|
||||
void url_esc(FILE *f, char *s);
|
||||
|
||||
#endif
|
110
test.sh
110
test.sh
|
@ -4,6 +4,10 @@
|
|||
: ${HTTPD_CGI:=./eris -c}
|
||||
: ${HTTPD_IDX:=./eris -d}
|
||||
|
||||
tests=0
|
||||
successes=0
|
||||
failures=0
|
||||
|
||||
H () {
|
||||
section="$*"
|
||||
printf "\n%-20s " "$*"
|
||||
|
@ -43,6 +47,7 @@ cat <<'EOD' > default/a.cgi
|
|||
echo 'Content-type: text/plain'
|
||||
echo
|
||||
set | sort
|
||||
ls *.cgi
|
||||
EOD
|
||||
chmod +x default/a.cgi
|
||||
|
||||
|
@ -55,6 +60,32 @@ echo 'james'
|
|||
EOD
|
||||
chmod +x default/mongo.cgi
|
||||
|
||||
cat <<'EOD' > default/redir.cgi
|
||||
#! /bin/sh
|
||||
echo "Location: http://example.com/froot"
|
||||
EOD
|
||||
chmod +x default/redir.cgi
|
||||
|
||||
cat <<'EOD' > default/status.cgi
|
||||
#! /bin/sh
|
||||
case "$PATH_INFO" in
|
||||
/empty)
|
||||
echo "Status"
|
||||
exit 0
|
||||
;;
|
||||
/nostat)
|
||||
echo "Status: "
|
||||
;;
|
||||
*)
|
||||
echo "Status: 300 wat"
|
||||
;;
|
||||
esac
|
||||
echo "Merf: merf"
|
||||
echo
|
||||
echo "james"
|
||||
EOD
|
||||
chmod +x default/status.cgi
|
||||
|
||||
mkdir -p default/empty
|
||||
mkdir -p default/subdir
|
||||
touch default/subdir/a
|
||||
|
@ -73,10 +104,10 @@ echo "IDX: $HTTPD_IDX "
|
|||
H "Basic tests"
|
||||
|
||||
title "GET /index.html"
|
||||
printf 'GET /index.html HTTP/1.0\r\n\r\n' | $HTTPD 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: [a-z]*/[0-9.]*#%Connection: close#%Content-Type: text/html; charset=UTF-8#%Content-Length: 6#%Last-Modified: ..., .. ... 20.. ..:..:.. GMT#%#%james%' && pass || fail
|
||||
printf 'GET /index.html HTTP/1.0\r\n\r\n' | $HTTPD 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: eris/[0-9.a-z]*#%Connection: close#%Content-Type: text/html; charset=UTF-8#%Content-Length: 6#%Last-Modified: ..., .. ... 20.. ..:..:.. GMT#%#%james%' && pass || fail
|
||||
|
||||
title "GET /"
|
||||
printf 'GET / HTTP/1.0\r\n\r\n' | $HTTPD 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: [a-z]*/[0-9.]*#%Connection: close#%Content-Type: text/html; charset=UTF-8#%Content-Length: 6#%Last-Modified: ..., .. ... 20.. ..:..:.. GMT#%#%james%' && pass || fail
|
||||
printf 'GET / HTTP/1.0\r\n\r\n' | $HTTPD 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: eris/[0-9.a-z]*#%Connection: close#%Content-Type: text/html; charset=UTF-8#%Content-Length: 6#%Last-Modified: ..., .. ... 20.. ..:..:.. GMT#%#%james%' && pass || fail
|
||||
|
||||
title "Keepalive"
|
||||
printf 'GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\n\r\n' | $HTTPD 2>/dev/null | grep -c 'james' | grep -q 2 && pass || fail
|
||||
|
@ -96,13 +127,31 @@ printf 'GET / HTTP/1.0\n\n' | $HTTPD 2>/dev/null | grep -q 'james' && pass || fa
|
|||
title "No trailing slash"
|
||||
printf 'GET /empty HTTP/1.0\r\n\r\n' | $HTTPD 2>/dev/null | d | grep -q '301 Redirect#%.*Location: /empty/#%#%' && pass || fail
|
||||
|
||||
title "No version after query_string"
|
||||
printf 'GET /?\r\n\r\n' | $HTTPD 2>/dev/null | d | grep -q 'HTTP/0.9' && pass || fail
|
||||
|
||||
title "Logging /"
|
||||
(printf 'GET / HTTP/1.1\r\nHost: host\r\n\r\n' |
|
||||
PROTO=TCP TCPREMOTEPORT=1234 TCPREMOTEIP=10.0.0.2 $HTTPD >/dev/null) 2>&1 | grep -q '^10.0.0.2 200 6 host (null) (null) /$' && pass || fail
|
||||
PROTO=TCP TCPREMOTEPORT=1234 TCPREMOTEIP=10.0.0.2 $HTTPD >/dev/null) 2>&1 | grep -q '^10.0.0.2:1234 200 6 host (null) (null) /$' && pass || fail
|
||||
|
||||
title "Logging /index.html"
|
||||
(printf 'GET /index.html HTTP/1.1\r\nHost: host\r\n\r\n' |
|
||||
PROTO=TCP TCPREMOTEPORT=1234 TCPREMOTEIP=10.0.0.2 $HTTPD >/dev/null) 2>&1 | grep -q '^10.0.0.2 200 6 host (null) (null) /index.html$' && pass || fail
|
||||
PROTO=TCP TCPREMOTEPORT=1234 TCPREMOTEIP=10.0.0.2 $HTTPD >/dev/null) 2>&1 | grep -q '^10.0.0.2:1234 200 6 host (null) (null) /index.html$' && pass || fail
|
||||
|
||||
title "Logging busybox"
|
||||
(printf 'GET /index.html HTTP/1.1\r\nHost: host\r\n\r\n' |
|
||||
PROTO=TCP TCPREMOTEADDR=[::1]:8765 $HTTPD >/dev/null) 2>&1 | grep -Fxq '[::1]:8765 200 6 host (null) (null) /index.html' && pass || fail
|
||||
|
||||
title "Logging stunnel"
|
||||
(printf 'GET /index.html HTTP/1.1\r\nHost: host\r\n\r\n' |
|
||||
REMOTE_HOST=::1 REMOTE_PORT=8765 $HTTPD >/dev/null) 2>&1 | grep -Fxq '::1:8765 200 6 host (null) (null) /index.html' && pass || fail
|
||||
|
||||
|
||||
|
||||
H "Options"
|
||||
|
||||
title "-."
|
||||
printf 'GET /eris HTTP/1.0\r\n\r\n' | $HTTPD -. 2>/dev/null | grep -q 'HTTP/1.. 200 OK' && pass || fail
|
||||
|
||||
|
||||
|
||||
|
@ -122,7 +171,12 @@ title "Too many headers"
|
|||
printf 'Header: val\r\n'
|
||||
done
|
||||
printf '\r\n') | $HTTPD 2>/dev/null | grep -q 'HTTP/1.. 431 ' && pass || fail
|
||||
|
||||
|
||||
title "Directory traversal"
|
||||
printf 'GET /../default/index.html HTTP/1.0\r\n\r\n' | $HTTPD 2>/dev/null | grep -q 'HTTP/1.. 404' && pass || fail
|
||||
|
||||
title "Escaped directory traversal"
|
||||
printf 'GET /%%2e%%2e/default/index.html HTTP/1.0\r\n\r\n' | $HTTPD 2>/dev/null | grep -q 'HTTP/1.. 404' && pass || fail
|
||||
|
||||
|
||||
H "If-Modified-Since"
|
||||
|
@ -146,16 +200,24 @@ printf 'GET / HTTP/1.0\r\nIf-Modified-Since: Thursday, 27-Feb-30 12:12:12 GMT\r\
|
|||
title "ANSI C Date"
|
||||
printf 'GET / HTTP/1.0\r\nIf-Modified-Since: Sun Feb 27 12:12:12 2030\r\n\r\n' | $HTTPD 2>/dev/null | grep -q 'HTTP/1.. 304 ' && pass || fail
|
||||
|
||||
title "ims persist"
|
||||
printf 'GET / HTTP/1.1\r\nIf-Modified-Since: %s\r\n\r\nGET / HTTP/1.0\r\n\r\n' "$ims" | $HTTPD 2>/dev/null | d | grep -q 'HTTP/1.. 304.*HTTP/1.. 200' && pass || fail
|
||||
|
||||
title "Logging"
|
||||
(printf 'GET / HTTP/1.0\r\nIf-Modified-Since: %s\r\n\r\n' "$ims" | $HTTPD > /dev/null) 2>&1 | grep -q '304' && pass || fail
|
||||
|
||||
|
||||
|
||||
H "Directory indexing"
|
||||
|
||||
title "Basic index"
|
||||
printf 'GET /empty/ HTTP/1.0\r\n\r\n' | $HTTPD_IDX 2>/dev/null | d | grep -Fq '<h1>Directory Listing: /empty/</h1><pre><a href="../">Parent Directory</a>%</pre>' && pass || fail
|
||||
|
||||
printf 'GET /empty/ HTTP/1.0\r\n\r\n' | $HTTPD_IDX 2>/dev/null | d | grep -Fq '<h1>Directory Listing: /empty/</h1><pre>%<a href="../">Parent Directory</a>%</pre>' && pass || fail
|
||||
title "Hidden file"
|
||||
printf 'GET /subdir/ HTTP/1.0\r\n\r\n' | $HTTPD_IDX 2>/dev/null | grep -q 'hidden' && fail || pass
|
||||
|
||||
title "Logging"
|
||||
(printf 'GET /empty/ HTTP/1.0\r\n\r\n' |
|
||||
PROTO=TCP TCPREMOTEPORT=1234 TCPREMOTEIP=10.0.0.2 $HTTPD_IDX >/dev/null) 2>&1 | grep -q '^10.0.0.2:1234 200 0 (null) (null) (null) /empty/$' && pass || fail
|
||||
|
||||
|
||||
H "CGI"
|
||||
|
@ -164,6 +226,10 @@ title "Basic CGI"
|
|||
printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | \
|
||||
$HTTPD_CGI 2>/dev/null | d | grep -Eq 'HTTP/1.0 200 OK#%Server: .*#%Connection: close#%Pragma: no-cache#%Content-type: text/plain#%#%.*%GATEWAY_INTERFACE=.?CGI/1.1.?%' && pass || fail
|
||||
|
||||
title "CGI chdir"
|
||||
printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | \
|
||||
$HTTPD_CGI 2>/dev/null | d | grep -Eq '%a.cgi%' && pass || fail
|
||||
|
||||
title "REQUEST_METHOD"
|
||||
printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | \
|
||||
$HTTPD_CGI 2>/dev/null | grep -Eq 'REQUEST_METHOD=.?GET.?$' && pass || fail
|
||||
|
@ -189,6 +255,31 @@ printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -Eq '%S
|
|||
title "Large response"
|
||||
printf 'GET /mongo.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | grep -q james && pass || fail
|
||||
|
||||
title "Redirect"
|
||||
printf 'GET /redir.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | grep -Fq 'Location: http://example.com/froot' && pass || fail
|
||||
|
||||
title "Status"
|
||||
printf 'GET /status.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>&1 | d | grep -q '^HTTP/1.0 300 wat#%.*.null. 300 6' && pass || fail
|
||||
|
||||
title "Status bug"
|
||||
printf 'GET /status.cgi/empty HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -q '^HTTP/1.0 500 ' && pass || fail
|
||||
|
||||
title "No status"
|
||||
printf 'GET /status.cgi/nostat HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -q '^HTTP/1.0 500 ' && pass || fail
|
||||
|
||||
|
||||
H "Timeouts"
|
||||
|
||||
title "Read timeout"
|
||||
(sleep 2.1; printf 'GET / HTTP/1.0\r\n\r\n') | $HTTPD 2>/dev/null | grep -q '.' && fail || pass
|
||||
|
||||
|
||||
H "CONNECT handler"
|
||||
|
||||
title "Basic test"
|
||||
printf 'CONNECT /etc HTTP/1.1\r\n\r\n' | $HTTPD -o /bin/ls | grep -q passwd && pass || fail
|
||||
|
||||
|
||||
H "fnord bugs"
|
||||
|
||||
# 1. Should return directory listing of /; instead segfaults
|
||||
|
@ -199,6 +290,11 @@ printf 'GET / HTTP/1.0\r\nHost: empty\r\n\r\n' | $HTTPD_IDX 2>/dev/null | grep -
|
|||
title "CGI output bare newlines"
|
||||
printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -q '#%#%' && pass || fail
|
||||
|
||||
## Note: fnord gets a pass on this since it only claims to be an HTTP/1.0
|
||||
## server. Eris is not 1.1 compliant either, but it at least tries to fake it. You
|
||||
## should consider how much of HTTP/1.1 you want before deploying either. In practice,
|
||||
## with browsers, both seems sufficient. Some tools, notably httperf, fail
|
||||
## with fnord.
|
||||
# 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
|
||||
|
|
|
@ -35,10 +35,12 @@
|
|||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
static const char days[] = "SunMonTueWedThuFriSat";
|
||||
static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "timerfc.h"
|
||||
|
||||
static time_t
|
||||
time_t
|
||||
timerfc(const char *s)
|
||||
{
|
||||
static const int daytab[2][12] = {
|
Loading…
Reference in New Issue