watermark-pdf/app/cgibashopts

171 lines
4.7 KiB
Bash

#!/bin/bash
# Author: (c) Colas Nahaboo http://colas.nahaboo.net with a MIT License.
# See https://github.com/ColasNahaboo/cgibashopts
# Uses the CGI env variables REQUEST_METHOD CONTENT_TYPE QUERY_STRING
export CGIBASHOPTS_RELEASE=4.1.1
export CGIBASHOPTS_VERSION="${CGIBASHOPTS_RELEASE%%.*}"
cr=$'\r'
nl=$'\n'
export FORMS=
export FORMFILES=
export FORMQUERY=
# parse options
uploads=true
tmpfs=/tmp
OPTIONS='nd:'
OPTIND=1
while getopts "${OPTIONS}" _o;do
case "$_o" in
n) uploads=false;;
d) tmpfs="$OPTARG";;
*) echo "unknown option: $_o"; exit 1;;
esac
done
shift $((OPTIND-1))
if "$uploads"; then
export CGIBASHOPTS_DIR="$tmpfs/cgibashopts-files.$$"
CGIBASHOPTS_TMP="$CGIBASHOPTS_DIR.tmp"
cgibashopts_clean() {
[ -n "$CGIBASHOPTS_DIR" ] && [ -d "$CGIBASHOPTS_DIR" ] && rm -rf "$CGIBASHOPTS_DIR"
}
trap cgibashopts_clean 0
else
CGIBASHOPTS_TMP=/dev/null
fi
# emulates bashlib param function. -f operate on uploaded file paths
param () {
if [ "$1" = -f ]; then
shift
if [ $# -eq 0 ]; then echo "$FORMFILES"
elif [ $# -eq 1 ]; then eval echo "\$FORMFILE_$1"
else declare -x "FORMFILE_$1=$*"
fi
else
if [ $# -eq 0 ]; then echo "$FORMS"
elif [ $# -eq 1 ]; then eval echo "\$FORM_$1"
else declare -x "FORM_$1=$*"
fi
fi
}
# decodes the %XX url encoding in $1, same as urlencode -d but faster
# removes carriage returns to force unix newlines, converts + into space
urldecode() {
local v="${1//+/ }" d r=''
while [ -n "$v" ]; do
if [[ $v =~ ^([^%]*)%([0-9a-fA-F][0-9a-fA-F])(.*)$ ]]; then
eval d="\$'\x${BASH_REMATCH[2]}'"
[ "$d" = "$cr" ] && d=
r="$r${BASH_REMATCH[1]}$d"
v="${BASH_REMATCH[3]}"
else
r="$r$v"
break
fi
done
echo "$r"
}
# the reverse of urldecode above
urlencode() {
local length="${#1}" i c
for (( i = 0; i < length; i++ )); do
c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) echo -n "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
}
if [ "${REQUEST_METHOD:-}" = POST ]; then
if [[ ${CONTENT_TYPE:-} =~ ^multipart/form-data\;[[:space:]]*boundary=([^\;]+) ]]; then
sep="--${BASH_REMATCH[1]}"
OIFS="$IFS"; IFS=$'\r'
while read -r line; do
if [[ $line =~ ^Content-Disposition:\ *form-data\;\ *name=\"([^\"]+)\"(\;\ *filename=\"([^\"]+)\")? ]]; then
var="${BASH_REMATCH[1]}"
val="${BASH_REMATCH[3]}"
[[ $val =~ [%+] ]] && val=$(urldecode "$val")
type=
read -r line
while [ -n "$line" ]; do
if [[ $line =~ ^Content-Type:\ *text/plain ]]; then
type=txt
elif [[ $line =~ ^Content-Type: ]]; then # any other type
type=bin
fi
read -r line
done
if [ "$type" = bin ]; then # binary file upload
# binary-read stdin till next step. -u and q stops reading immediately
# When changed, update code copy in tests/filefield-runaway.test
sed -u -n -e "{:loop p; n;/^$sep/q; b loop}" >$CGIBASHOPTS_TMP
[ $CGIBASHOPTS_TMP != /dev/null ] && \
truncate -s -2 $CGIBASHOPTS_TMP # remove last \r\n
elif [ "$type" = txt ]; then # text file upload
lp=
while read -r line; do
[[ $line =~ ^"$sep" ]] && break
echo -n "$lp$line"
lp="$nl"
done >$CGIBASHOPTS_TMP
else # string, possibly multi-line
val=
while read -r line; do
[[ $line =~ ^"$sep" ]] && break
val="$val${val:+$nl}${line}"
done
fi
if [ -n "$type" ]; then
if [ $CGIBASHOPTS_TMP != /dev/null ]; then
if [ -n "$val" ]; then
# a file was uploaded, even empty
[ -n "$FORMFILES" ] || mkdir -p "$CGIBASHOPTS_DIR"
FORMFILES="$FORMFILES${FORMFILES:+ }$var"
declare -x "FORMFILE_$var=$CGIBASHOPTS_DIR/${var}"
mv $CGIBASHOPTS_TMP "$CGIBASHOPTS_DIR/${var}"
else
rm -f $CGIBASHOPTS_TMP
fi
fi
fi
FORMS="$FORMS${FORMS:+ }$var"
declare -x "FORM_$var=$val"
fi
done
s="${QUERY_STRING:-}"
IFS="$OIFS"
unset OIFS
else
stdin=$(cat) # indirection to avoid issues with terminating newlines
s="${stdin}&${QUERY_STRING:-}"
unset stdin
fi
else
s="${QUERY_STRING:-}"
fi
# regular (no file uploads) arguments processing
if [[ $s =~ = ]]; then # modern & (or ;) separated list of key=value
while [[ $s =~ ^([^=]*)=([^\&\;]*)[\;\&]*(.*)$ ]]; do
var="${BASH_REMATCH[1]//[^a-zA-Z_0-9]/}"
val="${BASH_REMATCH[2]}"
s="${BASH_REMATCH[3]}"
if [[ $var =~ ^[_[:alpha:]] ]]; then # ignore invalid vars
[[ $val =~ [%+] ]] && val=$(urldecode "$val")
FORMS="$FORMS${FORMS:+ }$var"
declare -x "FORM_$var=$val"
fi
done
else # legacy indexed search
FORMQUERY=$(urldecode "$s")
fi
# clean up our local variables
unset sep line var val type s lp