The standard Tcl library includes an http package that is based on the code I wrote for this chapter. This section documents the package, which has a slightly different interface. The library version uses namespaces and combines the Http_Get, Http_Head, and Http_Post procedures into a single http::geturl procedure. The examples in this chapter are still interesting, but you should look at http.tcl in the Tcl library, which I also wrote. Definitely use the standard http package for your production code.
The http::config command is used to set the proxy information, time-outs, and the User-Agent and Accept headers that are generated in the HTTP request. You can specify the proxy host and port, or you can specify a Tcl command that is run to determine the proxy. With no arguments, http::config returns the current settings:
http::config => -accept */* -proxyfilter httpProxyRequired -proxyhost {}-proxyport {}-timeout unlimited -useragent {Tcl http client package 2.0}
If you specify just one option, its value is returned:
http::config -proxyfilter
=> httpProxyRequired
You can set one or more options:
http::config -proxyhost webcache.eng -proxyport 8080
The default proxy filter just returns the -proxyhost and -proxyport values if they are set. You can supply a smarter filter that picks a proxy based on the host in the URL. The proxy filter is called with the hostname and should return a list of two elements, the proxy host and port. If no proxy is required, return an empty list.
The -timeout value limits the time the transaction can take. Its value is unlimited for no timeout, or a milliseconds value. You can specify 500, for example, to have a half-second timeout.
The http::geturl procedure does a GET, POST, or HEAD transaction depending on its arguments. By default, http::geturl blocks until the request completes and it returns a token that represents the transaction. As described below, you use the token to get the results of the transaction. If you supply a -command callback option, then http::geturl returns immediately and invokes callback when the transaction completes. The callback is passed the token that represents the transaction. Table 17-1 lists the options to http::geturl:
For simple applications you can simply block on the transaction:
set token [http::geturl www.beedub.com/index.html]
=> http::1
The leading http:// in the URL is optional. The return value is a token that is also the name of a global array that contains state about the transaction. Names like http::1 are used instead of using the URL as the array name. You can use upvar to convert the return value from http::geturl to an array variable:
upvar #0 $token state
By default, the URL data is saved in state(body). The elements of the state array are described in Table 17-2:
body | The contents of the URL. |
currentsize | The current number of bytes transferred. |
error | An explanation of why the transaction was aborted. |
http | The HTTP reply status. |
meta | A list of the keys and values in the reply header. |
status | The current status: pending, ok, eof, or reset. |
totalsize | The expected size of the returned data. |
type | The content type of the returned data. |
url | The URL of the request. |
A handful of access functions are provided so that you can avoid using the state array directly. These are listed in Table 17-3:
http::data $token | Returns state(body). |
http::status $token | Returns state(status). |
http::error $token | Returns state(error). |
http::code $token | Returns state(http). |
http::wait $token | Blocks until the transaction completes. |
http::cleanup $token | Unsets the state array named by $token. |
You can take advantage of the asynchronous interface by specifying a command that is called when the transaction completes. The callback is passed the token returned from http::geturl so that it can access the transaction state:
http::geturl $url -command [list Url_Display $text $url] proc Url_Display {text url token} { upvar #0 $token state # Display the url in text }
You can have http::geturl copy the URL to a file or socket with the -channel option. This is useful for downloading large files or images. In this case, you can get a progress callback so that you can provide user feedback during the transaction. Example 17-12 shows a simple downloading script:
#!/usr/local/tclsh8.0 if {$argc < 2} { puts stderr "Usage: $argv0 url file" exit 1 } set url [lindex $argv 0] set file [lindex $argv 1] set out [open $file w] proc progress {token total current} { puts -nonewline "." } http::config -proxyhost webcache.eng -proxyport 8080 set token [http::geturl $url -progress progress -headers {Pragma no-cache}-channel $out] close $out # Print out the return header information puts "" upvar #0 $token state puts $state(http) foreach {key value}$state(meta) { puts "$key: $value" } exit 0 |
If you specify form data with the -query option, then http::geturl does a POST transaction. You need to encode the form data for safe transmission. The http::formatQuery procedure takes a list of keys and values and encodes them in x-www-url-encoded format. Pass this result as the query data:
http::formatQuery name "Brent Welch" title "Tcl Programmer"
=> name=Brent+Welch&title=Tcl+Programmer
You can cancel an outstanding transaction with http::reset:
http::reset $token
This is done automatically when you setup a -timeout with http::config.
When you are done with the data returned from http::geturl, use the http::cleanup procedure to unset the state variable used to store the data.
18.222.232.128