ref: 3e632e8d708e5038a318f9f4525cb96916b7359b
dir: /bin/cgilib.rc/
############################################## # Useful CGI functions NEW_LINE=' ' fn dprint { echo $* >[1=2] } fn dprintvars { { for(v in $*) { echo -n $v^'#'^$#$v^'=' $$v '; ' }; echo } >[1=2] } fn escape_html { sed 's/&/\&/g; s/</\</g; s/>/\>/g' $* } fn http_redirect { echo 'Status: '^$2^' Location: '^$1^' ' exit } fn perm_redirect { http_redirect $1 '301 Moved Permanantly' } fn post_redirect { http_redirect $1 '303 See Other' } fn static_file { echo 'Content-Type: '`{select_mime $1} echo cat $1 exit } # Note: should check if content type is application/x-www-form-urlencoded? fn load_post_args { if(~ $REQUEST_METHOD POST && ~ $#post_args 0) { ifs='& ' for(pair in `{cat}) { ifs='=' { pair=`{echo -n $pair} } n='post_arg_'^`{echo $pair(1)|tr -cd 'a-zA-Z0-9_'} post_args=( $post_args $n ) ifs=() { $n=`{echo -n $pair(2)|urldecode|tr -d ' '} } } pair=() } if not status='No POST or post args already loaded' } # Status is () if at least one arg is found. DEPRECATED: access vars directly. fn get_post_args { load_post_args _status='No post arg matches' for(n in $*) { v=post_arg_$n if(! ~ $#$v 0) { $n=$$v _status=() } } status=$_status } # This seems slightly improve performance, but might depend on httpd buffering behavior. fn awk_buffer { awk '{ buf = buf $0"\n" if(length(buf) > 1400) { printf "%s", buf buf = "" } } END { printf "%s", buf }' } fn urldecode { awk ' BEGIN { hextab ["0"] = 0; hextab ["8"] = 8; hextab ["1"] = 1; hextab ["9"] = 9; hextab ["2"] = 2; hextab ["A"] = hextab ["a"] = 10 hextab ["3"] = 3; hextab ["B"] = hextab ["b"] = 11; hextab ["4"] = 4; hextab ["C"] = hextab ["c"] = 12; hextab ["5"] = 5; hextab ["D"] = hextab ["d"] = 13; hextab ["6"] = 6; hextab ["E"] = hextab ["e"] = 14; hextab ["7"] = 7; hextab ["F"] = hextab ["f"] = 15; } { decoded = "" i = 1 len = length ($0) while ( i <= len ) { c = substr ($0, i, 1) if ( c == "%" ) { if ( i+2 <= len ) { c1 = substr ($0, i+1, 1) c2 = substr ($0, i+2, 1) if ( hextab [c1] == "" || hextab [c2] == "" ) { print "WARNING: invalid hex encoding: %" c1 c2 | "cat >&2" } else { code = 0 + hextab [c1] * 16 + hextab [c2] + 0 c = sprintf ("%c", code) i = i + 2 } } else { print "WARNING: invalid % encoding: " substr ($0, i, len - i) } } else if ( c == "+" ) { c = " " } decoded = decoded c ++i } printf "%s", decoded } ' } fn crop_text { ellipsis='...' if(~ $#* 2) ellipsis=$2 awk -v max'='^$"1^' ' -v 'ellipsis='$ellipsis ' { nc += 1 + length; if(nc > max) { print substr($0, 1, nc - max) ellipsis exit } print }' } # Cookies fn set_cookie { # TODO: should check input values more carefully name=$1 val=$2 extraHttpHeaders=( $extraHttpHeaders 'Set-cookie: '^$"name^'='^$"val^'; path=/;' ) } fn get_cookie { ifs=';' { co = `{ echo $HTTP_COOKIE } } # XXX: we might be adding a trailing new line? # The ' ?' is needed to deal with '; ' inter-cookie delimiter { for(c in $co) echo $c } | sed -n 's/^ ?'$1'=//p' } fn select_mime { m='text/plain' if(~ $1 *.css) m='text/css' if not if(~ $1 *.ico) m='image/x-icon' if not if(~ $1 *.png) m='image/png' if not if(~ $1 *.jpg *.jpeg) m='image/jpeg' if not if(~ $1 *.gif) m='image/gif' if not if(~ $1 *.pdf) m='application/pdf' echo $m } ############################################## # Generic rc programming helpers fn ll_add { _l=$1^_^$#$1 $_l=$*(2-) $1=( $$1 $_l ) } ############################################## # Werc-specific functions fn get_lib_file { if(! ~ $#sitedir 0 && test -f $sitedir/_werc/lib/$1) echo -n $sitedir/_werc/lib/$1 if not if(! ~ $#masterSite 0 && test -f $sitesdir/$masterSite/_werc/lib/$1) echo -n $sitesdir/$masterSite/_werc/lib/$1 if not if(test -f lib/$1) echo -n lib/$1 if not if(~ $#* 2) echo -n $2 if not status='Can''t find lib file: '$1 } fn template { awk -f bin/template.awk $* | rc $rcargs } # Auth code # Cookie format: WERC_USER: name:timestamp:hash(name.timestamp.password) # login_user can't be used from a template because it sets a cookie fn login_user { # Note: we set the cookie even if it is already there. if(get_user $*) set_cookie werc_user $"logged_user^':0:'^$"logged_password } # Check loggin status, if called with group arg we check membership too fn check_user { get_user _status=$status if(! ~ $#_status 0 ) _status=(Not logged in: $"_status) if not if(! ~ $#* 0 && ! grep -s '^'^$logged_user^'$' etc/groups/$*) { dprint NOT IN GROUP _status=(User $logged_user not in groups $*) } status=$_status } # If not logged in, try to get user login info from POST or from cookie fn get_user { if(~ $#logged_user 0) { if(~ $#* 2) { user_name=$1 user_password=$2 } if not if(~ $REQUEST_METHOD POST) get_post_args user_name user_password if(~ $#user_name 0) { ifs=':' { cu=`{get_cookie werc_user|tr -d $NEW_LINE} } if(! ~ $#cu 0) { user_name=$cu(1) user_password=$cu(3) } } auth_user $user_name $user_password } if not status=() } # Check if user_name and user_password represent a valid user account # If valid, 'log in' by setting logged_user fn auth_user { user_name=$1 user_password=$2 pfile='etc/users/'^$"user_name^'/password' if(~ $#user_name 0 || ~ $#user_password 0) status=('Auth: missing user name or pass: '^$"user_name^' / '^$"user_password) if not if(! test -f $pfile) status=('Auth: cant find '^$pfile) if not if(! ~ $user_password `{cat $pfile}) status=('Auth: Pass '$user_password' doesnt match '^`{cat $pfile}) if not { logged_user=$user_name logged_password=$user_password dprint Auth: success status=() } } fn user_controls { echo User: $"logged_user } # .md '(meta-)data' extract fn get_md_file_attr { sed -n '/^\* '$2': /p; /^\* '$2': /q; /^$/q' < $1 } #app_blog_methods = ( _post index.rss ) #fn app_blog__post { # echo #} # #app_blog___default { # if (~ $blog) # call_app blogpost #} # ## -- #app_blogpost_methods = ( comment _edit ) # #fn app_blogpost_comment { # call_app comments #} # ## -- #app_comments_methods = ( _post _edit ) # #fn app_comments___default { # #}