1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
::clay::define ::httpd::content.cgi {
superclass ::httpd::content.proxy
method FileName {} {
set uri [string trimleft [my request get REQUEST_PATH] /]
set path [my clay get path]
set prefix [my clay get prefix]
set fname [string range $uri [string length $prefix] end]
if {[file exists [file join $path $fname]]} {
return [file join $path $fname]
}
if {[file exists [file join $path $fname.fossil]]} {
return [file join $path $fname.fossil]
}
if {[file exists [file join $path $fname.fos]]} {
return [file join $path $fname.fos]
}
if {[file extension $fname] in {.exe .cgi .tcl .pl .py .php}} {
return $fname
}
return {}
}
method proxy_channel {} {
###
# When delivering static content, allow web caches to save
###
set local_file [my FileName]
if {$local_file eq {} || ![file exist $local_file]} {
my log httpNotFound [my request get REQUEST_PATH]
my error 404 {Not Found}
tailcall my DoOutput
}
if {[file isdirectory $local_file]} {
###
# Produce an index page... or error
###
tailcall my DirectoryListing $local_file
}
set verbatim {
CONTENT_LENGTH CONTENT_TYPE QUERY_STRING REMOTE_USER AUTH_TYPE
REQUEST_METHOD REMOTE_ADDR REMOTE_HOST REQUEST_URI REQUEST_PATH
REQUEST_VERSION DOCUMENT_ROOT QUERY_STRING REQUEST_RAW
GATEWAY_INTERFACE SERVER_PORT SERVER_HTTPS_PORT
SERVER_NAME SERVER_SOFTWARE SERVER_PROTOCOL
}
foreach item $verbatim {
set ::env($item) {}
}
foreach item [array names ::env HTTP_*] {
set ::env($item) {}
}
set ::env(SCRIPT_NAME) [my request get REQUEST_PATH]
set ::env(SERVER_PROTOCOL) HTTP/1.0
set ::env(HOME) $::env(DOCUMENT_ROOT)
foreach {f v} [my request dump] {
set ::env($f) $v
}
set arglist $::env(QUERY_STRING)
set pwd [pwd]
cd [file dirname $local_file]
set script_file $local_file
if {[file extension $local_file] in {.fossil .fos}} {
if {![file exists $local_file.cgi]} {
set fout [open $local_file.cgi w]
chan puts $fout "#!/usr/bin/fossil"
chan puts $fout "repository: $local_file"
close $fout
}
set script_file $local_file.cgi
set EXE [my Cgi_Executable fossil]
} else {
set EXE [my Cgi_Executable $local_file]
}
set ::env(PATH_TRANSLATED) $script_file
set pipe [my CgiExec $EXE $script_file $arglist]
cd $pwd
return $pipe
}
method ProxyRequest {chana chanb} {
chan event $chanb writable {}
my log ProxyRequest {}
set length [my request get CONTENT_LENGTH]
if {$length} {
chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096
chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096
###
# Send any POST/PUT/etc content
###
my ChannelCopy $chana $chanb -size $length
} else {
chan flush $chanb
}
my clay refcount_incr
chan event $chanb readable [info coroutine]
yield
}
method ProxyReply {chana chanb args} {
my log ProxyReply [list args $args]
chan event $chana readable {}
set replyhead [my HttpHeaders $chana]
set replydat [my MimeParse $replyhead]
if {![dict exists $replydat Content-Length]} {
set length 0
} else {
set length [dict get $replydat Content-Length]
}
###
# Convert the Status: header from the CGI process to
# a standard service reply line from a web server, but
# otherwise spit out the rest of the headers verbatim
###
set replybuffer "HTTP/1.0 [dict get $replydat Status]\n"
append replybuffer $replyhead
chan configure $chanb -translation {auto crlf} -blocking 0 -buffering full -buffersize 4096
chan puts $chanb $replybuffer
###
# Output the body. With no -size flag, channel will copy until EOF
###
chan configure $chana -translation binary -blocking 0 -buffering full -buffersize 4096
chan configure $chanb -translation binary -blocking 0 -buffering full -buffersize 4096
my ChannelCopy $chana $chanb -chunk 4096
my clay refcount_decr
}
###
# For most CGI applications a directory list is vorboten
###
method DirectoryListing {local_file} {
my error 403 {Not Allowed}
tailcall my DoOutput
}
}
|