diff --git a/TODO b/TODO index 3a20320..6bb0215 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ * More unit tests - * Content-Range support * Reverse proxy mode * If-Modified-Since support * Content-Disposition diff --git a/shellweb b/shellweb index 0840a6e..7f2f691 100755 --- a/shellweb +++ b/shellweb @@ -5,6 +5,7 @@ set -e verbose=false auth_enabled=false proxy_mode=false +content_range=(false 0 0 0) nc=$(command -v nc.openbsd || command -v nc || { echo nc not found; exit 1; }) if [ `id -u` = 0 ]; then @@ -193,6 +194,9 @@ cgi() { # It's okay to call this routine even after senderr(), see $sent sendfile() { + if [[ ${content_range[0]} == 'true' ]]; then + range_handle_verify "$root/$1" + fi $sent && return 0 test -d "$1" && return exec 3<"$root/$1" || { senderr 500; return 0; } @@ -203,9 +207,15 @@ sendfile() { printf "Content-Type: %s\r\n" "$ct" printf "Content-Length: %u\r\n" "$sz" printf "Date: %s\r\n" "$(env LC_ALL=en_US.UTF-8 date)" - printf "\r\n" - cat <&3 - exec 3<&- + if [[ ${content_range[0]} == 'true' ]]; then + printf "Content-Range: bytes ${content_range[1]}-${content_range[2]}/${content_range[3]}\r\n" + printf "\r\n" + range_sendfile "$root/$1" + else + printf "\r\n" + cat <&3 + exec 3<&- + fi } html_escape() { @@ -337,7 +347,19 @@ proxy() { fi done | $nc ${proxy_spec%%:*} $proxy_port >&p } - + +range_handle_verify() { + content_range[3]=$(stat --printf="%s" "$1") + if [[ ${content_range[3]} -ne 0 && ${content_range[1]} -ge 0 && ${content_range[2]} -le ${content_range[3]} ]]; then + return 0 + else + senderr 400 + fi +} + +range_sendfile(){ + dd if="$1" ibs=1 skip=${content_range[1]} count=${content_range[2]} 2> /dev/null +} NC_SERVER=$nc if $verbose; then @@ -371,6 +393,11 @@ while true; do elif [[ $header == "connection:" && $v2 == $(printf "close\r") ]]; then keep_conn=false + + elif [[ $header == "range:" ]]; then + content_range[0]='true' + content_range[1]=$(echo "$v3" | awk -F '-' '{print $1}') + content_range[2]=$(echo "$v3" | awk -F '-' '{print $2}' | sed 's/[^0-9]*//g') elif [[ $header = $(printf "\r\n") && -z $v2 ]]; then # empty line (end of headers)