Skip to content

Instantly share code, notes, and snippets.

@mwgamera
Last active May 5, 2019 15:08
Show Gist options
  • Save mwgamera/52108d05cdc2161843c036482828650b to your computer and use it in GitHub Desktop.
Save mwgamera/52108d05cdc2161843c036482828650b to your computer and use it in GitHub Desktop.
Product of some lunacy; usable for foot-shooting, maybe.
#!/bin/sh
# klg, Dec 2018
set -e
if ! [ '/--slave' = "/$1" ]
then
root_dir="${1:-.}"; ( cd "$root_dir"; )
charset=$(locale charmap 2>/dev/null || :)
echo >&2 "Serving $root_dir on http://localhost:${PORT:=8000}/ ..."
exec env - "PATH=$PATH" "charset=$charset" "root_dir=$root_dir" \
socat "TCP6-LISTEN:$PORT,reuseaddr,fork" "EXEC:$0 --slave"
fi
export LC_ALL=C
cd "$root_dir"
: "${charset:=L1}"
htmlesc() {
echo "$@" | sed \
-e 's/\&/\&/g' \
-e 's/</\&lt;/g' \
-e 's/>/\&gt;/g' \
-e 's/"/\&quot;/g' \
-e 's/'\''/\&apos;/g'
}
mime_ext() {
set -- "${1##*.}"
case "$1" in
([Hh][Tt][Mm]|[Hh][Tt][Mm][Ll]) echo 'text/html' ;;
([Tt][Xx][Tt]) echo 'text/plain' ;;
(*) awk -v "ext=$1" 'BEGIN{ext=tolower(ext)}
!/^#/&&$2{for(i=2;i<=NF;i++)if(ext==tolower($i)){print$1;exit}}' /etc/mime.types ;;
esac
}
error() {
code="$1"; shift
case "$code" in
(301) status='Moved Permanently';;
(302) status='Moved Temporarily';;
(403) status='Forbidden';;
(404) status='Not Found';;
(405) status='Method Not Allowed'; set -- "$@" 'Allow:GET';;
(*) status=Error;;
esac
if [ -n "$SERVER_PROTOCOL" ]
then
printf '%s\r\n' "HTTP/1.0 $code $status" \
"Content-Type:text/html;charset=$charset" "$@" ''
fi
code=$(htmlesc "$code")
status=$(htmlesc "$status")
echo "<!doctype html><html lang=\"en\"><meta charset=\"$charset\">"
echo "<title>$code - $status</title><h1>$code &mdash; $status</h1>"
exit
}
send_file() {
[ -r "$REQUEST_FILE" ] || error 403
if [ -n "$SERVER_PROTOCOL" ]
then
set --
mime_type=$(attr -q -g mime_type "$REQUEST_FILE" 2>/dev/null || :)
charset=$(attr -q -g charset "$REQUEST_FILE" 2>/dev/null || :)
: "${mime_type:=$(mime_ext "$REQUEST_FILE")}"
set -- "$@" "Content-Type:${mime_type:-text/plain}${charset:+";charset=$charset"}"
printf '%s\r\n' 'HTTP/1.0 200 OK' "$@" ''
fi
exec cat "$REQUEST_FILE"
}
dir_listing() {
[ -r "$REQUEST_FILE" ] || error 403
if [ -n "$SERVER_PROTOCOL" ]
then
set -- "Content-Type:text/html;charset=$charset"
printf '%s\r\n' 'HTTP/1.0 200 OK' "$@" ''
fi
echo "<!doctype html><html lang=\"en\"><meta charset=\"$charset\">"
html_dir="$(htmlesc "${REQUEST_URI%/}")"
echo "<title>Index of ${html_dir:-/}</title><h1>Index of ${html_dir:-/}</h1>"
echo '<ul>'
for file in "$REQUEST_FILE"/*
do
html_file=$(htmlesc "${file##*/}")
#html_path=$(printf '%s' "${file##*/}"| od -An -tx1 | tr -d '\n' | tr ' ' '%')
html_path="$html_file" # this ok if charset is utf8
if [ -x "$file/" ]
then
echo "<li><a href=\"$html_dir/$html_path/\">$html_file/</a></li>"
elif [ -f "$file" ]
then
echo "<li><a href=\"$html_dir/$html_path\">$html_file</a></li>"
fi
done
echo '</ul>'
}
read -r REQUEST_METHOD REQUEST_URI SERVER_PROTOCOL
echo >&2 "$SOCAT_PEERADDR \"$(echo "$REQUEST_METHOD $REQUEST_URI ${SERVER_PROTOCOL% }" | sed 's/[^ -~]/?/g')\""
case "$REQUEST_METHOD" in ([Gg][Ee][Tt]);; (*) error 405;; esac
REQUEST_FILE=$(echo "./$REQUEST_URI" | sed -e "$(awk 'BEGIN {
for(i = 1; i < 256; i++)
if (i != 25)
if (i >= 48 && i <= 57 || i >= 65 && i < 128 && i != 92)
printf("s/%%%02X/%c/gi;", i, i);
else
printf("s/%%%02X/\\%c/gi;", i, i);
print("s/%25/%/gi");
}')")
case "$REQUEST_FILE" in (*/.*) error 403;; esac
if [ -f "$REQUEST_FILE" ]
then
send_file
elif [ -d "$REQUEST_FILE/" ]
then
[ "/$REQUEST_FILE" = "/${REQUEST_FILE%/}" ] && error 301 "Location:$REQUEST_URI/"
if [ -f "$REQUEST_FILE/index.html" ]
then
REQUEST_FILE="$REQUEST_FILE/index.html"
send_file
else
dir_listing
fi
else
error 404
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment