#!/bin/bash set -e ADDR=127.0.0.1 PORT=1234 ROOT="$(realpath "${1:-$PWD}")" CR=$'\r' LF=$'\n' tmpdir="$(mktemp -d)" trap 'rm -r "$tmpdir"' EXIT trap 'exit' INT error() { code="$1" head="$2" message="$3" echo "HTTP/1.0 $code $head$CR" echo "Content-Type: text/plain$CR" echo "Connection: close$CR" echo "$CR" echo "$code $head$CR" echo "$CR" echo "$message" exit } handle() { connection_id="$1" response_pipe="$tmpdir/response-$connection_id.pipe" event_pipe="$tmpdir/event-$connection_id.pipe" mkfifo -m 0600 "$response_pipe" "$event_pipe" gnetcat --listen --source "$ADDR" --local-port "$PORT" --close < "$response_pipe" | sed -E -u 's/\r$//' | ( read method url version || { echo "Connection broken" > "$event_pipe" exit } cat >& /dev/null & # read but ignore headers and whatever else echo "$method $url" > "$event_pipe" if ! [ "$version" = "HTTP/1.0" -o "$version" = "HTTP/1.1" ]; then error 505 'HTTP Version Not Supported' "Version $version is not supported.${LF}Only 1.0 is really supported." fi if ! [ "$method" = "GET" ]; then error 501 'Not Implemented' "Method $method is not implemented.${LF}Only GET is supported." fi url="$(echo "$url" | urlencode -d)" if ! echo "$url" | grep -q '^/'; then error 400 'Bad Request' "URL must be host-relative" fi if echo "$url" | grep -q '/\.'; then error 403 'Forbidden' "Dot-files are forbidden" fi target="$ROOT$url" name=$(basename "$url") if [ -f "$target" ]; then echo "HTTP/1.0 200 OK$CR" echo "Connection: close$CR" echo "$CR" cat "$target" exit fi if [ -d "$target" ]; then if ! echo "$url" | grep -q '/$'; then echo "HTTP/1.0 307 Temporary Redirect$CR" echo "Connection: close$CR" echo "Location: $url/$CR" exit fi ls "$target" 2>/dev/null | { echo "HTTP/1.0 200 OK$CR" echo "Content-Type: text/html; charset=utf-8$CR" echo "Connection: close$CR" echo "$CR" echo "" echo "Directory listing for $url" echo "

$name

" echo "

up" echo "

" } || error 403 'Forbidden' "Permission denied for $url" exit fi error 404 'Not Found' "Requested file $url is not found" ) > "$response_pipe" & rm "$response_pipe" cat "$event_pipe" rm "$event_pipe" } echo "Listening at $ADDR:$PORT" echo "Serving $ROOT" for((i=0;;i++)); do handle $i done