cgilib.rc (5870B)
1 # Useful CGI stuff 2 3 fn dprint { echo $* >[1=2] } 4 fn dprintv { { for(v in $*) { echo -n $v^'#'^$#$v^'=' $$v '; ' }; echo } >[1=2] } 5 fn echo {if(! ~ $1 -n || ! ~ $2 '') /bin/echo $*} 6 fn escape_html { sed 's/&/\&/g; s/</\</g; s/>/\>/g' $* } 7 8 fn http_redirect { 9 if(~ $1 http://* https://*) 10 t=$1 11 if not if(~ $1 /*) 12 t=$"base_url^$1 13 if not 14 t=$"base_url^$"req_path^$1 15 exec /bin/echo 'Status: '^$2^' 16 Location: '^$t^' 17 18 ' 19 exit 20 } 21 fn perm_redirect { http_redirect $1 '301 Moved Permanantly' } 22 fn post_redirect { http_redirect $1 '303 See Other' } 23 24 25 # Note: should check if content type is application/x-www-form-urlencoded? 26 # Should compare with http://www.shelldorado.com/scripts/cmds/urlgetopt.txt 27 fn load_post_args { 28 if(~ $REQUEST_METHOD POST && ~ $#post_args 0) { 29 ifs='& 30 ' for(pair in `{cat}) { 31 ifs='=' { pair=`{echo -n $pair} } 32 n='post_arg_'^`{echo $pair(1)|nurldecode|tr -cd 'a-zA-Z0-9_'} 33 post_args=( $post_args $n ) 34 ifs=() { $n=`{echo -n $pair(2)|nurldecode|tr -d ''} } 35 } 36 pair=() 37 } 38 if not 39 status='No POST or post args already loaded' 40 } 41 # Status is () if at least one arg is found. DEPRECATED: access vars directly. 42 fn get_post_args { 43 load_post_args 44 _status='No post arg matches' 45 for(n in $*) { 46 v=post_arg_$n 47 if(! ~ $#$v 0) { 48 $n=$$v 49 _status=() 50 } 51 } 52 status=$_status 53 } 54 55 # This seems slightly improve performance, but might depend on httpd buffering behavior. 56 fn awk_buffer { 57 awk '{ 58 buf = buf $0"\n" 59 if(length(buf) > 1400) { 60 printf "%s", buf 61 buf = "" 62 } 63 } 64 END { printf "%s", buf }' 65 } 66 67 fn nurldecode { urlencode -d || url_decode} # GROSS 68 69 fn url_decode { 70 awk ' 71 BEGIN { 72 hextab ["0"] = 0; hextab ["8"] = 8; 73 hextab ["1"] = 1; hextab ["9"] = 9; 74 hextab ["2"] = 2; hextab ["A"] = hextab ["a"] = 10 75 hextab ["3"] = 3; hextab ["B"] = hextab ["b"] = 11; 76 hextab ["4"] = 4; hextab ["C"] = hextab ["c"] = 12; 77 hextab ["5"] = 5; hextab ["D"] = hextab ["d"] = 13; 78 hextab ["6"] = 6; hextab ["E"] = hextab ["e"] = 14; 79 hextab ["7"] = 7; hextab ["F"] = hextab ["f"] = 15; 80 } 81 { 82 decoded = "" 83 i = 1 84 len = length ($0) 85 while ( i <= len ) { 86 c = substr ($0, i, 1) 87 if ( c == "%" ) { 88 if ( i+2 <= len ) { 89 c1 = substr ($0, i+1, 1) 90 c2 = substr ($0, i+2, 1) 91 if ( hextab [c1] == "" || hextab [c2] == "" ) { 92 print "WARNING: invalid hex encoding: %" c1 c2 | "cat >&2" 93 } else { 94 code = 0 + hextab [c1] * 16 + hextab [c2] + 0 95 c = sprintf ("%c", code) 96 i = i + 2 97 } 98 } else { 99 print "WARNING: invalid % encoding: " substr ($0, i, len - i) 100 } 101 } else if ( c == "+" ) { 102 c = " " 103 } 104 decoded = decoded c 105 ++i 106 } 107 printf "%s", decoded 108 } 109 ' 110 } 111 112 fn nurlencode { urlencode || url_encode } # GROSS 113 114 fn url_encode { 115 awk ' 116 BEGIN { 117 # We assume an awk implementation that is just plain dumb. 118 # We will convert an character to its ASCII value with the 119 # table ord[], and produce two-digit hexadecimal output 120 # without the printf("%02X") feature. 121 122 EOL = "%0A" # "end of line" string (encoded) 123 split ("1 2 3 4 5 6 7 8 9 A B C D E F", hextab, " ") 124 hextab [0] = 0 125 for ( i=1; i<=255; ++i ) ord [ sprintf ("%c", i) "" ] = i + 0 126 if ("'^$"EncodeEOL^'" == "yes") EncodeEOL = 1; else EncodeEOL = 0 127 } 128 { 129 encoded = "" 130 for ( i=1; i<=length ($0); ++i ) { 131 c = substr ($0, i, 1) 132 if ( c ~ /[a-zA-Z0-9.-]/ ) { 133 encoded = encoded c # safe character 134 } else if ( c == " " ) { 135 encoded = encoded "+" # special handling 136 } else { 137 # unsafe character, encode it as a two-digit hex-number 138 lo = ord [c] % 16 139 hi = int (ord [c] / 16); 140 encoded = encoded "%" hextab [hi] hextab [lo] 141 } 142 } 143 if ( EncodeEOL ) { 144 printf ("%s", encoded EOL) 145 } else { 146 print encoded 147 } 148 } 149 END { 150 #if ( EncodeEOL ) print "" 151 } 152 ' $* 153 } 154 155 # Cookies 156 fn set_cookie { 157 # TODO: should check input values more carefully 158 name=$1 159 val=$2 160 extraHttpHeaders=( $extraHttpHeaders 'Set-cookie: '^$"name^'='^$"val^'; path=/;' ) 161 } 162 fn get_cookie { 163 ifs=';' { co=`{echo $HTTP_COOKIE} } 164 165 # XXX: we might be adding a trailing new line? 166 # The ' ?' is needed to deal with '; ' inter-cookie delimiter 167 { for(c in $co) echo $c } | sed -n 's/^ ?'$1'=//p' 168 } 169 170 171 fn static_file { 172 echo -n 'Content-Type: ' 173 select_mime $1 174 echo 175 exec cat $1 176 } 177 178 fn select_mime { 179 m='text/plain' 180 if(~ $1 *.css) 181 m='text/css' 182 if not if(~ $1 *.ico) 183 m='image/x-icon' 184 if not if(~ $1 *.png) 185 m='image/png' 186 if not if(~ $1 *.jpg *.jpeg) 187 m='image/jpeg' 188 if not if(~ $1 *.gif) 189 m='image/gif' 190 if not if(~ $1 *.pdf) 191 m='application/pdf' 192 echo $m 193 } 194 195 ############################################## 196 # Generic rc programming helpers 197 198 # Manage nested lists 199 fn ll_add { 200 _l=$1^_^$#$1 201 $_l=$*(2-) 202 $1=( $$1 $_l ) 203 } 204 # Add to the head: dangerous if you shrink list by hand! 205 fn ll_addh { 206 _l=$1^_^$#$1 207 $_l=$*(2-) 208 $1=( $_l $$1 ) 209 } 210 211 212 NEW_LINE=' 213 ' 214 215 # crop_text [max_lenght [ellipsis]] 216 # TODO: Option to crop only at word-delimiters. 217 fn crop_text { 218 m=512 219 e='...' 220 if(! ~ $#1 0) 221 m=$1 222 if(! ~ $#2 0) 223 e=$2 224 225 awk -v 'max='^$"m -v 'ellipsis='$e ' 226 { 227 nc += 1 + length; 228 if(nc > max) { 229 print substr($0, 1, nc - max) " " ellipsis 230 exit 231 } 232 print 233 }' 234 } 235 236