summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/http
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 19:39:39 (GMT)
commitea28451286d3ea4a772fa174483f9a7a66bb1ab3 (patch)
tree6ee9d8a7848333a7ceeee3b13d492e40225f8b86 /tcllib/modules/http
parentb5ca09bae0d6a1edce939eea03594dd56383f2c8 (diff)
parent7c621da28f07e449ad90c387344f07a453927569 (diff)
downloadblt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.zip
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.gz
blt-ea28451286d3ea4a772fa174483f9a7a66bb1ab3.tar.bz2
Merge commit '7c621da28f07e449ad90c387344f07a453927569' as 'tcllib'
Diffstat (limited to 'tcllib/modules/http')
-rw-r--r--tcllib/modules/http/ChangeLog159
-rw-r--r--tcllib/modules/http/autoproxy.man199
-rw-r--r--tcllib/modules/http/autoproxy.pcx62
-rw-r--r--tcllib/modules/http/autoproxy.tcl539
-rw-r--r--tcllib/modules/http/pkgIndex.tcl2
5 files changed, 961 insertions, 0 deletions
diff --git a/tcllib/modules/http/ChangeLog b/tcllib/modules/http/ChangeLog
new file mode 100644
index 0000000..74f393e
--- /dev/null
+++ b/tcllib/modules/http/ChangeLog
@@ -0,0 +1,159 @@
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2012-05-28 Andreas Kupries <andreask@activestate.com>
+
+ * autoproxy.tcl: Fixed bug where https proxying was attempted
+ * autoproxy.man: in the face of a domain exception. The TLS
+ * pkgIndex.tcl: setup code has to 'filter' properly. Further
+ check for existence of state(code), it may not exist (Server
+ accepts initial connection, then eof's during the TLS
+ handshake). Bumped version number to 1.5.3.
+
+2012-02-08 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Applied suggested fix from bug #3313923 to fix
+ handling of the -authProc option.
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2010-10-26 Andreas Kupries <andreask@activestate.com>
+
+ * autoproxy.man: [Bug 3094654]: Made the spelling of options
+ consistent, all using their '-'.
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11.1 ========================
+ *
+
+2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11 ========================
+ *
+
+2008-06-14 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * autoproxy.pcx: New file. Syntax definitions for the public
+ commands of the autoproxy package.
+
+2008-02-29 Andreas Kupries <andreask@activestate.com>
+
+ * autoproxy.tcl (::autoproxy::init, ::autoproxy::GetWin32Proxy):
+ Added tclchecker pragmas to suppress false non-portable command
+ warnings.
+
+ * autoproxy.tcl (::autoproxy::cget): Removed bogus closing
+ * autoproxy.man: bracket. Bumped version to 1.5.1
+ * pkgIndex.tcl:
+
+2008-02-27 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Fix title usage in defAuthProc
+
+2008-02-05 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.man: Increment version to 1.5 and document.
+ * autoproxy.tcl: Fixed architectural problems that prevented the
+ http registered command from having tls package options
+ appended. This makes an incompatible change to the tls_connect
+ command and the host and port must now be the last two options.
+ * autoproxy.tcl: Re-organised the tls_connect code to split out
+ the connect and the tls parts to create a tunnel_connect command
+ that can form a non-SSL tunnel through a proxy.
+
+2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.10 ========================
+ *
+
+2007-03-21 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * autoproxy.man: Fixed all warnings due to use of now deprecated
+ commands. Added a section about how to give feedback.
+
+2007-03-12 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Removed even the demo reference to BWidgets to
+ avoid confising the auto-dependency checker. Rearranged the tls
+ connection code to permit use outside of the http package as
+ tls_connect.
+ * autoproxy.man: Documented the tls functions.
+ * pkgIndex.tcl: Increment version to 1.4
+
+2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.9 ========================
+ *
+
+2006-09-19 Andreas Kupries <andreask@activestate.com>
+
+ * autoproxy.man: Bumped version to 1.3
+ * autoproxy.tcl:
+ * pkgIndex.tcl:
+
+2006-04-20 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Added a tls_socket procedure that can use
+ registered as the protocol handler for https
+ with the core http package and will do the right
+ thing when a proxy is in use.
+
+2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.8 ========================
+ *
+
+2005-02-17 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Dealt with the parsing requirements as mentioned
+ * autoproxy.man: in bug #1099162. In theory we may have different
+ * pkgIndex.tcl: proxy settings for https and http (and other
+ protocols) but to deal with these we will need to change the http
+ package so we do not deal with them now.
+
+2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.7 ========================
+ *
+
+2004-07-19 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Removed the stuff for Digest and NTLM until it
+ is working properly. Added an authProc configuration option to
+ permit application code to specify a procedure to get
+ authentication information from the user.
+
+2004-07-19 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Fix the version number.
+
+2004-07-17 Pat Thoyts <patthoyts@users.sourceforge.net>
+
+ * autoproxy.tcl: Import of the wiki version.
+ * autoproxy.man: Wrote a manual page.
diff --git a/tcllib/modules/http/autoproxy.man b/tcllib/modules/http/autoproxy.man
new file mode 100644
index 0000000..2401cf1
--- /dev/null
+++ b/tcllib/modules/http/autoproxy.man
@@ -0,0 +1,199 @@
+[manpage_begin autoproxy n 1.5.3]
+[see_also http(n)]
+[keywords authentication]
+[keywords http]
+[keywords proxy]
+[moddesc {HTTP protocol helper modules}]
+[titledesc {Automatic HTTP proxy usage and authentication}]
+[category Networking]
+[require Tcl 8.2]
+[require http [opt 2.0]]
+[require autoproxy [opt 1.5.3]]
+[description]
+[para]
+
+This package attempts to automate the use of HTTP proxy servers in Tcl
+HTTP client code. It tries to initialize the web access settings from
+system standard locations and can be configured to negotiate
+authentication with the proxy if required.
+
+[para]
+
+On Unix the 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.
+
+[para]
+
+There seem to be a number of ways that the http_proxy environment
+variable may be set up. Either a plain host:port or more commonly a
+URL and sometimes the URL may contain authentication parameters or
+these may be requested from the user or provided via http_proxy_user
+and http_proxy_pass. This package attempts to deal with all these
+schemes. It will do it's best to get the required parameters from the
+environment or registry and if it fails can be reconfigured.
+
+[include ../common-text/tls-security-notes.inc]
+
+[section "COMMANDS"]
+
+[list_begin definitions]
+
+[call [cmd ::autoproxy::init]]
+
+Initialize the autoproxy package from system resources. Under unix
+this means we look for environment variables. Under windows we look
+for the same environment variables but also look at the registry
+settings used by Internet Explorer.
+
+[call [cmd ::autoproxy::cget] [arg "-option"]]
+
+Retrieve individual package configuration options. See [sectref OPTIONS].
+
+[call [cmd ::autoproxy::configure] [opt "-option [arg value]"]]
+
+Configure the autoproxy package. Calling [cmd configure] with no
+options will return a list of all option names and values.
+See [sectref OPTIONS].
+
+[call [cmd ::autoproxy::tls_connect] [arg args]]
+
+Connect to a secure socket through a proxy. HTTP proxy servers permit
+the use of the CONNECT HTTP command to open a link through the proxy
+to the target machine. This function hides the details. For use with
+the http package see [cmd tls_socket].
+[para]
+The [arg args] list may contain any of the [package tls] package options but
+must end with the host and port as the last two items.
+
+[call [cmd ::autoproxy::tunnel_connect] [arg args]]
+
+Connect to a target host throught a proxy. This uses the same CONNECT
+HTTP command as the [cmd tls_connect] but does not promote the link
+security once the connection is established.
+[para]
+The [arg args] list may contain any of the [package tls] package options but
+must end with the host and port as the last two items.
+[para]
+Note that many proxy servers will permit CONNECT calls to a limited
+set of ports - typically only port 443 (the secure HTTP port).
+
+[call [cmd ::autoproxy::tls_socket] [arg args]]
+
+This function is to be used to register a proxy-aware secure socket
+handler for the https protocol. It may only be used with the Tcl http
+package and should be registered using the http::register command (see
+the examples below). The job of actually creating the tunnelled
+connection is done by the tls_connect command and this may be used
+when not registering with the http package.
+
+[list_end]
+
+[section {OPTIONS}]
+
+[list_begin options]
+
+[opt_def -host hostname]
+[opt_def -proxy_host hostname]
+Set the proxy hostname. This is normally set up by [cmd init] but may
+be configured here as well.
+
+[opt_def -port number]
+[opt_def -proxy_port number]
+Set the proxy port number. This is normally set up by [cmd init].
+e.g. [cmd configure] [option -port] [arg 3128]
+
+[opt_def -no_proxy list]
+You may manipulate the [option no_proxy] list that was setup by
+[cmd init]. The value of this option is a tcl list of
+strings that are matched against the http request host using the tcl
+[cmd "string match"] command. Therefore glob patterns are permitted.
+For instance, [cmd configure] [option -no_proxy] [arg "*.localdomain"]
+
+[opt_def -authProc procedure]
+This option may be used to set an application defined procedure to be
+called when [cmd configure] [option -basic] is called with either no or
+insufficient authentication details. This can be used to present a
+dialog to the user to request the additional information.
+
+[opt_def -basic]
+Following options are for configuring the Basic authentication
+scheme parameters. See [sectref "Basic Authentication"].
+
+[list_end]
+
+[section "Basic Authentication"]
+
+Basic is the simplest and most commonly use HTTP proxy authentication
+scheme. It is described in (1 section 11) and also in (2). It offers
+no privacy whatsoever and its use should be discouraged in favour of
+more secure alternatives like Digest. To perform Basic authentication
+the client base64 encodes the username and plaintext password
+separated by a colon. This encoded text is prefixed with the word
+"Basic" and a space.
+
+[para]
+
+The following options exists for this scheme:
+[list_begin options]
+[opt_def "-username" "name"]
+The username required to authenticate with the configured proxy.
+[opt_def "-password" "password"]
+The password required for the username specified.
+[opt_def "-realm" "realm"]
+This option is not used.
+[list_end]
+
+[section "EXAMPLES"]
+
+[para]
+[example {
+package require autoproxy
+autoproxy::init
+autoproxy::configure -basic -username ME -password SEKRET
+set tok [http::geturl http://wiki.tcl.tk/]
+http::data $tok
+}]
+
+[example {
+package require http
+package require tls
+package require autoproxy
+autoproxy::init
+http::register https 443 autoproxy::tls_socket
+set tok [http::geturl https://www.example.com/]
+}]
+
+[section {REFERENCES}]
+
+[list_begin enumerated]
+
+[enum]
+ Berners-Lee, T., Fielding R. and Frystyk, H.
+ "Hypertext Transfer Protocol -- HTTP/1.0",
+ RFC 1945, May 1996,
+ ([uri http://www.rfc-editor.org/rfc/rfc1945.txt])
+
+[enum]
+ Franks, J. et al.
+ "HTTP Authentication: Basic and Digest Access Authentication",
+ RFC 2617, June 1999
+ ([uri http://www.rfc-editor.org/rfc/rfc2617.txt])
+
+[list_end]
+
+[section {BUGS}]
+
+At this time only Basic authentication (1) (2) is supported. It is
+planned to add support for Digest (2) and NTLM in the future.
+
+[section AUTHORS]
+Pat Thoyts
+
+[vset CATEGORY {http :: autoproxy}]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/http/autoproxy.pcx b/tcllib/modules/http/autoproxy.pcx
new file mode 100644
index 0000000..8edad89
--- /dev/null
+++ b/tcllib/modules/http/autoproxy.pcx
@@ -0,0 +1,62 @@
+# -*- tcl -*- autoproxy.pcx
+# Syntax of the commands provided by package autoproxy.
+
+# For use by TclDevKit's static syntax checker.
+# See http://www.activestate.com/solutions/tcl/
+# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
+# for the documentation describing the format of the code contained in this file
+#
+
+package require pcx
+pcx::register autoproxy
+pcx::tcldep 1.5.1 needs tcl 8.2
+
+namespace eval ::autoproxy {}
+
+#pcx::message FOO {... text ...} type
+#pcx::scan <VERSION> <NAME> <RULE>
+
+pcx::check 1.5.1 std ::autoproxy::cget \
+ {checkSimpleArgs 1 1 {
+ checkKeyword 1 {-host -proxy_host -port -proxy_port -no_proxy -basic -authProc}
+ }}
+pcx::check 1.5.1 std ::autoproxy::configure \
+ {checkSimpleArgs 0 -1 {
+ {checkConfigure 1 {
+ {-host checkWord}
+ {-proy_host checkWord}
+ {-port checkWholeNum}
+ {-proxy_port checkWholeNum}
+ {-no_proxy checkList}
+ {-basic {checkConfigure 0 {
+ {-username checkWord}
+ {-password checkWord}
+ {-realm checkWord}
+ }}}
+ {-authProc checkProcName}
+ }}
+ }}
+pcx::check 1.5.1 std ::autoproxy::init \
+ {checkSimpleArgs 0 2 {
+ checkWord
+ checkList
+ }}
+# TODO: Get options/syntax for tls::socket
+pcx::check 1.5.1 std ::autoproxy::tls_connect \
+ {checkSimpleArgs 0 -1 {
+ checkWord
+ }}
+# TODO: Get options/syntax for tls_connect (s.a.)
+pcx::check 1.5.1 std ::autoproxy::tls_socket \
+ {checkSimpleArgs 0 -1 {
+ checkWord
+ }}
+# TODO: Get options/syntax for tls::socket
+pcx::check 1.5.1 std ::autoproxy::tunnel_connect \
+ {checkSimpleArgs 0 -1 {
+ checkWord
+ }}
+
+# Initialization via pcx::init.
+# Use a ::autoproxy::init procedure for non-standard initialization.
+pcx::complete
diff --git a/tcllib/modules/http/autoproxy.tcl b/tcllib/modules/http/autoproxy.tcl
new file mode 100644
index 0000000..6cc7c08
--- /dev/null
+++ b/tcllib/modules/http/autoproxy.tcl
@@ -0,0 +1,539 @@
+# autoproxy.tcl - Copyright (C) 2002-2008 Pat Thoyts <patthoyts@users.sf.net>
+#
+# On Unix the 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.
+#
+# Example:
+# package require autoproxy
+# autoproxy::init
+# set tok [http::geturl http://wiki.tcl.tk/]
+# http::data $tok
+#
+# To support https add:
+# package require tls
+# http::register https 443 ::autoproxy::tls_socket
+
+package require http; # tcl
+package require uri; # tcllib
+package require base64; # tcllib
+
+namespace eval ::autoproxy {
+ variable options
+
+ if {! [info exists options]} {
+ array set options {
+ proxy_host ""
+ proxy_port 80
+ no_proxy {}
+ basic {}
+ authProc {}
+ }
+ }
+
+ variable uid
+ if {![info exists uid]} { set uid 0 }
+
+ variable winregkey
+ set winregkey [join {
+ HKEY_CURRENT_USER
+ Software Microsoft Windows
+ CurrentVersion "Internet Settings"
+ } \\]
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# Obtain configuration options for the server.
+#
+proc ::autoproxy::cget {option} {
+ variable options
+ switch -glob -- $option {
+ -host -
+ -proxy_h* { set options(proxy_host) }
+ -port -
+ -proxy_p* { set options(proxy_port) }
+ -no* { set options(no_proxy) }
+ -basic { set options(basic) }
+ -authProc { set options(authProc) }
+ default {
+ set err [join [lsort [array names options]] ", -"]
+ return -code error "bad option \"$option\":\
+ must be one of -$err"
+ }
+ }
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# Configure the autoproxy package settings.
+# You may only configure one type of authorisation at a time as once we hit
+# -basic, -digest or -ntlm - all further args are passed to the protocol
+# specific script.
+#
+# Of course, most of the point of this package is to fill as many of these
+# fields as possible automatically. You should call autoproxy::init to
+# do automatic configuration and then call this method to refine the details.
+#
+proc ::autoproxy::configure {args} {
+ variable options
+
+ if {[llength $args] == 0} {
+ foreach {opt value} [array get options] {
+ lappend r -$opt $value
+ }
+ return $r
+ }
+
+ while {[string match "-*" [set option [lindex $args 0]]]} {
+ switch -glob -- $option {
+ -host -
+ -proxy_h* { set options(proxy_host) [Pop args 1]}
+ -port -
+ -proxy_p* { set options(proxy_port) [Pop args 1]}
+ -no* { set options(no_proxy) [Pop args 1] }
+ -basic { Pop args; configure:basic $args ; break }
+ -authProc { set options(authProc) [Pop args 1] }
+ -- { Pop args; break }
+ default {
+ set opts [join [lsort [array names options]] ", -"]
+ return -code error "bad option \"$option\":\
+ must be one of -$opts"
+ }
+ }
+ Pop args
+ }
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# Initialise the http proxy information from the environment or the
+# registry (Win32)
+#
+# This procedure will load the http package and re-writes the
+# http::geturl method to add in the authorisation header.
+#
+# A better solution will be to arrange for the http package to request the
+# authorisation key on receiving an authorisation reqest.
+#
+proc ::autoproxy::init {{httpproxy {}} {no_proxy {}}} {
+ global tcl_platform
+ global env
+ variable winregkey
+ variable options
+
+ # Look for standard environment variables.
+ if {[string length $httpproxy] > 0} {
+
+ # nothing to do
+
+ } elseif {[info exists env(http_proxy)]} {
+ set httpproxy $env(http_proxy)
+ if {[info exists env(no_proxy)]} {
+ set no_proxy $env(no_proxy)
+ }
+ } else {
+ if {$tcl_platform(platform) == "windows"} {
+ #checker -scope block exclude nonPortCmd
+ package require registry 1.0
+ array set reg {ProxyEnable 0 ProxyServer "" ProxyOverride {}}
+ catch {
+ # IE5 changed ProxyEnable from a binary to a dword value.
+ switch -exact -- [registry type $winregkey "ProxyEnable"] {
+ dword {
+ set reg(ProxyEnable) [registry get $winregkey "ProxyEnable"]
+ }
+ binary {
+ set v [registry get $winregkey "ProxyEnable"]
+ binary scan $v i reg(ProxyEnable)
+ }
+ default {
+ return -code error "unexpected type found for\
+ ProxyEnable registry item"
+ }
+ }
+ set reg(ProxyServer) [GetWin32Proxy http]
+ set reg(ProxyOverride) [registry get $winregkey "ProxyOverride"]
+ }
+ if {![string is bool $reg(ProxyEnable)]} {
+ set reg(ProxyEnable) 0
+ }
+ if {$reg(ProxyEnable)} {
+ set httpproxy $reg(ProxyServer)
+ set no_proxy $reg(ProxyOverride)
+ }
+ }
+ }
+
+ # If we found something ...
+ if {[string length $httpproxy] > 0} {
+ # 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]
+
+ # configure ourselves
+ configure -proxy_host $proxy(host) \
+ -proxy_port $proxy(port) \
+ -no_proxy $no_proxy
+
+ # Lift the authentication details from the environment if present.
+ if {[string length $proxy(user)] < 1 \
+ && [info exists env(http_proxy_user)] \
+ && [info exists env(http_proxy_pass)]} {
+ set proxy(user) $env(http_proxy_user)
+ set proxy(pwd) $env(http_proxy_pass)
+ }
+
+ # Maybe the proxy url has authentication parameters?
+ # At this time, only Basic is supported.
+ if {[string length $proxy(user)] > 0} {
+ configure -basic -username $proxy(user) -password $proxy(pwd)
+ }
+
+ # setup and configure the http package to use our proxy info.
+ http::config -proxyfilter [namespace origin filter]
+ }
+ return $httpproxy
+}
+
+# autoproxy::GetWin32Proxy --
+#
+# Parse the Windows Internet Settings registry key and return the
+# protocol proxy requested. If the same proxy is in use for all
+# protocols, then that will be returned. Otherwise the string is
+# parsed. Example:
+# ftp=proxy:80;http=proxy:80;https=proxy:80
+#
+proc ::autoproxy::GetWin32Proxy {protocol} {
+ variable winregkey
+ #checker exclude nonPortCmd
+ set proxies [split [registry get $winregkey "ProxyServer"] ";"]
+ foreach proxy $proxies {
+ if {[string first = $proxy] == -1} {
+ return $proxy
+ } else {
+ foreach {prot host} [split $proxy =] break
+ if {[string compare $protocol $prot] == 0} {
+ return $host
+ }
+ }
+ }
+ return -code error "failed to identify an '$protocol' proxy"
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# Pop the nth element off a list. Used in options processing.
+proc ::autoproxy::Pop {varname {nth 0}} {
+ upvar $varname args
+ set r [lindex $args $nth]
+ set args [lreplace $args $nth $nth]
+ return $r
+}
+
+# -------------------------------------------------------------------------
+# Description
+# An example user authentication procedure.
+# Returns:
+# A two element list consisting of the users authentication id and
+# password.
+proc ::autoproxy::defAuthProc {{user {}} {passwd {}} {realm {}}} {
+ if {[string length $realm] > 0} {
+ set title "Realm: $realm"
+ } else {
+ set title {}
+ }
+
+ # If you are using BWidgets then the following will do:
+ #
+ # package require BWidget
+ # return [PasswdDlg .defAuthDlg -parent {} -transient 0 \
+ # -title $title -logintext $user -passwdtext $passwd]
+ #
+ # if you just have Tk and no BWidgets --
+
+ set dlg [toplevel .autoproxy_defAuthProc -class Dialog]
+ wm title $dlg $title
+ wm withdraw $dlg
+ label $dlg.ll -text Login -underline 0 -anchor w
+ entry $dlg.le -textvariable [namespace current]::${dlg}:l
+ label $dlg.pl -text Password -underline 0 -anchor w
+ entry $dlg.pe -show * -textvariable [namespace current]::${dlg}:p
+ button $dlg.ok -text OK -default active -width -11 \
+ -command [list set [namespace current]::${dlg}:ok 1]
+ grid $dlg.ll $dlg.le -sticky news
+ grid $dlg.pl $dlg.pe -sticky news
+ grid $dlg.ok - -sticky e
+ grid columnconfigure $dlg 1 -weight 1
+ bind $dlg <Return> [list $dlg.ok invoke]
+ bind $dlg <Alt-l> [list focus $dlg.le]
+ bind $dlg <Alt-p> [list focus $dlg.pe]
+ variable ${dlg}:l $user; variable ${dlg}:p $passwd
+ variable ${dlg}:ok 0
+ wm deiconify $dlg; focus $dlg.pe; update idletasks
+ set old [::grab current]; grab $dlg
+ tkwait variable [namespace current]::${dlg}:ok
+ grab release $dlg ; if {[llength $old] > 0} {::grab $old}
+ set r [list [set ${dlg}:l] [set ${dlg}:p]]
+ unset ${dlg}:l; unset ${dlg}:p; unset ${dlg}:ok
+ destroy $dlg
+ return $r
+}
+
+# -------------------------------------------------------------------------
+
+# Description:
+# Implement support for the Basic authentication scheme (RFC 1945,2617).
+# Options:
+# -user userid - pass in the user ID (May require Windows NT domain
+# as DOMAIN\\username)
+# -password pwd - pass in the user's password.
+# -realm realm - pass in the http realm.
+#
+proc ::autoproxy::configure:basic {arglist} {
+ variable options
+ array set opts {user {} passwd {} realm {}}
+ foreach {opt value} $arglist {
+ switch -glob -- $opt {
+ -u* { set opts(user) $value}
+ -p* { set opts(passwd) $value}
+ -r* { set opts(realm) $value}
+ default {
+ return -code error "invalid option \"$opt\": must be one of\
+ -username or -password or -realm"
+ }
+ }
+ }
+
+ # If nothing was provided, try calling the authProc
+ if {$options(authProc) != {} \
+ && ($opts(user) == {} || $opts(passwd) == {})} {
+ set r [$options(authProc) $opts(user) $opts(passwd) $opts(realm)]
+ set opts(user) [lindex $r 0]
+ set opts(passwd) [lindex $r 1]
+ }
+
+ # Store the encoded string to avoid re-encoding all the time.
+ set options(basic) [list "Proxy-Authorization" \
+ [concat "Basic" \
+ [base64::encode $opts(user):$opts(passwd)]]]
+ return
+}
+
+# -------------------------------------------------------------------------
+# Description:
+# An http package proxy filter. This attempts to work out if a request
+# should go via the configured proxy using a glob comparison against the
+# no_proxy list items. A typical no_proxy list might be
+# [list localhost *.my.domain.com 127.0.0.1]
+#
+# If we are going to use the proxy - then insert the proxy authorization
+# header.
+#
+proc ::autoproxy::filter {host} {
+ variable options
+
+ if {$options(proxy_host) == {}} {
+ return {}
+ }
+
+ foreach domain $options(no_proxy) {
+ if {[string match $domain $host]} {
+ return {}
+ }
+ }
+
+ # Add authorisation header to the request (by Anders Ramdahl)
+ catch {
+ upvar state State
+ if {$options(basic) != {}} {
+ set State(-headers) [concat $options(basic) $State(-headers)]
+ }
+ }
+ return [list $options(proxy_host) $options(proxy_port)]
+}
+
+# -------------------------------------------------------------------------
+# autoproxy::tls_connect --
+#
+# Create a connection to a remote machine through a proxy
+# if necessary. This is used by the tls_socket command for
+# use with the http package but can also be used more generally
+# provided your proxy will permit CONNECT attempts to ports
+# other than port 443 (many will not).
+# This command defers to 'tunnel_connect' to link to the target
+# host and then upgrades the link to SSL/TLS
+#
+proc ::autoproxy::tls_connect {args} {
+ variable options
+ if {[string length $options(proxy_host)] > 0} {
+ set s [eval [linsert $args 0 tunnel_connect]]
+ fconfigure $s -blocking 1 -buffering none -translation binary
+ if {[string equal "-async" [lindex $args end-2]]} {
+ eval [linsert [lrange $args 0 end-3] 0 ::tls::import $s]
+ } else {
+ eval [linsert [lrange $args 0 end-2] 0 ::tls::import $s]
+ }
+ } else {
+ set s [eval [linsert $args 0 ::tls::socket]]
+ }
+ return $s
+}
+
+# autoproxy::tunnel_connect --
+#
+# Create a connection to a remote machine through a proxy
+# if necessary. This is used by the tls_socket command for
+# use with the http package but can also be used more generally
+# provided your proxy will permit CONNECT attempts to ports
+# other than port 443 (many will not).
+# Note: this command just opens the socket through the proxy to
+# the target machine -- no SSL/TLS negotiation is done yet.
+#
+proc ::autoproxy::tunnel_connect {args} {
+ variable options
+ variable uid
+ set code ok
+
+ # args = ... host port
+ # and the host/port is the actual endpoint we want to talk to,
+ # regardless of any proxying. See our caller tls_connect for
+ # ensuring this by peeking into the http package internals.
+
+ # To handle proxying properly we have to run through 'filter'
+ # (again), to ensure that proxy exceptions are correctly taken
+ # into account.
+
+ set proxy [filter [lindex $args end-1]]
+
+ if {[llength $proxy]} {
+ foreach {proxy_host proxy_port} $proxy break
+
+ set token [namespace current]::[incr uid]
+ upvar #0 $token state
+ set state(endpoint) [lrange $args end-1 end]
+ set state(state) connect
+ set state(data) ""
+ set state(useragent) [http::config -useragent]
+ set state(sock) [::socket $proxy_host $proxy_port]
+ fileevent $state(sock) writable [namespace code [list tunnel_write $token]]
+ vwait [set token](state)
+
+ if {[string length $state(error)] > 0} {
+ set result $state(error)
+ close $state(sock)
+ unset state
+ set code error
+ } elseif {[info exists state(code)] &&
+ (($state(code) >= 300) ||
+ ($state(code) < 200))} {
+ set result [lindex $state(headers) 0]
+ regexp {HTTP/\d.\d\s+\d+\s+(.*)} $result -> result
+ close $state(sock)
+ set code error
+ } else {
+ set result $state(sock)
+ }
+ unset state
+ } else {
+ set result [eval [linsert $args 0 ::socket]]
+ }
+ return -code $code $result
+}
+
+proc ::autoproxy::tunnel_write {token} {
+ upvar #0 $token state
+ variable options
+ fileevent $state(sock) writable {}
+ if {[catch {set state(error) [fconfigure $state(sock) -error]} err]} {
+ set state(error) $err
+ }
+ if {[string length $state(error)] > 0} {
+ set state(state) error
+ return
+ }
+ fconfigure $state(sock) -blocking 0 -buffering line -translation crlf
+ foreach {host port} $state(endpoint) break
+ puts $state(sock) "CONNECT $host:$port HTTP/1.1"
+ puts $state(sock) "Host: $host"
+ if {[string length $state(useragent)] > 0} {
+ puts $state(sock) "User-Agent: $state(useragent)"
+ }
+ puts $state(sock) "Proxy-Connection: keep-alive"
+ puts $state(sock) "Connection: keep-alive"
+ if {[string length $options(basic)] > 0} {
+ puts $state(sock) [join $options(basic) ": "]
+ }
+ puts $state(sock) ""
+
+ fileevent $state(sock) readable [namespace code [list tunnel_read $token]]
+ return
+}
+
+proc ::autoproxy::tunnel_read {token} {
+ upvar #0 $token state
+ set len [gets $state(sock) line]
+ if {[eof $state(sock)]} {
+ fileevent $state(sock) readable {}
+ set state(state) eof
+ } elseif {$len == 0} {
+ set state(code) [lindex [split [lindex $state(headers) 0] { }] 1]
+ fileevent $state(sock) readable {}
+ set state(state) ok
+ } else {
+ lappend state(headers) $line
+ }
+}
+
+# autoproxy::tls_socket --
+#
+# This can be used to handle TLS connections independently of
+# proxy presence. It can only be used with the Tcl http package
+# and to use it you must do:
+# http::register https 443 ::autoproxy::tls_socket
+# After that you can use the http::geturl command to access
+# secure web pages and any proxy details will be handled for you.
+#
+proc ::autoproxy::tls_socket {args} {
+ variable options
+
+ # Look into the http package for the actual target. If a proxy is in use then
+ # The function appends the proxy host and port and not the target.
+
+ upvar host uhost port uport
+ set args [lrange $args 0 end-2]
+ lappend args $uhost $uport
+
+ set s [eval [linsert $args 0 tls_connect]]
+
+ # record the tls connection status in the http state array.
+ upvar state state
+ tls::handshake $s
+ set state(tls_status) [tls::status $s]
+
+ return $s
+}
+
+# -------------------------------------------------------------------------
+
+package provide autoproxy 1.5.3
+
+# -------------------------------------------------------------------------
+#
+# Local variables:
+# mode: tcl
+# indent-tabs-mode: nil
+# End:
diff --git a/tcllib/modules/http/pkgIndex.tcl b/tcllib/modules/http/pkgIndex.tcl
new file mode 100644
index 0000000..c3ead43
--- /dev/null
+++ b/tcllib/modules/http/pkgIndex.tcl
@@ -0,0 +1,2 @@
+if {![package vsatisfies [package provide Tcl] 8.2]} {return}
+package ifneeded autoproxy 1.5.3 [list source [file join $dir autoproxy.tcl]]