Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # http.tcl --
- #
- # Client-side HTTP for GET, POST, and HEAD commands.
- # These routines can be used in untrusted code that uses
- # the Safesock security policy. These procedures use a
- # callback interface to avoid using vwait, which is not
- # defined in the safe base.
- #
- # See the file "license.terms" for information on usage and
- # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- #
- # RCS: @(#) $Id: http.tcl,v 2.5.001 2004/09/08 13:36:10 perpleXa Exp $
- # Rough version history:
- # 1.0 Old http_get interface
- # 2.0 http:: namespace and http::geturl
- # 2.1 Added callbacks to handle arriving data, and timeouts
- # 2.2 Added ability to fetch into a channel
- # 2.3 Added SSL support, and ability to post from a channel
- # This version also cleans up error cases and eliminates the
- # "ioerror" status in favor of raising an error
- # 2.4 Added -binary option to http::geturl and charset element
- # to the state array.
- # 2.5 Added useridentification support and http::base64 (by perpleXa)
- package require Tcl 8.2
- # keep this in sync with pkgIndex.tcl
- # and with the install directories in Makefiles
- package provide http 2.5.001
- namespace eval http {
- variable http
- array set http {
- -accept */*
- -proxyhost {}
- -proxyport {}
- -proxyfilter http::ProxyRequired
- }
- set http(-useragent) {Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7) Gecko/20040803 Firefox/0.9.3}
- proc init {} {
- variable formMap
- variable alphanumeric a-zA-Z0-9
- for {set i 0} {$i <= 256} {incr i} {
- set c [format %c $i]
- if {![string match \[$alphanumeric\] $c]} {
- set formMap($c) %[format %.2x $i]
- }
- }
- # These are handled specially
- array set formMap { " " + \n %0d%0a }
- }
- init
- variable urlTypes
- array set urlTypes {
- http {80 ::socket}
- }
- variable encodings [string tolower [encoding names]]
- # This can be changed, but iso8859-1 is the RFC standard.
- variable defaultCharset "iso8859-1"
- namespace export geturl config reset wait formatQuery register unregister
- # Useful, but not exported: data size status code
- }
- # http::register --
- #
- # See documentaion for details.
- #
- # Arguments:
- # proto URL protocol prefix, e.g. https
- # port Default port for protocol
- # command Command to use to create socket
- # Results:
- # list of port and command that was registered.
- proc http::register {proto port command} {
- variable urlTypes
- set urlTypes($proto) [list $port $command]
- }
- # http::unregister --
- #
- # Unregisters URL protocol handler
- #
- # Arguments:
- # proto URL protocol prefix, e.g. https
- # Results:
- # list of port and command that was unregistered.
- proc http::unregister {proto} {
- variable urlTypes
- if {![info exists urlTypes($proto)]} {
- return -code error "unsupported url type \"$proto\""
- }
- set old $urlTypes($proto)
- unset urlTypes($proto)
- return $old
- }
- # http::config --
- #
- # See documentaion for details.
- #
- # Arguments:
- # args Options parsed by the procedure.
- # Results:
- # TODO
- proc http::config {args} {
- variable http
- set options [lsort [array names http -*]]
- set usage [join $options ", "]
- if {[llength $args] == 0} {
- set result {}
- foreach name $options {
- lappend result $name $http($name)
- }
- return $result
- }
- set options [string map {- ""} $options]
- set pat ^-([join $options |])$
- if {[llength $args] == 1} {
- set flag [lindex $args 0]
- if {[regexp -- $pat $flag]} {
- return $http($flag)
- } else {
- return -code error "Unknown option $flag, must be: $usage"
- }
- } else {
- foreach {flag value} $args {
- if {[regexp -- $pat $flag]} {
- set http($flag) $value
- } else {
- return -code error "Unknown option $flag, must be: $usage"
- }
- }
- }
- }
- # http::Finish --
- #
- # Clean up the socket and eval close time callbacks
- #
- # Arguments:
- # token Connection token.
- # errormsg (optional) If set, forces status to error.
- # skipCB (optional) If set, don't call the -command callback. This
- # is useful when geturl wants to throw an exception instead
- # of calling the callback. That way, the same error isn't
- # reported to two places.
- #
- # Side Effects:
- # Closes the socket
- proc http::Finish { token {errormsg ""} {skipCB 0}} {
- variable $token
- upvar 0 $token state
- global errorInfo errorCode
- if {[string length $errormsg] != 0} {
- set state(error) [list $errormsg $errorInfo $errorCode]
- set state(status) error
- }
- catch {close $state(sock)}
- catch {after cancel $state(after)}
- if {[info exists state(-command)] && !$skipCB} {
- if {[catch {eval $state(-command) {$token}} err]} {
- if {[string length $errormsg] == 0} {
- set state(error) [list $err $errorInfo $errorCode]
- set state(status) error
- }
- }
- if {[info exists state(-command)]} {
- # Command callback may already have unset our state
- unset state(-command)
- }
- }
- }
- # http::reset --
- #
- # See documentaion for details.
- #
- # Arguments:
- # token Connection token.
- # why Status info.
- #
- # Side Effects:
- # See Finish
- proc http::reset { token {why reset} } {
- variable $token
- upvar 0 $token state
- set state(status) $why
- catch {fileevent $state(sock) readable {}}
- catch {fileevent $state(sock) writable {}}
- Finish $token
- if {[info exists state(error)]} {
- set errorlist $state(error)
- unset state
- eval ::error $errorlist
- }
- }
- # http::base64
- #
- # Converts a base10 string to a base64 string
- #
- # Arguments:
- # string The base10 string to convert
- # Results:
- # Returns a base64 encoded string,
- # this string is needed for http user-identification.
- #
- proc http::base64 {arguments} {
- set base64_en "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 wrapchar "\n"
- set maxlen 60
- set result {}
- set state 0
- set length 0
- if {[llength $arguments] == 0} {
- error "wrong # args: should be \"[lindex [info level 0] 0] string\""
- }
- binary scan $arguments c* X
- foreach {x y z} $X {
- if {$maxlen && $length >= $maxlen} {
- append result $wrapchar
- set length 0
- }
- append result [lindex $base64_en [expr {($x >> 2) & 0x3F}]]
- if {$y != {}} {
- append result [lindex $base64_en [expr {(($x << 4) & 0x30) | (($y >> 4) & 0xF)}]]
- if {$z != {}} {
- append result [lindex $base64_en [expr {(($y << 2) & 0x3C) | (($z >> 6) & 0x3)}]]
- append result [lindex $base64_en [expr {($z & 0x3F)}]]
- } else {
- set state 2
- break
- }
- } else {
- set state 1
- break
- }
- incr length 4
- }
- if {$state == 1} {
- append result [lindex $base64_en [expr {(($x << 4) & 0x30)}]]==
- } elseif {$state == 2} {
- append result [lindex $base64_en [expr {(($y << 2) & 0x3C)}]]=
- }
- return $result
- }
- # http::geturl --
- #
- # Establishes a connection to a remote url via http.
- #
- # Arguments:
- # url The http URL to goget.
- # args Option value pairs. Valid options include:
- # -blocksize, -validate, -headers, -timeout
- # Results:
- # Returns a token for this connection.
- # This token is the name of an array that the caller should
- # unset to garbage collect the state.
- proc http::geturl { url args } {
- variable http
- variable urlTypes
- variable defaultCharset
- # Initialize the state variable, an array. We'll return the
- # name of this array as the token for the transaction.
- if {![info exists http(uid)]} {
- set http(uid) 0
- }
- set token [namespace current]::[incr http(uid)]
- variable $token
- upvar 0 $token state
- reset $token
- # Process command options.
- array set state {
- -binary false
- -blocksize 8192
- -queryblocksize 8192
- -validate 0
- -headers {}
- -timeout 0
- -type application/x-www-form-urlencoded
- -queryprogress {}
- state header
- meta {}
- coding {}
- currentsize 0
- totalsize 0
- querylength 0
- queryoffset 0
- type text/html
- body {}
- status ""
- http ""
- }
- # These flags have their types verified [Bug 811170]
- array set type {
- -binary boolean
- -blocksize integer
- -queryblocksize integer
- -validate boolean
- -timeout integer
- }
- set state(charset) $defaultCharset
- set options {-binary -blocksize -channel -command -handler -headers \
- -progress -query -queryblocksize -querychannel -queryprogress\
- -validate -timeout -type}
- set usage [join $options ", "]
- set options [string map {- ""} $options]
- set pat ^-([join $options |])$
- foreach {flag value} $args {
- if {[regexp $pat $flag]} {
- # Validate numbers
- if {[info exists type($flag)] && ![string is $type($flag) -strict $value]} {
- unset $token
- return -code error "Bad value for $flag ($value), must be $type($flag)"
- }
- set state($flag) $value
- } else {
- unset $token
- return -code error "Unknown option $flag, can be: $usage"
- }
- }
- # Make sure -query and -querychannel aren't both specified
- set isQueryChannel [info exists state(-querychannel)]
- set isQuery [info exists state(-query)]
- if {$isQuery && $isQueryChannel} {
- unset $token
- return -code error "Can't combine -query and -querychannel options!"
- }
- # Validate URL, determine the server host and port, and check proxy case
- # Recognize user:pass@host URLs also
- set exp {^(([^:]*)://)?(([^@]+?)@)?([^/:]+?)(:([0-9]+?))?(/.*)?$}
- if {![regexp -nocase $exp $url x prefix proto y user host z port srvurl]} {
- unset $token
- return -code error "Unsupported URL: $url"
- }
- if {[string length $proto] == 0} {
- set proto http
- set url ${proto}://$url
- }
- if {![info exists urlTypes($proto)]} {
- unset $token
- return -code error "Unsupported URL type \"$proto\""
- }
- set defport [lindex $urlTypes($proto) 0]
- set defcmd [lindex $urlTypes($proto) 1]
- if {[string length $port] == 0} {
- set port $defport
- }
- if {[string length $srvurl] == 0} {
- set srvurl /
- }
- if {[string length $proto] == 0} {
- set url http://$url
- }
- set state(url) $url
- if {![catch {$http(-proxyfilter) $host} proxy]} {
- set phost [lindex $proxy 0]
- set pport [lindex $proxy 1]
- }
- # If a timeout is specified we set up the after event
- # and arrange for an asynchronous socket connection.
- if {$state(-timeout) > 0} {
- set state(after) [after $state(-timeout) \
- [list http::reset $token timeout]]
- set async -async
- } else {
- set async ""
- }
- # If we are using the proxy, we must pass in the full URL that
- # includes the server name.
- if {[info exists phost] && [string length $phost]} {
- set srvurl $url
- set conStat [catch {eval $defcmd $async {$phost $pport}} s]
- } else {
- set conStat [catch {eval $defcmd $async {$host $port}} s]
- }
- if {$conStat} {
- # something went wrong while trying to establish the connection
- # Clean up after events and such, but DON'T call the command callback
- # (if available) because we're going to throw an exception from here
- # instead.
- Finish $token "" 1
- cleanup $token
- return -code error $s
- }
- set state(sock) $s
- # Wait for the connection to complete
- if {$state(-timeout) > 0} {
- fileevent $s writable [list http::Connect $token]
- http::wait $token
- if {[string equal $state(status) "error"]} {
- # something went wrong while trying to establish the connection
- # Clean up after events and such, but DON'T call the command
- # callback (if available) because we're going to throw an
- # exception from here instead.
- set err [lindex $state(error) 0]
- cleanup $token
- return -code error $err
- } elseif {![string equal $state(status) "connect"]} {
- # Likely to be connection timeout
- return $token
- }
- set state(status) ""
- }
- # Send data in cr-lf format, but accept any line terminators
- fconfigure $s -translation {auto crlf} -buffersize $state(-blocksize)
- # The following is disallowed in safe interpreters, but the socket
- # is already in non-blocking mode in that case.
- catch {fconfigure $s -blocking off}
- set how GET
- if {$isQuery} {
- set state(querylength) [string length $state(-query)]
- if {$state(querylength) > 0} {
- set how POST
- set contDone 0
- } else {
- # there's no query data
- unset state(-query)
- set isQuery 0
- }
- } elseif {$state(-validate)} {
- set how HEAD
- } elseif {$isQueryChannel} {
- set how POST
- # The query channel must be blocking for the async Write to
- # work properly.
- fconfigure $state(-querychannel) -blocking 1 -translation binary
- set contDone 0
- }
- if {[catch {
- puts $s "$how $srvurl HTTP/1.0"
- puts $s "Accept: $http(-accept)"
- if {$port == $defport} {
- # Don't add port in this case, to handle broken servers.
- # [Bug #504508]
- puts $s "Host: $host"
- } else {
- puts $s "Host: $host:$port"
- }
- puts $s "User-Agent: $http(-useragent)"
- if {[string length $user] >= 1} {
- set b64user [base64 $user]
- puts $s "Authorization: Basic $b64user"
- }
- foreach {key value} $state(-headers) {
- set value [string map [list \n "" \r ""] $value]
- set key [string trim $key]
- if {[string equal $key "Content-Length"]} {
- set contDone 1
- set state(querylength) $value
- }
- if {[string length $key]} {
- puts $s "$key: $value"
- }
- }
- if {$isQueryChannel && $state(querylength) == 0} {
- # Try to determine size of data in channel
- # If we cannot seek, the surrounding catch will trap us
- set start [tell $state(-querychannel)]
- seek $state(-querychannel) 0 end
- set state(querylength) [expr {[tell $state(-querychannel)] - $start}]
- seek $state(-querychannel) $start
- }
- # Flush the request header and set up the fileevent that will
- # either push the POST data or read the response.
- #
- # fileevent note:
- #
- # It is possible to have both the read and write fileevents active
- # at this point. The only scenario it seems to affect is a server
- # that closes the connection without reading the POST data.
- # (e.g., early versions TclHttpd in various error cases).
- # Depending on the platform, the client may or may not be able to
- # get the response from the server because of the error it will
- # get trying to write the post data. Having both fileevents active
- # changes the timing and the behavior, but no two platforms
- # (among Solaris, Linux, and NT) behave the same, and none
- # behave all that well in any case. Servers should always read thier
- # POST data if they expect the client to read their response.
- if {$isQuery || $isQueryChannel} {
- puts $s "Content-Type: $state(-type)"
- if {!$contDone} {
- puts $s "Content-Length: $state(querylength)"
- }
- puts $s ""
- fconfigure $s -translation {auto binary}
- fileevent $s writable [list http::Write $token]
- } else {
- puts $s ""
- flush $s
- fileevent $s readable [list http::Event $token]
- }
- if {! [info exists state(-command)]} {
- # geturl does EVERYTHING asynchronously, so if the user
- # calls it synchronously, we just do a wait here.
- wait $token
- if {[string equal $state(status) "error"]} {
- # Something went wrong, so throw the exception, and the
- # enclosing catch will do cleanup.
- return -code error [lindex $state(error) 0]
- }
- }
- } err]} {
- # The socket probably was never connected,
- # or the connection dropped later.
- # Clean up after events and such, but DON'T call the command callback
- # (if available) because we're going to throw an exception from here
- # instead.
- # if state(status) is error, it means someone's already called Finish
- # to do the above-described clean up.
- if {[string equal $state(status) "error"]} {
- Finish $token $err 1
- }
- cleanup $token
- return -code error $err
- }
- return $token
- }
- # Data access functions:
- # Data - the URL data
- # Status - the transaction status: ok, reset, eof, timeout
- # Code - the HTTP transaction code, e.g., 200
- # Size - the size of the URL data
- proc http::data {token} {
- variable $token
- upvar 0 $token state
- return $state(body)
- }
- proc http::status {token} {
- variable $token
- upvar 0 $token state
- return $state(status)
- }
- proc http::code {token} {
- variable $token
- upvar 0 $token state
- return $state(http)
- }
- proc http::ncode {token} {
- variable $token
- upvar 0 $token state
- if {[regexp {[0-9]{3}} $state(http) numeric_code]} {
- return $numeric_code
- } else {
- return $state(http)
- }
- }
- proc http::size {token} {
- variable $token
- upvar 0 $token state
- return $state(currentsize)
- }
- proc http::error {token} {
- variable $token
- upvar 0 $token state
- if {[info exists state(error)]} {
- return $state(error)
- }
- return ""
- }
- # http::cleanup
- #
- # Garbage collect the state associated with a transaction
- #
- # Arguments
- # token The token returned from http::geturl
- #
- # Side Effects
- # unsets the state array
- proc http::cleanup {token} {
- variable $token
- upvar 0 $token state
- if {[info exists state]} {
- unset state
- }
- }
- # http::Connect
- #
- # This callback is made when an asyncronous connection completes.
- #
- # Arguments
- # token The token returned from http::geturl
- #
- # Side Effects
- # Sets the status of the connection, which unblocks
- # the waiting geturl call
- proc http::Connect {token} {
- variable $token
- upvar 0 $token state
- global errorInfo errorCode
- if {[eof $state(sock)] || [string length [fconfigure $state(sock) -error]]} {
- Finish $token "connect failed [fconfigure $state(sock) -error]" 1
- } else {
- set state(status) connect
- fileevent $state(sock) writable {}
- }
- return
- }
- # http::Write
- #
- # Write POST query data to the socket
- #
- # Arguments
- # token The token for the connection
- #
- # Side Effects
- # Write the socket and handle callbacks.
- proc http::Write {token} {
- variable $token
- upvar 0 $token state
- set s $state(sock)
- # Output a block. Tcl will buffer this if the socket blocks
- set done 0
- if {[catch {
- # Catch I/O errors on dead sockets
- if {[info exists state(-query)]} {
- # Chop up large query strings so queryprogress callback
- # can give smooth feedback
- puts -nonewline $s \
- [string range $state(-query) $state(queryoffset) \
- [expr {$state(queryoffset) + $state(-queryblocksize) - 1}]]
- incr state(queryoffset) $state(-queryblocksize)
- if {$state(queryoffset) >= $state(querylength)} {
- set state(queryoffset) $state(querylength)
- set done 1
- }
- } else {
- # Copy blocks from the query channel
- set outStr [read $state(-querychannel) $state(-queryblocksize)]
- puts -nonewline $s $outStr
- incr state(queryoffset) [string length $outStr]
- if {[eof $state(-querychannel)]} {
- set done 1
- }
- }
- } err]} {
- # Do not call Finish here, but instead let the read half of
- # the socket process whatever server reply there is to get.
- set state(posterror) $err
- set done 1
- }
- if {$done} {
- catch {flush $s}
- fileevent $s writable {}
- fileevent $s readable [list http::Event $token]
- }
- # Callback to the client after we've completely handled everything
- if {[string length $state(-queryprogress)]} {
- eval $state(-queryprogress) [list $token $state(querylength) $state(queryoffset)]
- }
- }
- # http::Event
- #
- # Handle input on the socket
- #
- # Arguments
- # token The token returned from http::geturl
- #
- # Side Effects
- # Read the socket and handle callbacks.
- proc http::Event {token} {
- variable $token
- upvar 0 $token state
- set s $state(sock)
- if {[eof $s]} {
- Eof $token
- return
- }
- if {[string equal $state(state) "header"]} {
- if {[catch {gets $s line} n]} {
- Finish $token $n
- } elseif {$n == 0} {
- variable encodings
- set state(state) body
- if {$state(-binary) || ![string match -nocase text* $state(type)] || [string match *gzip* $state(coding)] || [string match *compress* $state(coding)]} {
- # Turn off conversions for non-text data
- fconfigure $s -translation binary
- if {[info exists state(-channel)]} {
- fconfigure $state(-channel) -translation binary
- }
- } else {
- # If we are getting text, set the incoming channel's
- # encoding correctly. iso8859-1 is the RFC default, but
- # this could be any IANA charset. However, we only know
- # how to convert what we have encodings for.
- set idx [lsearch -exact $encodings [string tolower $state(charset)]]
- if {$idx >= 0} {
- fconfigure $s -encoding [lindex $encodings $idx]
- }
- }
- if {[info exists state(-channel)] && ![info exists state(-handler)]} {
- # Initiate a sequence of background fcopies
- fileevent $s readable {}
- CopyStart $s $token
- }
- } elseif {$n > 0} {
- if {[regexp -nocase {^content-type:(.+)$} $line x type]} {
- set state(type) [string trim $type]
- # grab the optional charset information
- regexp -nocase {charset\s*=\s*(\S+)} $type x state(charset)
- }
- if {[regexp -nocase {^content-length:(.+)$} $line x length]} {
- set state(totalsize) [string trim $length]
- }
- if {[regexp -nocase {^content-encoding:(.+)$} $line x coding]} {
- set state(coding) [string trim $coding]
- }
- if {[regexp -nocase {^([^:]+):(.+)$} $line x key value]} {
- lappend state(meta) $key [string trim $value]
- } elseif {[string match HTTP* $line]} {
- set state(http) $line
- }
- }
- } else {
- if {[catch {
- if {[info exists state(-handler)]} {
- set n [eval $state(-handler) {$s $token}]
- } else {
- set block [read $s $state(-blocksize)]
- set n [string length $block]
- if {$n >= 0} {
- append state(body) $block
- }
- }
- if {$n >= 0} {
- incr state(currentsize) $n
- }
- } err]} {
- Finish $token $err
- } else {
- if {[info exists state(-progress)]} {
- eval $state(-progress) {$token $state(totalsize) $state(currentsize)}
- }
- }
- }
- }
- # http::CopyStart
- #
- # Error handling wrapper around fcopy
- #
- # Arguments
- # s The socket to copy from
- # token The token returned from http::geturl
- #
- # Side Effects
- # This closes the connection upon error
- proc http::CopyStart {s token} {
- variable $token
- upvar 0 $token state
- if {[catch {
- fcopy $s $state(-channel) -size $state(-blocksize) -command \
- [list http::CopyDone $token]
- } err]} {
- Finish $token $err
- }
- }
- # http::CopyDone
- #
- # fcopy completion callback
- #
- # Arguments
- # token The token returned from http::geturl
- # count The amount transfered
- #
- # Side Effects
- # Invokes callbacks
- proc http::CopyDone {token count {error {}}} {
- variable $token
- upvar 0 $token state
- set s $state(sock)
- incr state(currentsize) $count
- if {[info exists state(-progress)]} {
- eval $state(-progress) {$token $state(totalsize) $state(currentsize)}
- }
- # At this point the token may have been reset
- if {[string length $error]} {
- Finish $token $error
- } elseif {[catch {eof $s} iseof] || $iseof} {
- Eof $token
- } else {
- CopyStart $s $token
- }
- }
- # http::Eof
- #
- # Handle eof on the socket
- #
- # Arguments
- # token The token returned from http::geturl
- #
- # Side Effects
- # Clean up the socket
- proc http::Eof {token} {
- variable $token
- upvar 0 $token state
- if {[string equal $state(state) "header"]} {
- # Premature eof
- set state(status) eof
- } else {
- set state(status) ok
- }
- set state(state) eof
- Finish $token
- }
- # http::wait --
- #
- # See documentaion for details.
- #
- # Arguments:
- # token Connection token.
- #
- # Results:
- # The status after the wait.
- proc http::wait {token} {
- variable $token
- upvar 0 $token state
- if {![info exists state(status)] || [string length $state(status)] == 0} {
- # We must wait on the original variable name, not the upvar alias
- vwait $token\(status)
- }
- return $state(status)
- }
- # http::formatQuery --
- #
- # See documentaion for details.
- # Call http::formatQuery with an even number of arguments, where
- # the first is a name, the second is a value, the third is another
- # name, and so on.
- #
- # Arguments:
- # args A list of name-value pairs.
- #
- # Results:
- # TODO
- proc http::formatQuery {args} {
- set result ""
- set sep ""
- foreach i $args {
- append result $sep [mapReply $i]
- if {[string equal $sep "="]} {
- set sep &
- } else {
- set sep =
- }
- }
- return $result
- }
- # http::mapReply --
- #
- # Do x-www-urlencoded character mapping
- #
- # Arguments:
- # string The string the needs to be encoded
- #
- # Results:
- # The encoded string
- proc http::mapReply {string} {
- variable formMap
- variable alphanumeric
- # The spec says: "non-alphanumeric characters are replaced by '%HH'"
- # 1 leave alphanumerics characters alone
- # 2 Convert every other character to an array lookup
- # 3 Escape constructs that are "special" to the tcl parser
- # 4 "subst" the result, doing all the array substitutions
- regsub -all \[^$alphanumeric\] $string {$formMap(&)} string
- regsub -all {[][{})\\]\)} $string {\\&} string
- return [subst -nocommand $string]
- }
- # http::ProxyRequired --
- # Default proxy filter.
- #
- # Arguments:
- # host The destination host
- #
- # Results:
- # The current proxy settings
- proc http::ProxyRequired {host} {
- variable http
- if {[info exists http(-proxyhost)] && [string length $http(-proxyhost)]} {
- if {![info exists http(-proxyport)] || ![string length $http(-proxyport)]} {
- set http(-proxyport) 8080
- }
- return [list $http(-proxyhost) $http(-proxyport)]
- }
- }
Add Comment
Please, Sign In to add comment