 316d4c4e57
			
		
	
	
		316d4c4e57
		
	
	
	
	
		
			
			- New generic http_redirect function, and two shortcuts for 303: post_redirect and 301: perm_redirect - Allow get_lib_file to take a default value, and change where master_template is set. - Fix bugs in auth code and properly trim ^M from post data. - Other cosmetic/minor improvements.
		
			
				
	
	
		
			290 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			290 lines
		
	
	
	
		
			6.9 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| ##############################################
 | |
| # 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 {
 | |
| #
 | |
| #}
 |