Compare commits
7 Commits
a981031e6f
...
a7b8f8fa6e
Author | SHA1 | Date |
---|---|---|
Emil Mikulic | a7b8f8fa6e | |
Emil Mikulic | a88ecadafe | |
Emil Mikulic | 762956f1a8 | |
artemis everfree | 47920915c7 | |
Emil Mikulic | 1eb6daa357 | |
Emil Mikulic | 1f166293b7 | |
Emil Mikulic | 1e4cddb6b6 |
2
Makefile
2
Makefile
|
@ -1,6 +1,6 @@
|
|||
CC?=cc
|
||||
CFLAGS?=-O
|
||||
LIBS=`[ \`uname\` = "SunOS" ] && echo -lsocket -lnsl`
|
||||
LIBS=`[ \`uname\` = "SunOS" ] && echo -lsocket -lnsl -lsendfile`
|
||||
|
||||
all: darkhttpd
|
||||
|
||||
|
|
|
@ -48,6 +48,12 @@ Simply run make:
|
|||
make
|
||||
```
|
||||
|
||||
If `cc` is not on your `PATH` as an alias to your C compiler, you may need to specify it. For example,
|
||||
|
||||
```
|
||||
CC=gcc make
|
||||
```
|
||||
|
||||
## How to run darkhttpd
|
||||
|
||||
Serve /var/www/htdocs on the default port (80 if running as root, else 8080):
|
||||
|
|
29
darkhttpd.c
29
darkhttpd.c
|
@ -1,6 +1,6 @@
|
|||
/* darkhttpd - a simple, single-threaded, static content webserver.
|
||||
* https://unix4lyfe.org/darkhttpd/
|
||||
* Copyright (c) 2003-2021 Emil Mikulic <emikulic@gmail.com>
|
||||
* Copyright (c) 2003-2022 Emil Mikulic <emikulic@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the
|
||||
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
static const char
|
||||
pkgname[] = "darkhttpd/1.13.from.git",
|
||||
copyright[] = "copyright (c) 2003-2021 Emil Mikulic";
|
||||
pkgname[] = "darkhttpd/1.14",
|
||||
copyright[] = "copyright (c) 2003-2022 Emil Mikulic";
|
||||
|
||||
/* Possible build options: -DDEBUG -DNO_IPV6 */
|
||||
|
||||
|
@ -308,7 +308,7 @@ static char *auth_key = NULL;
|
|||
static uint64_t num_requests = 0, total_in = 0, total_out = 0;
|
||||
static int accepting = 1; /* set to 0 to stop accept()ing */
|
||||
static int syslog_enabled = 0;
|
||||
static volatile int running = 1; /* signal handler sets this to false */
|
||||
volatile int running = 0; /* signal handler sets this to false */
|
||||
|
||||
#define INVALID_UID ((uid_t) -1)
|
||||
#define INVALID_GID ((gid_t) -1)
|
||||
|
@ -381,16 +381,6 @@ static char *xstrdup(const char *src) {
|
|||
return dest;
|
||||
}
|
||||
|
||||
#ifdef __sun /* unimpressed by Solaris */
|
||||
static int vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
char tmp;
|
||||
int result = vsnprintf(&tmp, 1, fmt, ap);
|
||||
*strp = xmalloc(result+1);
|
||||
result = vsnprintf(*strp, result+1, fmt, ap);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* vasprintf() that dies if it fails. */
|
||||
static unsigned int xvasprintf(char **ret, const char *format, va_list ap)
|
||||
__printflike(2,0);
|
||||
|
@ -1301,8 +1291,9 @@ static void logencode(const char *src, char *dest) {
|
|||
static char *clf_date(char *dest, const time_t when) {
|
||||
time_t when_copy = when;
|
||||
if (strftime(dest, CLF_DATE_LEN,
|
||||
"[%d/%b/%Y:%H:%M:%S %z]", localtime(&when_copy)) == 0)
|
||||
errx(1, "strftime() failed [%s]", dest);
|
||||
"[%d/%b/%Y:%H:%M:%S %z]", localtime(&when_copy)) == 0) {
|
||||
dest[0] = 0;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
@ -1456,8 +1447,9 @@ static void poll_check_timeout(struct connection *conn) {
|
|||
static char *rfc1123_date(char *dest, const time_t when) {
|
||||
time_t when_copy = when;
|
||||
if (strftime(dest, DATE_LEN,
|
||||
"%a, %d %b %Y %H:%M:%S GMT", gmtime(&when_copy)) == 0)
|
||||
errx(1, "strftime() failed [%s]", dest);
|
||||
"%a, %d %b %Y %H:%M:%S GMT", gmtime(&when_copy)) == 0) {
|
||||
dest[0] = 0;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
@ -2855,6 +2847,7 @@ int main(int argc, char **argv) {
|
|||
if (want_daemon) daemonize_finish();
|
||||
|
||||
/* main loop */
|
||||
running = 1;
|
||||
while (running) httpd_poll();
|
||||
|
||||
/* clean exit */
|
||||
|
|
|
@ -6,13 +6,16 @@
|
|||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <thread>
|
||||
|
||||
extern "C" int darkhttpd(int argc, const char** argv);
|
||||
extern "C" volatile int running;
|
||||
|
||||
namespace {
|
||||
int argc = 4;
|
||||
const char* argv[] = {"./a.out", "tmp.fuzz", "--log", "/dev/null"};
|
||||
int argc = 6;
|
||||
const char* argv[] = {"./a.out", "tmp.fuzz", "--log", "/dev/null",
|
||||
"--port", "8080"};
|
||||
std::thread* thr;
|
||||
const char* host = "127.0.0.1";
|
||||
int port = 8080;
|
||||
|
@ -23,11 +26,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||
static bool inited = false;
|
||||
if (!inited) {
|
||||
thr = new std::thread([]() { darkhttpd(argc, argv); });
|
||||
|
||||
// If PORT is set in the environment, use it as the port number.
|
||||
char* port_str = getenv("PORT");
|
||||
if (port_str) {
|
||||
port = atoi(port_str);
|
||||
argv[argc - 1] = port_str;
|
||||
}
|
||||
|
||||
addrin.sin_family = AF_INET;
|
||||
addrin.sin_port = htons(port);
|
||||
if (inet_aton(host, &addrin.sin_addr) == 0) err(1, "inet_aton");
|
||||
while (!running) { std::this_thread::yield(); }
|
||||
inited = true;
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
char buf[4096];
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#!/bin/bash -e
|
||||
set -x
|
||||
mkdir -p tmp.fuzz
|
||||
echo hi > tmp.fuzz/hello.txt
|
||||
mkdir -p fuzz_socket_testcases
|
||||
clang -c -Dmain=darkhttpd -g -O2 -fsanitize=fuzzer,address ../darkhttpd.c -o fuzz_darkhttpd.o
|
||||
clang++ -g -O2 -fsanitize=fuzzer,address fuzz_socket.cc fuzz_darkhttpd.o -o fuzz_socket
|
||||
./fuzz_socket fuzz_socket_testcases -detect_leaks=0 -only_ascii=1
|
||||
|
||||
# Or run multiple processes on different ports with e.g.:
|
||||
# env PORT=9999 ./fuzz_socket fuzz_socket_testcases -detect_leaks=0 -only_ascii=1
|
||||
|
|
|
@ -158,22 +158,23 @@ $CC -O2 -Wall -DNO_IPV6 ../darkhttpd.c || exit 1
|
|||
# -fsanitize=address produces stderr and crashes.
|
||||
# -fsanitize=memory produces stderr and crashes.
|
||||
|
||||
# msan first.
|
||||
if ! $CLANG -v 2>/dev/null; then
|
||||
echo "***WARNING*** Can't find clang."
|
||||
echo "Skipping memory sanitizer. Try setting the \$CLANG env var."
|
||||
else
|
||||
echo "===> building a.out for msan"
|
||||
$CLANG -g -O2 -fsanitize=memory -DDEBUG -DAPBUF_INIT=1 \
|
||||
../darkhttpd.c || exit 1
|
||||
(runtests) || {
|
||||
echo "FAILED! stderr was:"
|
||||
echo "---"
|
||||
cat test.out.stderr
|
||||
echo "---"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
# msan disabled due to issues with dlent.
|
||||
## # msan first.
|
||||
## if ! $CLANG -v 2>/dev/null; then
|
||||
## echo "***WARNING*** Can't find clang."
|
||||
## echo "Skipping memory sanitizer. Try setting the \$CLANG env var."
|
||||
## else
|
||||
## echo "===> building a.out for msan"
|
||||
## $CLANG -g -O2 -fsanitize=memory -DDEBUG -DAPBUF_INIT=1 \
|
||||
## ../darkhttpd.c || exit 1
|
||||
## (runtests) || {
|
||||
## echo "FAILED! stderr was:"
|
||||
## echo "---"
|
||||
## cat test.out.stderr
|
||||
## echo "---"
|
||||
## exit 1
|
||||
## }
|
||||
## fi
|
||||
|
||||
# asan and coverage next.
|
||||
echo "===> building a.out and darkhttpd.gcno for coverage + asan + ubsan"
|
||||
|
|
|
@ -6,6 +6,7 @@ import signal
|
|||
import re
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
WWWROOT = "tmp.httpd.tests"
|
||||
|
||||
|
@ -120,7 +121,7 @@ class TestHelper(unittest.TestCase):
|
|||
|
||||
def assertIsIndex(self, body, path):
|
||||
self.assertContains(body,
|
||||
'<a href="..">..</a>/',
|
||||
'<a href="../">..</a>/',
|
||||
'Generated by darkhttpd')
|
||||
|
||||
def assertIsInvalid(self, body, path):
|
||||
|
@ -178,8 +179,8 @@ class TestDirList(TestHelper):
|
|||
resp = self.get("/")
|
||||
status, hdrs, body = parse(resp)
|
||||
self.assertLess(b'(', b'..') # ( sorts before ..
|
||||
paren_pos = body.index(b'<a href="%28">(</a>/')
|
||||
dotdot_pos = body.index(b'<a href="..">..</a>/')
|
||||
paren_pos = body.index(b'<a href="%28/">(</a>/')
|
||||
dotdot_pos = body.index(b'<a href="../">..</a>/')
|
||||
# But we special-case .. to come first
|
||||
self.assertLess(dotdot_pos, paren_pos)
|
||||
|
||||
|
@ -470,6 +471,24 @@ class TestLargeFile2G(TestHelper):
|
|||
class TestLargeFile4G(TestLargeFile2G):
|
||||
BOUNDARY = 1<<32
|
||||
|
||||
class TestLargeMtime(TestHelper):
|
||||
def setUp(self):
|
||||
self.url = '/large_mtime'
|
||||
self.fn = WWWROOT + self.url
|
||||
with open(self.fn, 'wb') as f:
|
||||
f.write(b'x')
|
||||
# A timestamp in the year 10,000
|
||||
t = int(time.mktime((10000,3,14,1,2,3,0,0,-1)))
|
||||
os.utime(self.fn, (t, t))
|
||||
|
||||
def tearDown(self):
|
||||
os.unlink(self.fn)
|
||||
|
||||
def test_file_get(self):
|
||||
resp = self.get(self.url)
|
||||
status, hdrs, body = parse(resp)
|
||||
self.assertContains(status, "200 OK")
|
||||
|
||||
if __name__ == '__main__':
|
||||
setUpModule()
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue