X-Git-Url: https://git.plutz.net/?p=cgilite;a=blobdiff_plain;f=cgilite.sh;h=2193e29ff90069b181db9475c439c89f34e5f529;hp=7f828ddd6c8e2234c7cb3e2625505b5796e8eb77;hb=5038774f89b33ecd03e407898e9d57d38245b5bb;hpb=dcab9893c3e08b2ad0d0e9246b8ceefc3d40b9f8 diff --git a/cgilite.sh b/cgilite.sh index 7f828dd..2193e29 100755 --- a/cgilite.sh +++ b/cgilite.sh @@ -25,10 +25,35 @@ # set -o posix # ksh, not portable setopt -o OCTAL_ZEROES 2>&- +# Integrated webserver request timeout +cgilite_timeout=2 + +# General environment variables +# $_EXEC - directory containing application itself +# $_DATA - direcotry where application data may be stored +# $_BASE - optional prefix for http path, e.g. "/myapp" +# +# Programmers should take care to use those variables throughout the +# application. +# Variables may be set via CLI argument, in environment, or left as default. + +for cgilite_arg in "$@"; do case $cgilite_arg in + --exec=*) _EXEC="${cgilite_arg#*=}";; + --data=*) _DATA="${cgilite_arg#*=}";; + --base=*) _BASE="${cgilite_arg#*=}";; +esac; done +unset cgilite_arg + +_EXEC="${_EXEC:-${0%/*}}" +_DATA="${_DATA:-.}" +_EXEC="${_EXEC%/}" _DATA="${_DATA%/}" _BASE="${_BASE%/}" + +export _EXEC _DATA _BASE + +# Carriage Return and Line Break characters for convenience CR=" " BR=' ' -cgilite_timeout=2 PATH(){ local str seg out @@ -64,10 +89,11 @@ HEX_DECODE(){ "$pfx"[0-9a-fA-F][0-9a-fA-F]*) in="${in#${pfx}}";; \\*) in="${in#?}"; out="${out}\\\\"; continue;; %*) in="${in#?}"; out="${out}%%"; continue;; - *) out="${out}${in%"${in#?}"}"; in="${in#?}"; continue;; + *) att="${in%%"${pfx}"*}"; att="${att%%%*}"; att="${att%%\\*}" + out="${out}${att}"; in="${in#"${att}"}"; continue;; esac; - # Hex escaes for printf (e.g. \x41) are not portable + # Hex escapes for printf (e.g. \x41) are not portable # The portable way for Hex output is transforming Hex to Octal # (e.g. \x41 = \101) case $in in @@ -118,6 +144,8 @@ if [ -z "$REQUEST_METHOD" ]; then (sleep $cgilite_timeout && kill $$) & cgilite_watchdog=$! while read REQUEST_METHOD REQUEST_URI SERVER_PROTOCOL; do + unset PATH_INFO QUERY_STRING cgilite_headers CONTENT_LENGTH CONTENT_TYPE + [ "${SERVER_PROTOCOL#HTTP/1.[01]${CR}}" ] && break kill $cgilite_watchdog @@ -126,7 +154,7 @@ if [ -z "$REQUEST_METHOD" ]; then [ "${REQUEST_URI}" = "${REQUEST_URI#*\?}" ] \ && QUERY_STRING='' \ || QUERY_STRING="${REQUEST_URI#*\?}" - cgilite_headers=''; while read -r hl; do + while read -r hl; do hl="${hl%${CR}}"; [ "$hl" ] || break case $hl in 'Content-Length: '*) CONTENT_LENGTH="${hl#*: }";; @@ -136,7 +164,7 @@ if [ -z "$REQUEST_METHOD" ]; then done export REMOTE_ADDR SERVER_NAME SERVER_PORT REQUEST_METHOD REQUEST_URI SERVER_PROTOCOL \ - PATH_INFO QUERY_STRING CONTENT_TYPE CONTENT_LENGTH + PATH_INFO QUERY_STRING CONTENT_TYPE CONTENT_LENGTH cgilite_headers # Try to serve multiple requests, provided that script serves a # Content-Length header. @@ -172,9 +200,13 @@ if [ "${REQUEST_METHOD}" = POST -a "${CONTENT_LENGTH:-0}" -gt 0 -a \ cgilite_post="$(head -c "$CONTENT_LENGTH")" fi +PATH_INFO="$(PATH "/${PATH_INFO#${_BASE}}")" + debug(){ [ $# -gt 0 ] && printf '%s\n' "$@" >&2 || tee -a /dev/stderr; } [ "${DEBUG+x}" ] && env >&2 +# general helper functions, see GET, POST, and REF below + cgilite_count(){ printf %s "&$1" \ | grep -oE '&'"$2"'=[^&]*' \ @@ -200,6 +232,17 @@ cgilite_keys(){ | sort -u } +# Read arguments from GET, POST, or the query string of the referrer (REF). +# Example: +# GET varname n +# +# where n is number for the Nth occurence of a variable and defaults to 1 +# +# *_COUNT varname +# -> returns number of ocurences +# *_KEYS +# -> returns list of available varnames + GET(){ cgilite_value "${QUERY_STRING}" "$@"; } GET_COUNT(){ cgilite_count "${QUERY_STRING}" $1; } GET_KEYS(){ cgilite_keys "${QUERY_STRING}"; } @@ -228,6 +271,7 @@ HEADER(){ } COOKIE(){ + # Read value of cookie HEX_DECODE % "$( HEADER Cookie \ | grep -oE '(^|; ?)'"$1"'=[^;]*' \ @@ -240,21 +284,18 @@ HTML(){ # Also escape [, ], and \n for use in html-sh local str out [ $# -eq 0 ] && str="$(cat)" || str="$*" - while [ "$str" ]; do - case $str in - \&*) out="${out}&";; - \<*) out="${out}<";; - \>*) out="${out}>";; - \"*) out="${out}"";; - \'*) out="${out}'";; - \[*) out="${out}[";; - \]*) out="${out}]";; - "${CR}"*) out="${out} ";; - "${BR}"*) out="${out} ";; - *) out="${out}${str%"${str#?}"}";; - esac - str="${str#?}" - done + while [ "$str" ]; do case $str in + \&*) out="${out}&"; str="${str#?}";; + \<*) out="${out}<"; str="${str#?}";; + \>*) out="${out}>"; str="${str#?}";; + \"*) out="${out}""; str="${str#?}";; + \'*) out="${out}'"; str="${str#?}";; + \[*) out="${out}["; str="${str#?}";; + \]*) out="${out}]"; str="${str#?}";; + "${CR}"*) out="${out} "; str="${str#?}";; + "${BR}"*) out="${out} "; str="${str#?}";; + *) out="${out}${str%%[]&<>\"\'${CR}${BR}[]*}"; str="${str#"${str%%[]&<>\"\'${CR}${BR}[]*}"}";; + esac; done printf %s "$out" } @@ -262,24 +303,21 @@ URL(){ # Escape pathes, so they can be used in link tags and HTTP Headers local str out [ $# -eq 0 ] && str="$(cat)" || str="$*" - while [ "$str" ]; do - case $str in - \&*) out="${out}%26";; - \"*) out="${out}%22";; - \'*) out="${out}%27";; - \?*) out="${out}%3F";; - \#*) out="${out}%23";; - \[*) out="${out}%5B";; - \]*) out="${out}%5D";; - \ *) out="${out}%20";; - " "*) out="${out}%09";; - "${CR}"*) out="${out}%0D";; - "${BR}"*) out="${out}%0A";; - %*) out="${out}%25";; - *) out="${out}${str%"${str#?}"}";; - esac - str="${str#?}" - done + while [ "$str" ]; do case $str in + \&*) out="${out}%26"; str="${str#?}";; + \"*) out="${out}%22"; str="${str#?}";; + \'*) out="${out}%27"; str="${str#?}";; + \?*) out="${out}%3F"; str="${str#?}";; + \#*) out="${out}%23"; str="${str#?}";; + \[*) out="${out}%5B"; str="${str#?}";; + \]*) out="${out}%5D"; str="${str#?}";; + \ *) out="${out}%20"; str="${str#?}";; + " "*) out="${out}%09"; str="${str#?}";; + "${CR}"*) out="${out}%0D"; str="${str#?}";; + "${BR}"*) out="${out}%0A"; str="${str#?}";; + %*) out="${out}%25"; str="${str#?}";; + *) out="${out}${str%%[]&\"\'\?# ${CR}${BR}%[]*}"; str="${str#"${str%%[]&\"\'\?# ${CR}${BR}%[]*}"}";; + esac; done printf %s "$out" } @@ -302,6 +340,7 @@ SET_COOKIE(){ } REDIRECT(){ + # Trigger redirct and terminate script printf '%s: %s\r\n' \ Status "303 See Other" \ Content-Length 0 \