Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -1,3 +1,4 @@ filed filed.o filed-mime-types.h +compiled Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -1,32 +1,34 @@ CC = gcc -CFLAGS = -std=gnu11 -Wall -W -pthread -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE $(FILED_EXTRA_CFLAGS) +CFLAGS = -I. -std=gnu11 -Wall -W -pthread -O3 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE $(FILED_EXTRA_CFLAGS) LDFLAGS = -pthread $(FILED_EXTRA_LDFLAGS) LIBS = -lpthread $(FILED_EXTRA_LIBS) MIMETYPES = /etc/httpd/mime.types PREFIX = /usr/local prefix = $(PREFIX) bindir = $(prefix)/bin mandir = $(prefix)/share/man +srcdir = . +vpath %.c $(srcdir) all: filed filed: filed.o $(CC) $(CFLAGS) $(LDFLAGS) -o "$@" $^ $(LIBS) -filed.o: filed.c filed-mime-types.h +filed.o: $(srcdir)/filed.c filed-mime-types.h -filed-mime-types.h: generate-mime-types mime.types - ./generate-mime-types "$(MIMETYPES)" > filed-mime-types.h.new || \ - ./generate-mime-types mime.types > filed-mime-types.h.new +filed-mime-types.h: $(srcdir)/generate-mime-types $(srcdir)/mime.types + '$(srcdir)/generate-mime-types' '$(MIMETYPES)' > filed-mime-types.h.new || \ + '$(srcdir)/generate-mime-types' '$(srcdir)/mime.types' > filed-mime-types.h.new mv filed-mime-types.h.new filed-mime-types.h -install: filed filed.1 +install: filed $(srcdir)/filed.1 test -d "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" test -d "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)" - cp filed.1 "$(DESTDIR)$(mandir)/man1/" + cp '$(srcdir)/filed.1' "$(DESTDIR)$(mandir)/man1/" cp filed "$(DESTDIR)$(bindir)/" clean: rm -f filed filed.o rm -f filed-mime-types.h.new Index: README ================================================================== --- README +++ README @@ -72,11 +72,16 @@ In these cases the executable may be compiled with the FILED_FAKE_CHROOT C preprocessor macro defined and instead of calling chroot() all HTTP requests will have the root suffix specified as the argument to the "-r" or "--root" option prepended to them. - 5. MIME Types (MIMETYPES) + 5. Differing "index.html" handling (CFLAGS, -DFILED_DONT_REDIRECT_DIRECTORIES=1) + Normally "filed" redirects users who request a directory to the + index.html file in that directory so that no memory allocations are + required; This option lets the server generate the new path. + + 6. MIME Types (MIMETYPES) For single-file convenience "filed" compiles the mapping of file extensions (the string in the filename following its last dot (".")) into the executable. This mapping comes from a file in the format of type1 type1_extension1 type1_extension2... type2 type2_extension1 type2_extension2... ADDED build/build-precompiled Index: build/build-precompiled ================================================================== --- /dev/null +++ build/build-precompiled @@ -0,0 +1,65 @@ +#! /usr/bin/env bash + +# Ensure we are in the correct working directory +cd "$(dirname "$(which "$0")")/.." || exit 1 + +# Determine the version of Filed +version='' +eval "$(( grep '^# *define *FILED_VERSION' filed.c; echo '|version=FILED_VERSION' ) | cpp -E | grep '^|' | sed 's@^|@@')" +if [ -z "${version}" ]; then + echo "Unable to determine which version of Filed we are compiling. Aborting." >&2 + + exit 1 +fi + +# Cleanup +rm -rf workdir-buildPrecompiled-* + +# Compile everything, all at once +idx=-1 +for tryCompilerDir in "$(readlink -f ~/root/cross-compilers)" "$(readlink -f ~/devel/build-cc/TMP)"; do + setup_cc="${tryCompilerDir}/setup-cc" + + platforms=( + $("${setup_cc}" | tail -n +2) + ) + + for platform in "${platforms[@]}"; do + idx=$[$idx + 1] + ( + workdir="workdir-buildPrecompiled-${idx}-$(openssl rand 20 -hex)-platform-${platform}" || exit 1 + mkdir "${workdir}" || exit 1 + cd "${workdir}" || exit 1 + + eval $("${setup_cc}" "${platform}") + make_extra=( + -f ../Makefile + srcdir=.. + CC="${CC}" + ) + + case "${platform}" in + *-musl-*|*-musl) + make_extra=("${make_extra[@]}" FILED_EXTRA_LDFLAGS="-static") + ;; + esac + + make "${make_extra[@]}" + ) & + done +done + +# Wait for that to get done +wait + +# Rename the files into place +mkdir -p compiled +for binary in workdir-buildPrecompiled-*/filed; do + platform="$(echo "${binary}" | sed 's@^.*-platform-@@;s@/.*$@@')" + mv "${binary}" "compiled/filed-${version}-${platform}" +done + +# Cleanup +rm -rf workdir-buildPrecompiled-* + +exit 0 Index: filed.1 ================================================================== --- filed.1 +++ filed.1 @@ -1,7 +1,7 @@ .PU -.TH FILED 1 "17 Aug 2016" "filed 1.19" +.TH FILED 1 "22 Sep 2016" "filed 1.21" .SH NAME filed \- serve files over HTTP .SH SYNOPSIS .ll +10 .B filed Index: filed.c ================================================================== --- filed.c +++ filed.c @@ -42,11 +42,11 @@ #include #include #include /* Compile time constants */ -#define FILED_VERSION "1.19" +#define FILED_VERSION "1.21" #define FILED_SENDFILE_MAX 16777215 #define FILED_MAX_FAILURE_COUNT 30 #define FILED_DEFAULT_TYPE "application/octet-stream" #define FILED_PATH_BUFFER_SIZE 1010 @@ -272,10 +272,12 @@ } /* Initialize process */ static int filed_init(unsigned int cache_size) { static int called = 0; + struct sigaction signal_handler_info; + sigset_t signal_handler_mask; ssize_t read_ret = 0; unsigned int random_value = 0; int cache_ret; int random_fd; @@ -286,15 +288,24 @@ called = 1; /* Attempt to lock all memory to physical RAM (but don't care if we can't) */ mlockall(MCL_CURRENT | MCL_FUTURE); - /* Ignore SIGPIPE */ - signal(SIGPIPE, SIG_IGN); + /* Establish signal handlers */ + /* SIGPIPE should interrupt system calls */ + sigfillset(&signal_handler_mask); + signal_handler_info.sa_handler = filed_signal_handler; + signal_handler_info.sa_mask = signal_handler_mask; + signal_handler_info.sa_flags = SA_RESTART; + sigaction(SIGPIPE, &signal_handler_info, NULL); /* Handle SIGHUP to release all caches */ - signal(SIGHUP, filed_signal_handler); + sigfillset(&signal_handler_mask); + signal_handler_info.sa_handler = filed_signal_handler; + signal_handler_info.sa_mask = signal_handler_mask; + signal_handler_info.sa_flags = 0; + sigaction(SIGHUP, &signal_handler_info, NULL); /* Initialize cache structure */ cache_ret = filed_init_cache(cache_size); if (cache_ret != 0) { return(cache_ret); @@ -605,11 +616,11 @@ time_t filed_sockettimeout_time; struct { time_t expiration_time; pthread_t thread_id; int valid; -}* filed_sockettimeout_sockstatus; +} *filed_sockettimeout_sockstatus; long filed_sockettimeout_sockstatus_length; int filed_sockettimeout_devnull_fd; static int filed_sockettimeout_sockfd_in_range(int sockfd) { if (sockfd < 3) { @@ -678,19 +689,22 @@ return; } static void *filed_sockettimeout_thread(void *arg) { + struct timespec sleep_time; time_t now, expiration_time; pthread_t thread_id; long idx; int count; int valid; while (1) { for (count = 0; count < 10; count++) { - usleep(30000000); + sleep_time.tv_sec = 30; + sleep_time.tv_nsec = 0; + nanosleep(&sleep_time, NULL); now = time(NULL); atomic_store(&filed_sockettimeout_time, now); } @@ -738,20 +752,20 @@ maxfd = sysconf(_SC_OPEN_MAX); if (maxfd <= 0) { maxfd = 4096; } - filed_sockettimeout_sockstatus = malloc(sizeof(*filed_sockettimeout_sockstatus) * maxfd); + filed_sockettimeout_sockstatus_length = maxfd; + filed_sockettimeout_sockstatus = malloc(sizeof(*filed_sockettimeout_sockstatus) * filed_sockettimeout_sockstatus_length); if (filed_sockettimeout_sockstatus == NULL) { return(-1); } for (idx = 0; idx < maxfd; idx++) { filed_sockettimeout_sockstatus[idx].valid = false; } - filed_sockettimeout_sockstatus_length = maxfd; filed_sockettimeout_devnull_fd = open("/dev/null", O_RDWR); if (filed_sockettimeout_devnull_fd < 0) { return(-1); } @@ -1169,12 +1183,13 @@ return; } /* Return a redirect to index.html */ +#ifndef FILED_DONT_REDIRECT_DIRECTORIES static void filed_redirect_index(FILE *fp, const char *date_current, const char *path, struct filed_log_entry *log) { - int http_code = 301; + int http_code = 302; fprintf(fp, "HTTP/1.1 %i OK\r\nDate: %s\r\nServer: filed\r\nLast-Modified: %s\r\nContent-Length: 0\r\nConnection: close\r\nLocation: %s\r\n\r\n", http_code, date_current, date_current, "index.html" @@ -1194,10 +1209,11 @@ return; /* Currently unused: path */ path = path; } +#endif /* Convert an enum representing the "Connection" header value to a string */ static const char *filed_connection_str(int connection_value) { switch (connection_value) { case FILED_CONNECTION_CLOSE: @@ -1255,13 +1271,28 @@ strcpy(log->buffer, path); log->method = request->method; /* If the requested path is a directory, redirect to index page */ if (request->type == FILED_REQUEST_TYPE_DIRECTORY) { +#ifdef FILED_DONT_REDIRECT_DIRECTORIES + char localpath[8192]; + int snprintf_ret; + + snprintf_ret = snprintf(localpath, sizeof(localpath), "%s/index.html", path); + + if (snprintf_ret <= 0 || snprintf_ret > (sizeof(localpath) - 1)) { + filed_error_page(fp, date_current, 500, request->method, "path_format", log); + + return(FILED_CONNECTION_CLOSE); + } + + path = localpath; +#else filed_redirect_index(fp, date_current, path, log); return(FILED_CONNECTION_CLOSE); +#endif } fileinfo = filed_open_file(path, &request->fileinfo, options); if (fileinfo == NULL) { filed_error_page(fp, date_current, 404, request->method, "open_failed", log); @@ -1876,11 +1907,11 @@ } /* Wait for threads to exit */ /* XXX:TODO: Monitor thread usage */ while (1) { - sleep(60); + sleep(86400); } /* Return in failure */ return(2); }