rp_handler

one of the documented procedures in this installation of the ACS
Usage:
rp_handler   conn   ignore
What it does:
The request handler, which responds to absolutely every HTTP request made to the server.
Defined in: /web/philip/packages/acs-core/request-processor-procs.tcl

Source code:


    set errno [catch {
	#####
	#
	# Initialize the environment: unset the ad_conn array, and populate it with
	# a few things.
	#
	#####

	global ad_conn
	if { [info exists ad_conn] } {
	    unset ad_conn
	}
	set ad_conn(request) [nsv_incr ad_security request]
	set ad_conn(sec_validated) ""
	set ad_conn(browser_id) ""
	set ad_conn(session_id) ""
	set ad_conn(user_id) 0
	set ad_conn(token) ""
	set ad_conn(last_issue) ""
	set ad_conn(deferred_dml) ""
	set ad_conn(start_clicks) [clock clicks]

	rp_debug "Serving request: [ns_conn url]"

	set url [ns_conn url]
	set urlv [rp_url_component_list $url]

	# Here we'd play with $urlv, stripping any scoping/subcommunity information
	# from the beginning of the URL and setting the appropriate ad_conn fields.
	# For now, since we don't support scoping here, we don't do anything to
	# $urlv.

	# The URL, sans scoping information, goes in ad_conn(url).
	set ad_conn(url) "/[join $urlv "/"]"
	set ad_conn(urlv) $urlv

	#####
	#
	# See if any libraries have changed. This may look expensive, but all it
	# does is check an NSV.
	#
	#####

	rp_debug "Checking for changed libraries"
	apm_load_any_changed_libraries

	#####
	#
	# Log stuff for developer support.
	#
	#####

	rp_debug "Performing developer support logging"
	ad_call_proc_if_exists ds_collect_connection_info
	
	# Skip a few steps for requests to system directories (like SYSTEM) - don't
	# check the Host header, and don't check any cookies.

	if { ![nsv_exists rp_system_url_sections [lindex $urlv 0]] } {
	    #####
	    #
	    # Check the Host header (if provided). If it doesn't look like [ns_conn location]
	    # (a combination of the Hostname and Port specified under the nssock module in
	    # the server.ini file), issue a redirect.
	    #
	    #####

	    if { [ad_parameter ForceHostP "" 1] } {
		rp_debug "Checking the host header"
		set host_header [ns_set iget [ns_conn headers] "Host"]

		set virtual_mappings [ad_parameter_all_values_as_list Host "virtual-host-mapping"]
		foreach mapping $virtual_mappings {
		    set virtualhostname [lindex [split $mapping "|"] 0]
		    set virtualhosttarget [lindex [split $mapping "|"] 1]
		    if { [string first $virtualhostname $host_header] != -1 } {
			# one of the virtual hosts has been asked for
			# we'll redirect only if there is no URL, e.g., just bostonhelicoptertours.com
			if { [ns_conn url] == "" || [ns_conn url] == "/" } {
			    ns_returnredirect $virtualhosttarget
			    return "filter_return"			
			}
		    }
		}
		# first let's check to see if it is one of our virtual hosts
		
		regexp {^([^:]*)} $host_header "" host_without_port
		regexp {^https?://([^:]+)} [ns_conn location] "" desired_host_without_port
		if { ![empty_string_p $host_header] &&  ![string equal $host_without_port $desired_host_without_port] } {
		    rp_debug "Host header is set to \"$host_header\"; forcing to \"[ns_conn location]\""
		    set query [ns_conn query]
		    if { $query != "" } {
			set query "?$query"
			if { [ns_getform] != "" } {
			    set query "$query&[export_entire_form_as_url_vars]"
			}
		    } elseif { [ns_set size [ns_getform]] != 0 } { 
			set query "?[export_entire_form_as_url_vars]"
		    }
		    ad_returnredirect "[ns_conn location][ns_conn url]$query"
		    return "filter_return"
		}
	    }

	    #####
	    #
	    # Read in and/or generate security cookies.
	    #
	    #####

	    rp_debug "Handling security"

	    # Read in the security cookies.
	    sec_read_security_info

	    # Use sec_log to log the cookies (for debugging's sake).
	    sec_log "ad_browser_id=<<[ad_get_cookie "ad_browser_id"]>>; ad_session_id=<<[ad_get_cookie "ad_session_id"]>>"

	    if { [empty_string_p $ad_conn(browser_id)] } {
		# Assign a browser_id
		set db [ns_db gethandle]
                # Fails under read-only -jsc
                set ad_conn(browser_id) [database_to_tcl_string $db "select sec_id_seq.nextval from dual"]
		sec_log "Assigned browser ID $ad_conn(browser_id)"
		ad_set_cookie -expires never "ad_browser_id" $ad_conn(browser_id)
	    }

	    if { [empty_string_p $ad_conn(session_id)] ||  $ad_conn(last_issue) > [ns_time] + [sec_session_timeout] ||  $ad_conn(last_issue) + [sec_session_timeout] < [ns_time] } {
		# No session or user ID yet (or last_issue is way in the future, or session is
		# expired).

		if { ![info exists db] } {
		    # Allocate a database handle if one hasn't been allocated yet.
		    set db [ns_db gethandle]
		}

		if { [empty_string_p $ad_conn(last_issue)] } {
		    set ad_conn(last_issue) ""
		}
		sec_log "Bad session: session ID was \"$ad_conn(session_id)\"; last_issue was \"$ad_conn(last_issue)\"; ns_time is [ns_time]; timeout is [sec_session_timeout]"
		
		ad_assign_session_id $db
	    } else {
		# The session already exists and is valid.

		if { $ad_conn(last_issue) + [sec_session_cookie_reissue] < [ns_time] } {
		    # It's been a while... reissue the cookie and update sec_sessions.
		    ad_defer_dml "
		    update sec_sessions
		    set last_hit = [ns_time]
		    where session_id = $ad_conn(session_id)
		    "

		    # This should probably be changed to util_memoize_seed.
		    util_memoize_flush "sec_get_session_info $ad_conn(session_id)"
		    sec_generate_session_id_cookie
		}
	    }

	    if { [info exists db] } {
		# Free any database handle we may have allocated.
		ns_db releasehandle $db
	    }
	}
	
	#####
	#
	# Invoke applicable preauth filters.
	#   
	#####

	rp_debug "Calling preauth filters"
	
	# filters based on ad_conn(url)
	if { [rp_call_filters $conn preauth] == "filter_return" } {
	    rp_debug "Filter returned filter_return"
	    return "filter_return"
	}    

	#####
	#
	# Invoke ns_requestauthorize to run any authorization module, such as nsperm.
	# Patch by Brian Mottershead, 2005-11-17
	#
	#####

	set method [ns_conn method]
	set authuser [ns_conn authuser]
	set authpassword [ns_conn authpassword]
	set ip [peeraddr]

	switch [ns_requestauthorize $method $url $authuser $authpassword $ip] {
	    "OK"  { 
		# do nothing
	    }
	    "FORBIDDEN" { 
		ns_returnforbidden
		return "filter_return"
	    }
	    "UNAUTHORIZED" { 
		ns_returnunauthorized
		return "filter_return"
	    }
            default -
	    "ERROR" { 
		ad_return_error "Authorization problem"  "An error occurred while authorizing the request"
		return "filter_return"
	    }
	}

	#####
	#
	# Invoke applicable postauth filters.
	#
	#####

	rp_debug "Calling postauth filters"

	if { [rp_call_filters $conn postauth] == "filter_return" } {
	    return "filter_return"
	}

	#####
	#
	# Invoke a registered procedure, if we find one.
	#
	#####

	rp_debug "Looping through registered procedures"

	# Loop through the array of registered procs, dispatching if we find a match.
	foreach proc_info [nsv_get rp_registered_procs [ns_conn method]] {
	    set proc_path [lindex $proc_info 1]
	    set proc_noinherit [lindex $proc_info 5]
	    if { [string match $proc_path $ad_conn(url)] ||  $proc_noinherit == "f" && [string match "$proc_path/*" $ad_conn(url)] } {
		# Found a match. Execute the handler procedure.

		if { [catch {
		    set proc [lindex $proc_info 2]
		    set args [lindex $proc_info 3]

		    if { [llength [info procs $proc]] == 0 } {
			# [info procs $proc] returns nothing when the procedure has been
			# registered by C code (e.g., ns_returnredirect). Assume that neither
			# "conn" nor "why" is present in this case.
			eval $proc $args
		    } else {
			# Need to eval different things depending on whether the proc
			# has the $conn element.
			if { [llength [info args $proc]] - [llength $args] == 2 } {
			    # Procedure has conn argument.
			    eval $proc [list $conn] "dontuseme"
			} elseif { [llength [info args $proc]] - [llength $args] == 1 } {
			    # Procedure has conn argument.
			    eval $proc [list $conn] $args
			} else {
			    eval $proc $args
			}
		    }
		}] } {
		    # We got an error! Eventually write out a fancy error message; for now,
		    # return a server error.

		    global errorInfo
		    ns_log "Notice" "Error in registered procedure $proc: $errorInfo"
		    ad_return_error "Error in filter" "The filter routine <tt>$proc</tt> has failed."
		}

		return "filter_return"
	    }
	}

	#####
	#
	# Invoke the abstract URL system.
	#
	#####

	rp_debug "Calling rp_abstract_url_server"

	rp_abstract_url_server

	return "filter_return"
    } error]

    # If it's an "OK" or a "return" exception, just propagate it
    if { $errno == 0 || $errno == 2 } {
	return $error
    }

    # Bombed! Dump a stack trace.
    global errorInfo
    ns_log "Error" "Error executing request processor: $errorInfo"
    ad_return_error "Error in request processor" "An error occurred in the request processor.
    Please try later.  If the problem persists, send a message to philg-webmaster@photo.net"
    return "filter_return"


philg@mit.edu