]> git.plutz.net Git - serve0/commitdiff
Merge commit '6a2f150eed622d61263b7137ffa0ef46764f5345'
authorPaul Hänsch <paul@plutz.net>
Wed, 3 Jun 2020 17:52:42 +0000 (19:52 +0200)
committerPaul Hänsch <paul@plutz.net>
Wed, 3 Jun 2020 17:52:42 +0000 (19:52 +0200)
1  2 
cgilite/cgilite.sh

diff --combined cgilite/cgilite.sh
index 333334c460f5cae9bc763f0079584a41132f70c5,86ad28073018c9a2626877e74426c0b2d4a95914..86ad28073018c9a2626877e74426c0b2d4a95914
@@@ -1,6 -1,6 +1,6 @@@
  #!/bin/sh
  
- # Copyright 2017 - 2018 Paul Hänsch
+ # Copyright 2017 - 2020 Paul Hänsch
  #
  # This is CGIlite.
  # A collection of posix shell functions for writing CGI scripts.
@@@ -27,15 -27,19 +27,19 @@@ BR=
  '
  cgilite_timeout=2
  
- HEADER(){
-   # Read value of header line. Use this instead of
-   # referencing HTTP_* environment variables.
-   if [ -n "${cgilite_headers+x}" ]; then
-     printf %s "$cgilite_headers" \
-     | sed -En 's;^'"${1}"': ([^\r]+)\r?$;\1;i; tX; d; :X;p;q;'
-   else
-     eval "printf %s \"\$HTTP_$(printf %s "${1}" |tr a-z A-Z |tr -c A-Z _)\""
-   fi
+ PATH(){ 
+   local str seg out
+   [ $# -eq 0 ] && str="$(cat)" || str="$*"
+   while [ "$str" ]; do
+     seg=${str%%/*}; str="${str#*/}"
+     case $seg in
+       ..) out="${out%/}"; out="${out%/*}/";;
+     .|'') out="${out%/}/";;
+        *) out="${out%/}/${seg}";;
+     esac;
+     [ "$seg" = "$str" ] && break
+   done
+   [ "${str}" -a "${out}" ] && printf %s "$out" || printf %s/ "${out%/}"
  }
  
  HEX_DECODE='
@@@ -68,41 -72,59 +72,59 @@@ if [ -z "$REQUEST_METHOD" ]; the
  
    (sleep $cgilite_timeout && kill $$) & cgilite_watchdog=$!
    while read REQUEST_METHOD REQUEST_URI SERVER_PROTOCOL; do
+     [ "${SERVER_PROTOCOL#HTTP/1.[01]${CR}}" ] && break
      kill $cgilite_watchdog
-     PATH_INFO="$(HEX_DECODE "${REQUEST_URI%\?*}")"
-     QUERY_STRING="${REQUEST_URI#*\?}"
-     cgilite_headers="$(while read -r hl; do [ "${hl%${CR}}" ] && printf '%s\n' "$hl" || break; done )"
  
-     HTTP_CONTENT_LENGTH="$(HEADER Content-Length |grep -xE '[0-9]+')"
+     SERVER_PROTOCOL="${SERVER_PROTOCOL%${CR}}"
+     PATH_INFO="$(HEX_DECODE "${REQUEST_URI%\?*}" |PATH)"
+     [ "${REQUEST_URI}" = "${REQUEST_URI#*\?}" ] \
+     && QUERY_STRING='' \
+     || QUERY_STRING="${REQUEST_URI#*\?}"
+     cgilite_headers=''; while read -r hl; do
+       hl="${hl%${CR}}"; [ "$hl" ] || break
+       case $hl in
+         'Content-Length: '*) CONTENT_LENGTH="${hl#*: }";;
+           'Content-Type: '*)   CONTENT_TYPE="${hl#*: }";;
+       esac
+       cgilite_headers="${cgilite_headers}${hl}${BR}"
+     done
  
      export REMOTE_ADDR SERVER_NAME SERVER_PORT REQUEST_METHOD REQUEST_URI SERVER_PROTOCOL \
-            PATH_INFO QUERY_STRING HTTP_CONTENT_LENGTH
+            PATH_INFO QUERY_STRING CONTENT_TYPE CONTENT_LENGTH
  
      # Try to serve multiple requests, provided that script serves a
      # Content-Length header.
      # Without Content-Length header, connection will terminate after
      # script.
  
-     cgilite_status='200 OK'; cgilite_response=''; cgilite_cl="Connection: close${CR}";
+     cgilite_status='200 OK'; cgilite_response=''; cgilite_cl="Connection: close${CR}${BR}";
      . "$0" | while read -r l; do case $l in
