The http Package
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.
http::config
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.
http::geturl
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:
Table 17-1. Options to the http::geturl command.| -blocksize num | Block size when copying to a channel. | | -channel fileID | The fileID is an open file or socket. The URL data is copied to this channel instead of saving it in memory. | | -command callback | Calls callback when the transaction completes. The token from http::geturl is passed to callback. | | -handler command | Called from the event handler to read data from the URL. | | -headers list | The list specifies a set of headers that are included in the HTTP request. The list alternates between header keys and values. | | -progress command | Calls command after each block is copied to a channel. It gets called with three parameters:
command token totalsize currentsize | | -query codedstring | Issues a POST request with the codedstring form data. | | -timeout msec | Aborts the request after msec milliseconds have elapsed. | | -validate bool | If bool is true, a HEAD request is made. |
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:
Table 17-2. Elements of the http::geturl state array.| 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:
Table 17-3. The http support procedures.| 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:
Example 17-12 Downloading files with http::geturl.
#!/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
http::formatQuery
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
http::reset
You can cancel an outstanding transaction with http::reset:
http::reset $token
This is done automatically when you setup a -timeout with http::config.
http::cleanup
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.
|