Version 6 of autoproxy

Updated 2002-12-11 14:58:53

Supporting proxies with the http package is tedious and error prone and has to be done for each application in turn. I've done a few of these and finally decided this can be done by an external package.

Here is the first draft. I'll add in the handling for proxy authentication soon.

To use this:

  package require http
  package require autoproxy
  autoproxy::init

 # autoproxy.tcl - Copyright (C) 2002 Pat Thoyts <[email protected]>
 #
 # On Unix an emerging standard for identifying the local HTTP proxy server
 # seems to be to use the environment variable http_proxy or ftp_proxy and
 # no_proxy to list those domains to be excluded from proxying.
 #
 # On Windows we can retrieve the Internet Settings values from the registry
 # to obtain pretty much the same information.
 #
 # With this information we can setup a suitable filter procedure for the 
 # Tcl http package and arrange for automatic use of the proxy.
 #
 # @(#)$Id: 2879,v 1.7 2002-12-12 09:01:09 jcw Exp $

 namespace eval autoproxy {
     variable proxy
     variable no_proxy {}

     array set proxy {host "" port 80}

     variable winregkey
     set winregkey [join {
         HKEY_CURRENT_USER
         Software Microsoft Windows
         CurrentVersion "Internet Settings"
     } \\]
 }

 proc autoproxy::init {} {
     package require uri
     global tcl_platform
     global env
     variable winregkey
     variable proxy
     variable no_proxy
     set httpproxy {}

     # Look for environment variables.
     if {[info exists env(http_proxy)]} {
         set httpproxy $env(http_proxy)
         set no_proxy $env(no_proxy)
     } else {
         puts "a"
         if {$tcl_platform(platform) == "windows"} {
             puts "b"
             package require registry 1.0

             if {[registry get $winregkey "ProxyEnable"]} {
                 set httpproxy [registry get $winregkey "ProxyServer"]
                 set no_proxy [registry get $winregkey "ProxyOverride"]
             }
         }
     }

     # If we found something ...
     if {$httpproxy != {}} {
         # The http_proxy is supposed to be a URL - lets make sure.
         if {![regexp {\w://.*} $httpproxy]} {
             set httpproxy "http://$httpproxy"
         }

         # decompose the string.
         array set proxy [uri::split $httpproxy]

         # turn the no_proxy value into a tcl list
         set no_proxy [string map {; " " , " "} $no_proxy]

         # setup the http package
         package require http
         http::config -proxyfilter [namespace origin filter]
     }
 }

 proc autoproxy::filter {host} {
     variable proxy
     variable no_proxy

     if {$proxy(host) == {}} {
         return {}
     }

     foreach domain $no_proxy {
         if {[string match $domain $host]} {
             return {}
         }
     }
     return [list $proxy(host) $proxy(port)]
 }

 package provide autoproxy 1.0

 #
 # Local variables:
 #   mode: tcl
 #   indent-tabs-mode: nil
 # End:

Automagic proxy authorization header by Anders Ramdahl

The filter is easily changed to automagically add a proxy authorization header when needed. Remember to set autoproxy::user and autoproxy::password before the first http::geturl call.

 proc autoproxy::filter {host} {
     variable user
     variable password
     variable proxy
     variable no_proxy

     if {$proxy(host) == {}} {
         return {}
     }

     foreach domain $no_proxy {
         if {[string match $domain $host]} {
             return {}
         }
     }

     # add proxy authorization header
     upvar state _state
     array set h $_state(-headers)
     set h(Proxy-Authorization) [concat Base [base64::encode $user:$password]]
     set _state(-headers) [array get h]

     return [list $proxy(host) $proxy(port)]
 }

This will fail if autoproxy::user or autoproxy::password is not set. I should probably add a catch statement somewhere.


I've incorporated Pat Thoyts' code in a project and it works like a charm. The only small issue being that ProxyOverride apparently does not always exist (according to one problem report I received) -jcw

11dec02 jcw - Another problem is that ProxyEnable may exist but not be a valid boolean.


Category Package