]> Sergey Matveev's repositories - zws.git/commitdiff
Initial commit master
authorSergey Matveev <stargrave@stargrave.org>
Thu, 7 Mar 2024 09:00:07 +0000 (12:00 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 9 Mar 2024 10:26:23 +0000 (13:26 +0300)
zws [new file with mode: 0755]

diff --git a/zws b/zws
new file mode 100755 (executable)
index 0000000..456169d
--- /dev/null
+++ b/zws
@@ -0,0 +1,79 @@
+#!/usr/bin/env zsh
+# zws -- Z Shell-based Web server
+# Copyright (C) 2024 Sergey Matveev <stargrave@stargrave.org>
+# Serves static files, directory listings and MIME types
+# Usage: tcpserver -DHR -l 0 ::0 80 ./zws
+
+setopt ERR_EXIT PIPE_FAIL
+
+while read l ; do
+    local cols=(${=l})
+    [[ ${#cols} -ge 2 ]] || break
+    [[ $cols && ${cols[1]} = GET ]] || continue
+    REQPATH=${cols[2]}
+done
+
+doreply() {
+    local ct=$1
+    [[ -n $ct ]]
+    local code=${2:-200 OK}
+    print "HTTP/1.1 $code\r"
+    print "Server: zws/0.1.0\r"
+    print "Connection: close\r"
+    print "Cache-Control: no-cache\r"
+    print "Content-Type: $ct\r"
+    print "\r"
+}
+
+notfound() {
+    doreply text/plain "404 NOT FOUND"
+    exit 0
+}
+
+REQPATH=(${(s/?/)REQPATH})
+REQQUERY=${REQPATH[2]}
+REQPATH=${REQPATH[1]}
+[[ $REQPATH =~ "/\.\./" ]] && notfound
+
+REQPATH=${REQPATH#/}
+if [[ (-z $REQPATH) || ($REQPATH =~ "/$") ]] ; then
+    [[ (-n $REQPATH) && (! -d $REQPATH) ]] && notfound || :
+    doreply text/html
+    cat <<EOF
+<!DOCTYPE html>
+<html><head>
+    <title>$REQPATH</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head><body>
+<table border=1>
+<tr><th>&nbsp;</th><th>name</th><th>mtime</th><th>size</th></tr>
+EOF
+    [[ -z $REQPATH ]] || cd $REQPATH
+    ctr=0
+    zmodload -F zsh/stat b:zstat
+    zmodload -F zsh/datetime b:strftime
+    for i (*(onN)) {
+        zstat -A mtimeSec +mtime $i
+        strftime -s mtime "%Y-%m-%d %H:%M:%S" $mtimeSec
+        zstat -A size +size $i
+        [[ ! -d $i ]] || i="$i/"
+        print "<tr><td>$ctr</td><td><a href=\"$i\">$i</a></td>"
+        print "<td>$mtime</td><td>$size</td></tr>"
+        ctr=$(( $ctr + 1 ))
+    }
+    print "</table></body></html>"
+    exit 0
+fi
+
+[[ -r $REQPATH ]] || notfound
+
+ct=application/octet-stream
+case $REQPATH:e in
+txt) ct=text/plain ;;
+html) ct=text/html ;;
+esac
+
+doreply $ct
+_cat=cat
+[[ $REQQUERY =~ "tai64nlocal=1" ]] && _cat=tai64nlocal
+$_cat < $REQPATH