nik wants a QUERY_STRING parser, so give him one, for food ☺
[shellsnippets/shellsnippets.git] / mksh / annex.cgi
1 #!/bin/mksh
2 # $MirOS: src/share/misc/licence.template,v 1.28 2008/11/14 15:33:44 tg Rel $
3 #-
4 # Copyright © 2012
5 #       Thorsten Glaser <tg@mirbsd.org>
6 #
7 # Provided that these terms and disclaimer and all copyright notices
8 # are retained or reproduced in an accompanying document, permission
9 # is granted to deal in this work without restriction, including un‐
10 # limited rights to use, publicly perform, distribute, sell, modify,
11 # merge, give away, or sublicence.
12 #
13 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
14 # the utmost extent permitted by applicable law, neither express nor
15 # implied; without malicious intent or gross negligence. In no event
16 # may a licensor, author or contributor be held liable for indirect,
17 # direct, other damage, loss, or other issues arising in any way out
18 # of dealing in the work, even if advised of the possibility of such
19 # damage or existence of a defect, except proven that it results out
20 # of said person’s immediate fault when using the work as intended.
21
22 export LC_ALL=C.UTF-8
23 unset LANGUAGE
24
25 [[ $1 = -s ]] || if [[ $REQUEST_METHOD = GET && $HTTPS = on && \
26     -n $REMOTE_USER && $REMOTE_USER = "$AUTHENTICATE_UID" ]]; then
27         [[ $PATH_INFO = /* ]] && \
28             exec sudo -u "$REMOTE_USER" "$(realpath "$0")" -s "$PATH_INFO" \
29             "$QUERY_STRING"
30         print Status: 301 Redirect
31         print Location: $SCRIPT_NAME/
32         print
33         print Please add the trailing slash after the .cgi
34         exit 1
35 else
36         print Content-type: text/plain\; charset=UTF-8
37         print
38         print Error in request arguments.
39         exit 1
40 fi
41
42 me=$(realpath "$0")
43 cd $(dirname "$(dirname "$me")")
44 basedir=$(realpath .)
45 shift
46 pi=$1
47 QUERY_STRING=$2
48
49 function qsdecode {
50         local _x=$1
51
52         _x=${_x//\\/\\\\}
53         print -- "${_x//[%]/\\x}"
54 }
55
56 function qsparse {
57         local _saveIFS _q _s _k _v
58
59         # no 'key=value' at all: make q be everything
60         if [[ $QUERY_STRING != *=* ]]; then
61                 qs_q=$(qsdecode "$QUERY_STRING")
62                 qskeys=(q)
63                 return
64         fi
65
66         _saveIFS=$IFS
67         IFS=';&'
68         set -A _q -- $QUERY_STRING
69         IFS=$_saveIFS
70
71         set -A qskeys
72         for _s in "${_q[@]}"; do
73                 # skip not 'key=value' parts
74                 [[ $_s = *=* ]] || continue
75
76                 _k=$(qsdecode "${_s%%=*}")
77                 _v=$(qsdecode "${_s#*=}")
78
79                 # limit keys to alphanumeric and underscore
80                 # as they must fit as part of an mksh variable
81                 [[ $_k = +([0-9A-Za-z_]) ]] || continue
82
83                 # eval is evil, but… as long as we don’t have
84                 # associative arrays in mksh… this works
85                 eval qs_$_k=\$_v
86                 qskeys+=("$_k")
87         done
88 }
89
90 function in_array {
91         nameref _arr=$1
92         local _val=$2 _x
93
94         for _x in "${_arr[@]}"; do
95                 [[ $_x = "$_val" ]] && return 0
96         done
97         return 1
98 }
99
100 qsparse
101
102 pi=${pi##*(/)}
103 pi=${pi%%*(/)}
104
105 function e403 {
106         print Status: 403 Forbidden
107         print Content-type: text/plain\; charset=UTF-8
108         print
109         print Du kumms hier nisch rein!
110         exit 1
111 }
112
113 if [[ -n $pi ]]; then
114         i=$(realpath "$pi")
115         [[ -n $i && $i = "$basedir"/* ]] || e403
116 fi
117
118 [[ -e ${pi:-.} && -r ${pi:-.} ]] || e403
119
120 [[ -n $pi ]] && if [[ ! -d $pi ]]; then
121         if in_array qskeys type; then
122                 ct=$qs_type
123         else
124                 ct=$(file -biL "$pi")
125         fi
126         print -r Content-type: "$ct"
127         print
128         cat "$pi"
129         exit 0
130 fi
131
132 [[ -n $pi ]] && cd "$pi"
133 set -A dirs
134 set -A files
135 for i in *; do
136         [[ -e $i && -r $i ]] || continue
137         if [[ -d $i ]]; then
138                 dirs+=("$i")
139         else
140                 files+=("$i")
141         fi
142 done
143
144 function h {
145         typeset x="$*"
146
147         x=${x//'&'/"&amp;"}
148         x=${x//'<'/"&lt;"}
149         x=${x//'>'/"&gt;"}
150
151         print -r -- "$x"
152 }
153
154 cat <<EOF
155 Content-type: text/html; charset=UTF-8
156
157 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
158  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
159 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head>
160  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
161  <title>$pi/ – Index for nik’s Annex</title>
162 </head><body>
163 <h1>Index of $pi/ in nik’s Annex</h1>
164 EOF
165
166 if (( !${#dirs[*]} && !${#files[*]} )); then
167         print '<p>No content found.</p>'
168 else
169         print '<table width="100%" border="0">'
170         for i in "${dirs[@]}"; do
171                 print "<tr><td align=\"right\" style=\"width:20;\">[DIR]</td><td><a href=\"$(h "$i")/\">$(h "$i")/</a></td></tr>"
172         done
173         for i in "${files[@]}"; do
174                 sz=$(stat -Lc '%s' "$i")
175                 if (( ${#sz} < 10 )); then
176                         if (( sz >= 1048576 )); then
177                                 if (( sz > 210000000 )); then
178                                         sz=$(( (sz + 524288) / 1048576)) MiB
179                                 else
180                                         (( sz = (sz * 10 + 524288) / 1048576 ))
181                                         x=${sz%?}
182                                         sz=$x.${sz#$x} MiB
183                                 fi
184                         elif (( sz >= 1024 )); then
185                                 sz=$(( (sz * 100 + 512) / 1024))
186                                 x=${sz%??}
187                                 sz=$x.${sz#$x} KiB
188                         fi
189                 else
190                         sz=$(bc -q <<<$'scale=2\n'"$sz/1073741824") GiB
191                 fi
192                 print "<tr><td align=\"right\" style=\"width:20;\">$sz</td><td><a href=\"$(h "$i")\">$(h "$i")</a> (<a href=\"$(h "$i")?type=application/octet-stream\">download</a>)</td></tr>"
193         done
194         print '</table>'
195 fi
196
197 print '</body></html>'
198 exit 0