+#!/bin/zsh
+
+# Copyright 2016 - 2018 Paul Hänsch
+#
+# This file is part of cgilite.
+#
+# cgilite is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cgilite is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with cgilite. If not, see <http://www.gnu.org/licenses/>.
+
+file_type(){
+ case ${1##*.} in
+ html|html) printf 'text/html';;
+ css) printf 'text/css';;
+ js) printf 'text/javascript';;
+ txt) printf 'text/plain';;
+ sh) printf 'text/shellscript';;
+ jpg|jpeg) printf 'image/jpeg';;
+ png) printf 'image/png';;
+ svg) printf 'image/svg+xml';;
+ gif) printf 'image/gif';;
+ webm) printf 'video/webm';;
+ mp4) printf 'video/mp4';;
+ ogg) printf 'audio/ogg';;
+ xml) printf 'application/xml';;
+ *) printf 'application/octet-stream';;
+ esac
+}
+
+FILE(){
+ unset range file_size file_date http_date cachedate
+ file="$1"
+
+ if ! [ -f "$file" ]; then
+ printf 'Status: 404 Not Found\r\n\r\n'
+ exit 0
+ elif ! [ -r "$file" ]; then
+ printf 'Status: 403 Forbidden\r\n\r\n'
+ exit 0
+ fi
+
+ file_size="$(stat -Lc %s "$file")"
+ file_date="$(stat -Lc %Y "$file")"
+ http_date="$(date -uRd @$file_date)"
+ http_date="${http_date%+0000}GMT"
+ cachedate="$(
+ # Parse the allowable date formats from Section 3.3.1 of
+ # https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html
+ HEADER If-Modified-Since \
+ | sed -r 's;^[^ ]+, ([0-9]{2}) (...) ([0-9]{4}) (..:..:..) GMT$;\3-\2-\1 \4;;
+ s;^[^ ]+, ([0-9]{2})-(...)-([789][0-9]) (..:..:..) GMT$;19\3-\2-\1 \4;;
+ s;^[^ ]+, ([0-9]{2})-(...)-([0-6][0-9]) (..:..:..) GMT$;20\3-\2-\1 \4;;
+ s;^[^ ]+ (...) ([0-9]{2}) (..:..:..) ([0-9]{4})$;\4-\1-\2 \3;;
+ s;^[^ ]+ (...) ([0-9]) (..:..:..) ([0-9]{4})$;\4-\1-\2 \3;;
+ s;Jan;01;; s;Feb;02;; s;Mar;03;; s;Apr;04;; s;May;05;; s;Jun;06;;
+ s;Jul;07;; s;Aug;08;; s;Sep;09;; s;Oct;10;; s;Nov;11;; s;Dec;12;;' \
+ | xargs -0 date +%s -ud 2>&-
+ )"
+
+ range="$(HEADER Range |sed -nr 's;^bytes=([0-9]+-[0-9]*|-[0-9]+)$;\1;p;q;')"
+ case "$range" in
+ *-) range="${range}$((file_size - 1))";;
+ -*) [ ${range#-} -le $file_size ] \
+ && range="$((file-size - ${rang#-}))-$((file_size - 1))" \
+ || range="0-$((file_size - 1))";;
+ *-*) [ ${range#*-} -ge $file_size ] \
+ && range="${range%-*}-$((file_size - 1))";;
+ esac
+
+ if [ "$file_date" -lt "$cachedate" ] 2>&-; then
+ printf '%s: %s\r\n' \
+ Status '304 Not Modified' \
+ Last-Modified "$http_date"
+ printf '\r\n'
+
+ elif [ -z "$range" ]; then
+ printf '%s: %s\r\n' \
+ Status "200 OK" \
+ Accept-Ranges bytes \
+ Last-Modified "$http_date" \
+ Content-Type $(file_type "$file") \
+ Content-Length $file_size
+ printf '\r\n'
+
+ [ "$REQUEST_METHOD" != HEAD ] && cat "$file"
+
+ elif [ "${range%-*}" -le "${range#*-}" ]; then
+ printf '%s: %s\r\n' \
+ Status "206 Partial Content" \
+ Accept-Ranges bytes \
+ Last-Modified "$http_date" \
+ Content-Type $(file_type "$file") \
+ Content-Range "bytes ${range}/${file_size}" \
+ Content-Length "$((${range#*-} - ${range%-*} + 1))"
+ printf '\r\n'
+
+ [ "$REQUEST_METHOD" != HEAD ] \
+ && tail -c+$((${range%-*} + 1)) "$file" \
+ | head -c "$((${range#*-} - ${range%-*} + 1))"
+
+ elif [ "${range%-*}" -gt "${range#*-}" ]; then
+ printf '%s: %s\r\n' \
+ Status "216 Range Not Satisfiable" \
+ Content-Range \*/${file_size}
+ printf '\r\n'
+ fi
+}