From 6be4c0330141b6c630f32eda9f8889924cb65b2e40640edd8d80857d96324ba7 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Thu, 7 Mar 2024 12:00:07 +0300 Subject: [PATCH 1/1] Initial commit --- zws | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100755 zws diff --git a/zws b/zws new file mode 100755 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 +# 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 < + + $REQPATH + + + + +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 "" + print "" + ctr=$(( $ctr + 1 )) + } + print "
 namemtimesize
$ctr$i$mtime$size
" + 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 -- 2.44.0