blob: 3778cbe1460bec8c047a60ac8dbf6af43b1ab9dc [file] [log] [blame]
#
# script.ws3 -- the commands of websh3 that are implemented as Tcl scripts
# nca-073-9
#
# Copyright (C) 1996-2000 by Netcetera AG.
# Copyright (C) 2001 by Apache Software Foundation.
# All rights reserved.
#
# See the file "license.terms" for information on usage and
# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# @(#) $Id$
#
#-----------------------------------------------------------------------------
# namespace init (make sure web:: exists)
#-----------------------------------------------------------------------------
namespace eval web {}
#-----------------------------------------------------------------------------
# web::putxfile
#-----------------------------------------------------------------------------
proc web::putxfile {file {channel ""} {vmsg ""}} {
if {[string length $vmsg]} {
upvar $vmsg msg
}
if {[string length $channel]} {
# file is actually the channel and channel is the file
if {[web::readfile $channel content msg]} {
return 1
}
return [catch {uplevel [list web::putx $file $content]} msg]
} else {
if {[web::readfile $file content msg]} {
return 1
}
return [catch {uplevel [list web::putx $content]} msg]
}
}
#-----------------------------------------------------------------------------
# web::readfile
#-----------------------------------------------------------------------------
proc web::readfile {name vtarget {vmsg ""}} {
upvar $vtarget target
if {[string length $vmsg]} {
upvar $vmsg msg
}
return [catch {
set fh [open $name r]
set target [read $fh]
close $fh
} msg]
}
#-----------------------------------------------------------------------------
# web_include
#-----------------------------------------------------------------------------
proc web::include {name {vmsg ""}} {
if {[string length $vmsg]} {
upvar $vmsg msg
}
if {![file exists $name]} {
set so "$name[info sharedlibextension]"
if {[file exists $so]} {
return [catch {uplevel [list load $so]} msg]
}
}
return [catch {uplevel [list source $name]} msg]
}
#-----------------------------------------------------------------------------
# web::match
# 1: string to be returned if $val exists in $list
# 2: list to be searched for $val
# 3: string to search
#-----------------------------------------------------------------------------
proc web::match {res list val} {
if {[lsearch -exact $list $val] >= 0} {
return $res
}
return ""
}
#-----------------------------------------------------------------------------
# web::list2uri
#-----------------------------------------------------------------------------
proc web::list2uri {list} {
if {[llength $list] % 2} {
error "list must have even number of elems"
}
set pairs {}
foreach {k v} $list {
lappend pairs [join [list [uriencode $k] [uriencode $v] ] = ]
}
return [join $pairs &]
}
#-----------------------------------------------------------------------------
# web::uri2list
#-----------------------------------------------------------------------------
proc web::uri2list {string} {
# special case: must return a list with an even # of elements
set res ""
foreach item [split $string &] {
set kv [split $item =]
if [llength $kv] {
lappend res [uridecode [lindex $kv 0]] [uridecode [lindex $kv 1]]
}
}
return $res
}
#-----------------------------------------------------------------------------
# mod_websh and CGI stuff
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# per request init and cleanup for mod_websh
namespace eval web::ap {}
proc web::ap::perReqInit {} {
}
proc web::ap::perReqCleanup {} {
# reset logging (except stuff from web::initializer)
web::loglevel delete -requests
web::logdest delete -requests
# reset request data
web::request -reset
# reset response channels
web::response -resetall
# reset url data
web::cmdurlcfg -reset
}
#-----------------------------------------------------------------------------
# setup environment for cgi mode
namespace eval web::cgi {}
proc web::cgi::copyenv {} {
set cgienv {
SERVER_SOFTWARE
SERVER_NAME
GATEWAY_INTERFACE
SERVER_PROTOCOL
SERVER_PORT
REQUEST_METHOD
PATH_INFO
PATH_TRANSLATED
SCRIPT_NAME
QUERY_STRING
REMOTE_HOST
REMOTE_ADDR
AUTH_TYPE
REMOTE_USER
REMOTE_IDENT
CONTENT_TYPE
CONTENT_LENGTH
HTTPS
}
# set request headers from environment
foreach e [array names ::env] {
if {![string match HTTP_* $e]} {
if {[lsearch -exact $cgienv $e] == -1} continue
}
web::request -set $e $::env($e)
}
# check for Authorization
if {![info exists ::env(REMOTE_USER)] && [info exists ::env(AUTH_BASIC)]} {
# AUTH_BASIC contains the Authorization header
# sent by the browser (e.g. created using Apache >= 2.0.51:
# SetEnvIf Authorization "^(Basic .+)$" AUTH_BASIC=$1
# check the quick reference for security considerations
if {[regexp "^Basic (.*)" $::env(AUTH_BASIC) dummy authstring]} {
# base64 decode it
set i 0
foreach char {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
a b c d e f g h i j k l m n o p q r s t u v w x y z \
0 1 2 3 4 5 6 7 8 9 + / =} {
set b64($char) $i
incr i
}
set decoded {}
set group 0; set j 18; set eq 0
foreach char [split $authstring {}] {
# ignore all characters not in base64 character set
# should be only newlines, but who knows ;-)
if {![info exists b64($char)]} {continue}
if {[string compare $char "="]} {
set bits $b64($char)
set group [expr {$group | ($bits << $j)}]
} else {
incr eq
}
if {[incr j -6] < 0} {
scan [format %06x $group] %2x%2x%2x a b c
switch $eq {
0 {append decoded [format %c%c%c $a $b $c]}
1 {append decoded [format %c%c $a $b]}
2 {append decoded [format %c $a]}
}
set group 0; set j 18; set eq 0
}
}
# set request params
web::request -set AUTH_USER [lindex [split $decoded :] 0]
web::request -set AUTH_PW [join [lrange [split $decoded :] 1 end] :]
}
}
if {[info exists ::env(AUTH_BASIC)]} {
unset ::env(AUTH_BASIC)
}
}