mirror of https://github.com/nealey/eris.git
Rename to eris, maybe fix CGI \r\n\r\n bug
This commit is contained in:
parent
ab3a9fb31b
commit
300840c311
16
CHANGES
16
CHANGES
|
@ -1,17 +1,17 @@
|
||||||
2.0:
|
2:
|
||||||
Major modifications
|
Rename to "eris httpd" to acknowledge fork
|
||||||
Replace libowfat with libc
|
|
||||||
Replace buffer_1 and buffer_2 with stdio
|
|
||||||
Fix directory listing of / SEGV
|
|
||||||
Replace compile-time options with command-line ones
|
|
||||||
Add regression test suite
|
Add regression test suite
|
||||||
|
Replace compile-time options with command-line ones
|
||||||
1.11:
|
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
|
Fix if-modified-since date parsing
|
||||||
Make text content-types use charset=UTF-8
|
Make text content-types use charset=UTF-8
|
||||||
Change default content-type to application/octet-stream
|
Change default content-type to application/octet-stream
|
||||||
Makefile no longer overrides CC and CPP from parent makes
|
Makefile no longer overrides CC and CPP from parent makes
|
||||||
Don't send Content-type if there's no content
|
Don't send Content-type if there's no content
|
||||||
|
New maintainer: Neale Pickett <neale@woozle.org>
|
||||||
|
|
||||||
1.10:
|
1.10:
|
||||||
have fallback in case sendfile fails
|
have fallback in case sendfile fails
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -1,11 +1,11 @@
|
||||||
VERSION := $(shell head -n 1 CHANGES | tr -d :)
|
VERSION := $(shell head -n 1 CHANGES | tr -d :)
|
||||||
|
|
||||||
CFLAGS = -DFNORD='"fnord/$(VERSION)"' -Wall -Werror
|
CFLAGS = -DFNORD='"eris/$(VERSION)"' -Wall -Werror
|
||||||
|
|
||||||
all: fnord
|
all: eris
|
||||||
|
|
||||||
test: fnord
|
test: eris
|
||||||
cd tests && python3 ./test.py
|
cd tests && python3 ./test.py
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.[oa] fnord
|
rm -f *.[oa] eris
|
||||||
|
|
47
README
47
README
|
@ -1,3 +1,20 @@
|
||||||
|
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, Fefe, approved of the fork.
|
||||||
|
|
||||||
|
The 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 (use tcpserver)
|
||||||
|
* elimination of chroot code (use chroot)
|
||||||
|
* several bugfixes (which have been sent to the fnord mail list)
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
|
|
||||||
tcpserver -v -RHl localhost -u 1234 -g 1234 0 80 ./httpd
|
tcpserver -v -RHl localhost -u 1234 -g 1234 0 80 ./httpd
|
||||||
|
@ -13,13 +30,13 @@ 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.
|
||||||
|
|
||||||
fnord-httpd does simple virtual hosting. If the Host: HTTP header is
|
eris httpd does simple virtual hosting. If the Host: HTTP header is
|
||||||
there, fnord will try to chdir to a directory of that name, i.e. if the
|
there, eris will try to chdir to a directory of that name, i.e. if the
|
||||||
client asks for "/" on host "www.fefe.de:80", fnord will look for
|
client asks for "/" on host "www.fefe.de:80", eris will look for
|
||||||
"www.fefe.de:80/index.html". Fnord will also try the directory
|
"www.fefe.de:80/index.html". Eris will also try the directory
|
||||||
"default" if no specific directory for the virtual host was there. If
|
"default" if no specific directory for the virtual host was there. If
|
||||||
the directory is a dangling symlink and fnord was compiled with
|
the directory is a dangling symlink and eris was compiled with
|
||||||
-DREDIRECT (default), fnord will redirect the whole site. Examples:
|
-DREDIRECT (default), eris will redirect the whole site. 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:80 -> 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:80 -> =http://www.baz.de/
|
||||||
|
@ -27,35 +44,35 @@ the directory is a dangling symlink and fnord was compiled with
|
||||||
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/.
|
||||||
|
|
||||||
fnord implements el-cheapo HTTP ranges (only byte ranges and only of the
|
eris implements el-cheapo HTTP ranges (only byte ranges and only of the
|
||||||
form x-y, not multiple ranges).
|
form x-y, not multiple ranges).
|
||||||
|
|
||||||
fnord implements content type matching and Accepts: parsing, but the
|
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
|
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
|
the source code. Shouldn't be a problem because you _have_ the source
|
||||||
code ;)
|
code ;)
|
||||||
|
|
||||||
fnord implements HTTP redirection. If a file is not found, but a
|
eris implements HTTP redirection. If a file is not found, but a
|
||||||
dangling symlink is there under the same name, fnord will issue 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
|
redirection to the contents of that symlink. To be RFC compliant, the
|
||||||
symlink must point to a full URL, i.e.
|
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
|
||||||
|
|
||||||
fnord implements in-place substitution of * to *.gz
|
eris implements in-place substitution of * to *.gz
|
||||||
if the file is available and the client supports the mime-type and
|
if the file is available and the client supports the mime-type and
|
||||||
content-encoding. That means you can save substantial bandwidth by
|
content-encoding. That means you can save substantial bandwidth by
|
||||||
having an index.html.gz for each index.html, as most clients can
|
having an index.html.gz for each index.html, as most clients can
|
||||||
transparently decode gzipped files.
|
transparently decode gzipped files.
|
||||||
|
|
||||||
fnord 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.
|
||||||
|
|
||||||
fnord understands and implements keep-alive connections.
|
eris understands and implements keep-alive connections.
|
||||||
|
|
||||||
fnord can use sendfile on Linux to enable zero-copy TCP.
|
eris can use sendfile on Linux to enable zero-copy TCP.
|
||||||
|
|
||||||
If fnord 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.
|
||||||
CGI programs starting with "nph-" will be handled as no-parse-header
|
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
|
CGIs. Please see http://hoohoo.ncsa.uiuc.edu/cgi/interface.html for the
|
||||||
|
|
114
fnord.c → eris.c
114
fnord.c → eris.c
|
@ -38,6 +38,7 @@
|
||||||
#define DUMP_s(v) DUMPf("%s = %s", #v, v)
|
#define DUMP_s(v) DUMPf("%s = %s", #v, v)
|
||||||
#define DUMP_c(v) DUMPf("%s = %c", #v, v)
|
#define DUMP_c(v) DUMPf("%s = %c", #v, v)
|
||||||
#define DUMP_p(v) DUMPf("%s = %p", #v, v)
|
#define DUMP_p(v) DUMPf("%s = %p", #v, v)
|
||||||
|
#define DUMP_buf(v, l) DUMPf("%s = %.*s", #v, l, v)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the following is the time in seconds that fnord should wait for a valid
|
* the following is the time in seconds that fnord should wait for a valid
|
||||||
|
@ -70,10 +71,6 @@
|
||||||
#include <sys/sendfile.h>
|
#include <sys/sendfile.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef O_NDELAY
|
|
||||||
#define O_NDELAY O_NONBLOCK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define USE_MMAP
|
#define USE_MMAP
|
||||||
#ifndef _POSIX_MAPPED_FILES
|
#ifndef _POSIX_MAPPED_FILES
|
||||||
#undef USE_MMAP
|
#undef USE_MMAP
|
||||||
|
@ -219,6 +216,37 @@ elen(register const char *const *e)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
read_header(int fd, char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
int found = 0;
|
||||||
|
size_t p = 0;
|
||||||
|
|
||||||
|
while (found < 2) {
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
tmp = read(fd, buf + len, buflen - len);
|
||||||
|
if (tmp < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (tmp == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += tmp;
|
||||||
|
|
||||||
|
for (; p < len; p += 1) {
|
||||||
|
if (buf[p] == '\n') {
|
||||||
|
if (++found == 2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
env_append(const char *key, const char *val)
|
env_append(const char *key, const char *val)
|
||||||
{
|
{
|
||||||
|
@ -370,30 +398,37 @@ cgi_child(int sig)
|
||||||
signal(SIGCHLD, cgi_child);
|
signal(SIGCHLD, cgi_child);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/* Convert bare \n to \r\n in header. Return 0 if
|
||||||
|
* header is over. */
|
||||||
|
static int
|
||||||
cgi_send_correct_http(const char *s, unsigned int sl)
|
cgi_send_correct_http(const char *s, unsigned int sl)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
char ch = 0;
|
int newline = 0;
|
||||||
for (i = 0; i < sl; ++i) {
|
|
||||||
if ((s[i] == '\r') && (s[i + 1] == '\n')) {
|
for (i = 0; i < sl; i += 1) {
|
||||||
++i;
|
switch (s[i]) {
|
||||||
goto out_nl;
|
case '\r':
|
||||||
} else {
|
if (s[i + 1] == '\n') {
|
||||||
if (s[i] != '\n') {
|
i += 1;
|
||||||
putchar(s[i]);
|
case '\n':
|
||||||
} else {
|
|
||||||
out_nl:
|
|
||||||
printf("\r\n");
|
printf("\r\n");
|
||||||
if (ch == '\n') {
|
if (newline) {
|
||||||
++i;
|
fwrite(s + i + 1, sl - i - 1, 1, stdout);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
newline = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
default:
|
||||||
|
newline = 0;
|
||||||
|
putchar(s[i]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return 1;
|
||||||
ch = s[i];
|
|
||||||
}
|
|
||||||
printf("%.*s", sl - i, s + i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -442,17 +477,29 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp)
|
||||||
* read from cgi
|
* read from cgi
|
||||||
*/
|
*/
|
||||||
if (pfd[0].revents & POLLIN) {
|
if (pfd[0].revents & POLLIN) {
|
||||||
if (!(n = read(fd[0], ibuf, sizeof(ibuf))))
|
size_t len;
|
||||||
|
|
||||||
|
if (startup) {
|
||||||
|
/* XXX: could block :< */
|
||||||
|
len = read_header(fd[0], ibuf, sizeof ibuf);
|
||||||
|
} else {
|
||||||
|
len = read(fd[0], ibuf, sizeof ibuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == len) {
|
||||||
break;
|
break;
|
||||||
if (n < 0)
|
}
|
||||||
|
if (len == -1) {
|
||||||
goto cgi_500;
|
goto cgi_500;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* startup
|
* startup
|
||||||
*/
|
*/
|
||||||
if (startup) {
|
if (startup) {
|
||||||
startup = 0;
|
|
||||||
if (nph) { /* NPH-CGI */
|
if (nph) { /* NPH-CGI */
|
||||||
printf("%.*s", n, ibuf);
|
startup = 0;
|
||||||
|
printf("%.*s", len, ibuf);
|
||||||
/*
|
/*
|
||||||
* skip HTTP/x.x
|
* skip HTTP/x.x
|
||||||
*/
|
*/
|
||||||
|
@ -473,7 +520,8 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp)
|
||||||
FNORD
|
FNORD
|
||||||
"\r\nPragma: no-cache\r\nConnection: close\r\n");
|
"\r\nPragma: no-cache\r\nConnection: close\r\n");
|
||||||
signal(SIGCHLD, SIG_IGN);
|
signal(SIGCHLD, SIG_IGN);
|
||||||
cgi_send_correct_http(ibuf, n);
|
cgi_send_correct_http(ibuf, len);
|
||||||
|
startup = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,9 +529,9 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp)
|
||||||
* non startup
|
* non startup
|
||||||
*/
|
*/
|
||||||
else {
|
else {
|
||||||
printf("%.*s", n, ibuf);
|
fwrite(ibuf, len, 1, stdout);
|
||||||
}
|
}
|
||||||
size += n;
|
size += len;
|
||||||
if (pfd[0].revents & POLLHUP)
|
if (pfd[0].revents & POLLHUP)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1398,6 +1446,7 @@ serve_static_data(int fd)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[], const char *const *envp)
|
main(int argc, char *argv[], const char *const *envp)
|
||||||
{
|
{
|
||||||
|
@ -1797,14 +1846,17 @@ main(int argc, char *argv[], const char *const *envp)
|
||||||
}
|
}
|
||||||
printf("Content-Length: %llu\r\n",
|
printf("Content-Length: %llu\r\n",
|
||||||
(unsigned long long) (rangeend - rangestart));
|
(unsigned long long) (rangeend - rangestart));
|
||||||
printf("Last-Modified: ");
|
|
||||||
{
|
{
|
||||||
/* XXX: This parses tzinfo. It shouldn't have to. */
|
/*
|
||||||
|
* glibc's gmtime parses tzinfo, resulting in 9
|
||||||
|
* additional syscalls. uclibc doesn't do this.
|
||||||
|
* I presume dietlibc doesn't either.
|
||||||
|
*/
|
||||||
struct tm *x = gmtime(&st.st_mtime);
|
struct tm *x = gmtime(&st.st_mtime);
|
||||||
/*
|
/*
|
||||||
* "Sun, 06 Nov 1994 08:49:37 GMT"
|
* "Sun, 06 Nov 1994 08:49:37 GMT"
|
||||||
*/
|
*/
|
||||||
printf("%.3s, %02d %.3s %d %02d:%02d:%02d GMT\r\n",
|
printf("Last-Modified: %.3s, %02d %.3s %d %02d:%02d:%02d GMT\r\n",
|
||||||
days + (3 * x->tm_wday),
|
days + (3 * x->tm_wday),
|
||||||
x->tm_mday,
|
x->tm_mday,
|
||||||
months + (3 * x->tm_mon),
|
months + (3 * x->tm_mon),
|
|
@ -4,8 +4,8 @@ import unittest
|
||||||
from subprocess import *
|
from subprocess import *
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def fnord(*args):
|
def eris(*args):
|
||||||
return Popen(('../fnord',) + args,
|
return Popen(('../eris',) + args,
|
||||||
stdin=PIPE, stdout=PIPE, stderr=PIPE,
|
stdin=PIPE, stdout=PIPE, stderr=PIPE,
|
||||||
env={'PROTO': 'TCP',
|
env={'PROTO': 'TCP',
|
||||||
'TCPREMOTEPORT': '5858',
|
'TCPREMOTEPORT': '5858',
|
||||||
|
@ -13,9 +13,9 @@ def fnord(*args):
|
||||||
|
|
||||||
class ArgTests(unittest.TestCase):
|
class ArgTests(unittest.TestCase):
|
||||||
def check_index(self, *args):
|
def check_index(self, *args):
|
||||||
p = fnord(*args)
|
p = eris(*args)
|
||||||
so, se = p.communicate(b'GET / HTTP/1.0\r\n\r\n')
|
so, se = p.communicate(b'GET / HTTP/1.0\r\n\r\n')
|
||||||
self.assertRegex(so, b'HTTP/1.0 200 OK\r\nServer: fnord/2.0\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 6\r\nLast-Modified: (Mon|Tue|Wed|Thu|Fri|Sat|Sun), .. (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) 2... ..:..:.. GMT\r\n\r\njames\n')
|
self.assertRegex(so, b'HTTP/1.0 200 OK\r\nServer: eris/2\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Length: 6\r\nLast-Modified: (Mon|Tue|Wed|Thu|Fri|Sat|Sun), .. (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) 2... ..:..:.. GMT\r\n\r\njames\n')
|
||||||
self.assertEqual(se, b'10.1.2.3 200 6 127.0.0.1:80 (null) (null) /index.html\n')
|
self.assertEqual(se, b'10.1.2.3 200 6 127.0.0.1:80 (null) (null) /index.html\n')
|
||||||
|
|
||||||
def testArgs(self):
|
def testArgs(self):
|
||||||
|
@ -36,7 +36,7 @@ class BasicTests(unittest.TestCase):
|
||||||
args = []
|
args = []
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.p = fnord(*self.args)
|
self.p = eris(*self.args)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
del self.p
|
del self.p
|
||||||
|
@ -56,7 +56,7 @@ class DirTests(BasicTests):
|
||||||
|
|
||||||
def testRootDir(self):
|
def testRootDir(self):
|
||||||
so, se = self.get('/', 'empty')
|
so, se = self.get('/', 'empty')
|
||||||
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: fnord/2.0\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<h3>Directory Listing: /</h3>\n<pre>\n</pre>\n')
|
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: eris/2\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<h3>Directory Listing: /</h3>\n<pre>\n</pre>\n')
|
||||||
self.assertEqual(se, b'10.1.2.3 200 32 empty:80 (null) (null) /\n')
|
self.assertEqual(se, b'10.1.2.3 200 32 empty:80 (null) (null) /\n')
|
||||||
|
|
||||||
def testNoTrailingSlash(self):
|
def testNoTrailingSlash(self):
|
||||||
|
@ -67,7 +67,7 @@ class DirTests(BasicTests):
|
||||||
def testFiles(self):
|
def testFiles(self):
|
||||||
so, se = self.get('/files/', 'default')
|
so, se = self.get('/files/', 'default')
|
||||||
|
|
||||||
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: fnord/2.0\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<h3>Directory Listing: /files/</h3>\n<pre>\n<a href="/">Parent directory</a>\n[TXT] <a href="1.txt">1.txt</a>\n</pre>\n')
|
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: eris/2\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\n\r\n<h3>Directory Listing: /files/</h3>\n<pre>\n<a href="/">Parent directory</a>\n[TXT] <a href="1.txt">1.txt</a>\n</pre>\n')
|
||||||
self.assertEqual(se, b'10.1.2.3 200 110 default:80 (null) (null) /files/\n')
|
self.assertEqual(se, b'10.1.2.3 200 110 default:80 (null) (null) /files/\n')
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,17 +76,18 @@ class CGITests(BasicTests):
|
||||||
|
|
||||||
def testSet(self):
|
def testSet(self):
|
||||||
so, se = self.get('/cgi/set.cgi', 'default')
|
so, se = self.get('/cgi/set.cgi', 'default')
|
||||||
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: fnord/2.0\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:fnord/2.0\nSERVER_NAME:default:80\nSERVER_PORT:80\nREQUEST_METHOD:GET\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\n')
|
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: eris/2\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:eris/2\nSERVER_NAME:default:80\nSERVER_PORT:80\nREQUEST_METHOD:GET\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\n')
|
||||||
self.assertEqual(se, b'10.1.2.3 200 248 default:80 (null) (null) /cgi/set.cgi\n')
|
self.assertEqual(se, b'10.1.2.3 200 245 default:80 (null) (null) /cgi/set.cgi\n')
|
||||||
|
|
||||||
def testSetArgs(self):
|
def testSetArgs(self):
|
||||||
so, se = self.get('/cgi/set.cgi?a=1&b=2&c=3', 'default')
|
so, se = self.get('/cgi/set.cgi?a=1&b=2&c=3', 'default')
|
||||||
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: fnord/2.0\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:fnord/2.0\nSERVER_NAME:default:80\nSERVER_PORT:80\nREQUEST_METHOD:GET\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\nQUERY_STRING:a=1&b=2&c=3\n')
|
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: eris/2\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:eris/2\nSERVER_NAME:default:80\nSERVER_PORT:80\nREQUEST_METHOD:GET\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\nQUERY_STRING:a=1&b=2&c=3\n')
|
||||||
self.assertEqual(se, b'10.1.2.3 200 273 default:80 (null) (null) /cgi/set.cgi\n')
|
self.assertEqual(se, b'10.1.2.3 200 270 default:80 (null) (null) /cgi/set.cgi\n')
|
||||||
|
|
||||||
def testPost(self):
|
def testPost(self):
|
||||||
so, se = self.post('/cgi/set.cgi', 'default', 'a=1&b=2&c=3')
|
so, se = self.post('/cgi/set.cgi', 'default', 'a=1&b=2&c=3')
|
||||||
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: fnord/2.0\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:fnord/2.0\nSERVER_NAME:default:80\nSERVER_PORT:80\nREQUEST_METHOD:POST\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\nCONTENT_TYPE:application/x-www-form-urlencoded\nCONTENT_LENGTH:11\nForm data: a=1&b=2&c=3')
|
self.assertEqual(so, b'HTTP/1.0 200 OK\r\nServer: eris/2\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:eris/2\nSERVER_NAME:default:80\nSERVER_PORT:80\nREQUEST_METHOD:POST\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\nCONTENT_TYPE:application/x-www-form-urlencoded\nCONTENT_LENGTH:11\nForm data: a=1&b=2&c=3')
|
||||||
|
self.assertEqual(se, b'10.1.2.3 200 333 default:80 (null) (null) /cgi/set.cgi\n')
|
||||||
|
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue