Compare commits

...

7 Commits

Author SHA1 Message Date
Emil Mikulic a7b8f8fa6e [ darkhttpd 1.14 release ] 2022-10-02 12:29:13 +11:00
Emil Mikulic a88ecadafe fuzzer: take optional port number from environment variable.
Makes it possible to run multiple fuzzer processes in parallel.
2022-10-02 12:24:17 +11:00
Emil Mikulic 762956f1a8 Set running = 1 before entering the main loop.
This is so the fuzzer can wait for it.
2022-10-02 12:21:33 +11:00
artemis everfree 47920915c7
Update illumos support to the modern era (#24)
* Update Solaris / Illumos support

Old versions of Solaris did not have vasprintf, so darkhttpd defined one
gated behind an ifdef. Oracle Solaris 10 has had vasprintf since 2011.
Oracle Solaris 11 has had it since release. illumos (which also reports
as `__sun`) also has it in all current incarnations. As a result, this
ifdef'd block creates compiler errors due to a second definition of the
function. This commit removes the block.

This commit also adds `-lsendfile` to the Makefile for systems that
report as `SunOS` in `uname` (Solaris and Illumos), which is necessary
to link successfully in current day.

* Comment on manually specifying CC in readme

Some systems, including versions of illumos I use, do not have a `cc`
alias to the system C compiler. Arguably this is a flaw in the
distribution, but as a user, it's perhaps helpful to be reminded that
this is an option.
2022-10-02 11:56:40 +11:00
Emil Mikulic 1eb6daa357 Fix crash when a file has a large (year 10,000+) mtime.
https://bugzilla.redhat.com/show_bug.cgi?id=1893725
https://github.com/emikulic/darkhttpd/issues/21
2022-10-02 11:50:02 +11:00
Emil Mikulic 1f166293b7 Update tests after adding slash to href for directories. 2022-10-02 11:38:12 +11:00
Emil Mikulic 1e4cddb6b6 Disable msan because it's not working.
It looks like parts of dlent are not being unpoisoned.
2022-10-02 11:34:56 +11:00
7 changed files with 75 additions and 43 deletions

View File

@ -1,6 +1,6 @@
CC?=cc
CFLAGS?=-O
LIBS=`[ \`uname\` = "SunOS" ] && echo -lsocket -lnsl`
LIBS=`[ \`uname\` = "SunOS" ] && echo -lsocket -lnsl -lsendfile`
all: darkhttpd

View File

@ -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):

View File

@ -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 */

View File

@ -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];

View File

@ -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

View File

@ -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"

View File

@ -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()