-       Status:*) cgilite_status="${l#Status: }";;
-       Content-Length:*) cgilite_cl="${l}";;
-       $CR) printf '%s %s\r\n%s\n%s\n\r\n' \
+       Status:*)
+         cgilite_status="${l#Status: }";;
+       Content-Length:*)
+         cgilite_cl=""
+         cgilite_response="${cgilite_response:+${cgilite_response}${BR}}${l}";;
+       Connection:*)
+         cgilite_cl="${l}${BR}";;
+       $CR) printf '%s %s\r\n%s%s\r\n' \
               'HTTP/1.1' "${cgilite_status%${CR}}" \
-              "$cgilite_response" "${cgilite_cl}"
+              "${cgilite_response}${cgilite_response:+${BR}}" "${cgilite_cl}"
             cat || kill $$
             [ "${cgilite_cl#Connection}" = "${cgilite_cl}" ]; exit;;
        *) cgilite_response="${cgilite_response:+${cgilite_response}${BR}}${l}";;
      esac; done || exit 0;
      (sleep $cgilite_timeout && kill $$) & cgilite_watchdog=$!
    done
+   kill $cgilite_watchdog
+   exit 0
  fi
  
- if [ "$REQUEST_METHOD" = POST -a "${HTTP_CONTENT_LENGTH:=${CONTENT_LENGTH:=0}}" -gt 0 ]; then
-   cgilite_post="$(head -c "$HTTP_CONTENT_LENGTH")"
+ if [ "${REQUEST_METHOD}" = POST -a "${CONTENT_LENGTH:-0}" -gt 0 -a \
+      "${CONTENT_TYPE}" = "application/x-www-form-urlencoded" ]; then
+   cgilite_post="$(head -c "$CONTENT_LENGTH")"
  fi
  
- [ -n "${DEBUG+x}" ] && env
+ [ "${DEBUG+x}" ] && env >&2
  
  cgilite_count(){
    printf %s "&$1" \
  cgilite_value(){
    local str="&$1" name="$2" cnt="${3:-1}"
    while [ $cnt -gt 0 ]; do
-     str=${str#*&${name}=}
+     [ "${str}" = "${str#*&${name}=}" ] && return 1
+     str="${str#*&${name}=}"
      cnt=$((cnt - 1))
    done
    printf -- "$(printf %s "${str%%&*}" |sed -E 's;\+; ;g;'"$HEX_DECODE")"
@@@ -140,6 -163,21 +163,21 @@@ REF(){ cgilite_value "${HTTP_REFERER#*\
  REF_COUNT(){ cgilite_count "${HTTP_REFERER#*\?}" $1; }
  REF_KEYS(){ cgilite_keys "${HTTP_REFERER#*\?}"; }
  
+ HEADER(){
+   # Read value of header line. Use this instead of
+   # referencing HTTP_* environment variables.
+   if [ -n "${cgilite_headers+x}" ]; then
+     local str="${BR}${cgilite_headers}"
+     [ "${str}" = "${str#*${BR}${1}: }" ] && return 1
+     str="${str#*${BR}${1}: }"
+     printf %s "${str%%${BR}*}"
+   else
+     local var="HTTP_$(printf %s "$1" |tr a-z- A-Z-)"
+     eval "[ \"\$$var\" ] && printf %s \"\$$var\" || return 1"
+     # eval "printf %s \"\$HTTP_$(printf %s "${1}" |tr a-z A-Z |tr -c A-Z _)\""
+   fi
+ }
  COOKIE(){
    HEX_DECODE "$(
      HEADER Cookie \
@@@ -180,19 -218,10 +218,10 @@@ URL()
    | sed 's;,;%;g; s;%2F;/;g;'
  }
  
- PATH(){
-   { [ $# -eq 0 ] && cat || printf %s "$*"; } \
-   | sed -E 's;^.*$;/&/;; s;/+;/;g;
-             :X;
-             s;^/\.\./;/;; s;/\./;/;g;
-             tX;
-             s;/[^/]+/\.\./;/;;
-             tX;
-             s;^(/.*)/$;\1;'
- }
  SET_COOKIE(){
+   # Param: session | +seconds | [date]
+   # Param: name=value
+   # Param: Path= | Domain= | Secure
    local expire cookie
    case "$1" in
      ''|0|session) expire='';;
    esac
    cookie="$2"
  
-   printf 'Set-Cookie: %s' "$cookie"
+   printf 'Set-Cookie: %s; HttpOnly; SameSite=Lax' "$cookie"
    [ -n "$expire" ] && printf '; Expires=%s' "${expire%+????}${expire:+GMT}"
    [ $# -ge 3 ] && shift 2 && printf '; %s' "$@"
    printf '\r\n'