⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http.tcl

📁 一款用来进行网络模拟的软件
💻 TCL
📖 第 1 页 / 共 2 页
字号:
    } 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)"	foreach {key value} $state(-headers) {	    set value [string map [list \n "" \r ""] $value]	    set key [string trim $key]	    if {$key eq "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	# their 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 {$state(status) eq "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 {$state(status) eq "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 dataproc 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 arrayproc 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 callproc 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 {$state(state) eq "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 errorproc 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 callbacksproc 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 socketproc http::Eof {token} {    variable $token    upvar 0 $token state    if {$state(state) eq "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:#	TODOproc http::formatQuery {args} {    set result ""    set sep ""    foreach i $args {	append result $sep [mapReply $i]	if {$sep eq "="} {	    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 stringproc http::mapReply {string} {    variable http    variable formMap    # The spec says: "non-alphanumeric characters are replaced by '%HH'". Use    # a pre-computed map and [string map] to do the conversion (much faster    # than [regsub]/[subst]). [Bug 1020491]    if {$http(-urlencoding) ne ""} {	set string [encoding convertto $http(-urlencoding) $string]	return [string map $formMap $string]    }    set converted [string map $formMap $string]    if {[string match "*\[\u0100-\uffff\]*" $converted]} {	regexp {[\u0100-\uffff]} $converted badChar	# Return this error message for maximum compatability... :^/	return -code error \	    "can't read \"formMap($badChar)\": no such element in array"    }    return $converted}# http::ProxyRequired --#	Default proxy filter.## Arguments:#	host	The destination host## Results:#       The current proxy settingsproc 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)]    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -