2 # zws -- Z Shell-based Web server
3 # Copyright (C) 2024 Sergey Matveev <stargrave@stargrave.org>
4 # Serves static files, directory listings and MIME types
5 # Usage: tcpserver -DHR -l 0 ::0 80 ./zws
7 setopt ERR_EXIT PIPE_FAIL
11 [[ ${#cols} -ge 2 ]] || break
12 [[ $cols && ${cols[1]} = GET ]] || continue
19 local code=${2:-200 OK}
20 print "HTTP/1.1 $code\r"
21 print "Server: zws/0.1.0\r"
22 print "Connection: close\r"
23 print "Cache-Control: no-cache\r"
24 print "Content-Type: $ct\r"
29 doreply text/plain "404 NOT FOUND"
33 REQPATH=(${(s/?/)REQPATH})
34 REQQUERY=${REQPATH[2]}
36 [[ $REQPATH =~ "/\.\./" ]] && notfound
39 if [[ (-z $REQPATH) || ($REQPATH =~ "/$") ]] ; then
40 [[ (-n $REQPATH) && (! -d $REQPATH) ]] && notfound || :
45 <title>$REQPATH</title>
46 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
49 <tr><th> </th><th>name</th><th>mtime</th><th>size</th></tr>
51 [[ -z $REQPATH ]] || cd $REQPATH
53 zmodload -F zsh/stat b:zstat
54 zmodload -F zsh/datetime b:strftime
56 zstat -A mtimeSec +mtime $i
57 strftime -s mtime "%Y-%m-%d %H:%M:%S" $mtimeSec
58 zstat -A size +size $i
59 [[ ! -d $i ]] || i="$i/"
60 print "<tr><td>$ctr</td><td><a href=\"$i\">$i</a></td>"
61 print "<td>$mtime</td><td>$size</td></tr>"
64 print "</table></body></html>"
68 [[ -r $REQPATH ]] || notfound
70 ct=application/octet-stream
78 [[ $REQQUERY =~ "tai64nlocal=1" ]] && _cat=tai64nlocal