diff options
| author | kjnash <k.j.nash@usa.net> | 2022-11-10 17:10:49 (GMT) |
|---|---|---|
| committer | kjnash <k.j.nash@usa.net> | 2022-11-10 17:10:49 (GMT) |
| commit | b2b045293797df7ff4e350e74cfdab191eadc31f (patch) | |
| tree | 7fd15e3285134613f2ac27dffb21f427a7c56d9f | |
| parent | a90bc45a547c857ffc5257490827aebfb7ac6d8d (diff) | |
| parent | 1684b35abb9f320d56c45d0044a5a8c0b594cb90 (diff) | |
| download | tcl-b2b045293797df7ff4e350e74cfdab191eadc31f.zip tcl-b2b045293797df7ff4e350e74cfdab191eadc31f.tar.gz tcl-b2b045293797df7ff4e350e74cfdab191eadc31f.tar.bz2 | |
Merge http-bugfixes-2022H2. Fix bugs in recent http.tcl code related to https over a proxy server, especially cleanup after a failed CONNECT request to the proxy. Add new tests to httpProxy.test.
| -rw-r--r-- | library/http/http.tcl | 261 | ||||
| -rw-r--r-- | tests/httpProxy.test | 874 |
2 files changed, 993 insertions, 142 deletions
diff --git a/library/http/http.tcl b/library/http/http.tcl index fcb03e1..a1d4a2b 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -77,6 +77,7 @@ namespace eval http { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId if {[info exists socketMapping]} { # Close open sockets on re-init. Do not permit retries. foreach {url sock} [array get socketMapping] { @@ -101,6 +102,7 @@ namespace eval http { array unset socketClosing array unset socketPlayCmd array unset socketCoEvent + array unset socketProxyId array set socketMapping {} array set socketRdState {} array set socketWrState {} @@ -110,6 +112,7 @@ namespace eval http { array set socketClosing {} array set socketPlayCmd {} array set socketCoEvent {} + array set socketProxyId {} return } init @@ -219,6 +222,33 @@ namespace eval http { 511 {Network Authentication Required} }] + variable failedProxyValues { + binary + body + charset + coding + connection + connectionRespFlag + currentsize + host + http + httpResponse + meta + method + querylength + queryoffset + reasonPhrase + requestHeaders + requestLine + responseCode + state + status + tid + totalsize + transfer + type + } + namespace export geturl config reset wait formatQuery postError quoteString namespace export register unregister registerError namespace export requestLine requestHeaders requestHeaderValue @@ -380,6 +410,7 @@ proc http::Finish {token {errormsg ""} {skipCB 0}} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId variable $token upvar 0 $token state @@ -513,6 +544,7 @@ proc http::KeepSocket {token} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId variable $token upvar 0 $token state @@ -715,6 +747,7 @@ proc http::CloseSocket {s {token {}}} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId set tk [namespace tail $token] @@ -777,8 +810,9 @@ proc http::CloseQueuedQueries {connId {token {}}} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId - ##Log CloseQueuedQueries $connId + ##Log CloseQueuedQueries $connId $token if {![info exists socketMapping($connId)]} { # Command has already been called. # Don't come here again - especially recursively. @@ -838,6 +872,7 @@ proc http::Unset {connId} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId unset socketMapping($connId) unset socketRdState($connId) @@ -846,6 +881,7 @@ proc http::Unset {connId} { unset -nocomplain socketWrQueue($connId) unset -nocomplain socketClosing($connId) unset -nocomplain socketPlayCmd($connId) + unset -nocomplain socketProxyId($connId) return } @@ -871,6 +907,7 @@ proc http::reset {token {why reset}} { set errorlist $state(error) unset state eval ::error $errorlist + # i.e. error msg errorInfo errorCode } return } @@ -1316,6 +1353,11 @@ proc http::CreateToken {url args} { set srvurl $url set targetAddr [list $phost $pport] set state(proxyUsed) HttpProxy + # The value of state(proxyUsed) none|HttpProxy depends only on the + # all-transactions http::config settings and on the target URL. + # Even if this is a persistent socket there is no need to change the + # value of state(proxyUsed) for other transactions that use the socket: + # they have the same value already. } else { set targetAddr [list $host $port] } @@ -1351,6 +1393,7 @@ proc http::CreateToken {url args} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId if {[info exists socketMapping($state(socketinfo))]} { # - If the connection is idle, it has a "fileevent readable" binding @@ -1373,6 +1416,7 @@ proc http::CreateToken {url args} { # causes a call to Finish. set reusing 1 set sock $socketMapping($state(socketinfo)) + set state(proxyUsed) $socketProxyId($state(socketinfo)) Log "reusing closing socket $sock for $state(socketinfo) - token $token" set state(alreadyQueued) 1 @@ -1407,6 +1451,7 @@ proc http::CreateToken {url args} { # - The socket may not yet exist, and be defined with a placeholder. set reusing 1 set sock $socketMapping($state(socketinfo)) + set state(proxyUsed) $socketProxyId($state(socketinfo)) if {[SockIsPlaceHolder $sock]} { set state(ReusingPlaceholder) 1 lappend socketPhQueue($sock) $token @@ -1505,6 +1550,7 @@ proc http::AsyncTransaction {token} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId set sock $state(sock) @@ -1581,9 +1627,15 @@ proc http::PreparePersistentConnection {token} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId set DoLater {-traceread 0 -tracewrite 0} set socketMapping($state(socketinfo)) $state(sock) + set socketProxyId($state(socketinfo)) $state(proxyUsed) + # - The value of state(proxyUsed) was set in http::CreateToken to either + # "none" or "HttpProxy". + # - $token is the first transaction to use this placeholder, so there are + # no other tokens whose (proxyUsed) must be modified. if {![info exists socketRdState($state(socketinfo))]} { set socketRdState($state(socketinfo)) {} @@ -1613,12 +1665,16 @@ proc http::PreparePersistentConnection {token} { set socketWrState($state(socketinfo)) $token } + # Value of socketPhQueue() may have already been set by ReplayCore. + if {![info exists socketPhQueue($state(sock))]} { + set socketPhQueue($state(sock)) {} + } set socketRdQueue($state(socketinfo)) {} set socketWrQueue($state(socketinfo)) {} - set socketPhQueue($state(socketinfo)) {} set socketClosing($state(socketinfo)) 0 set socketPlayCmd($state(socketinfo)) {ReplayIfClose Wready {} {}} set socketCoEvent($state(socketinfo)) {} + set socketProxyId($state(socketinfo)) {} return $DoLater } @@ -1651,6 +1707,7 @@ proc http::OpenSocket {token DoLater} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId Log >K$tk Start OpenSocket coroutine @@ -1697,16 +1754,38 @@ proc http::OpenSocket {token DoLater} { # Code above has set state(sock) $sock ConfigureNewSocket $token $sockOld $DoLater + ##Log OpenSocket success $sock - token $token } result errdict]} { + ##Log OpenSocket failed $result - token $token + # There may be other requests in the socketPhQueue. + # Prepare socketPlayCmd so that Finish will replay them. + if { ($state(-keepalive)) && (!$state(reusing)) + && [info exists socketPhQueue($sockOld)] + && ($socketPhQueue($sockOld) ne {}) + } { + if {$socketMapping($state(socketinfo)) ne $sockOld} { + Log "WARNING: this code should not be reached.\ + {$socketMapping($state(socketinfo)) ne $sockOld}" + } + set socketPlayCmd($state(socketinfo)) [list ReplayIfClose Wready {} $socketPhQueue($sockOld)] + set socketPhQueue($sockOld) {} + } if {[string range $result 0 20] eq {proxy connect failed:}} { - # The socket can be persistent: if so it is identified with - # the https target host, and will be kept open. - # Results of the failed proxy CONNECT have been copied to $token and - # are available to the caller. - Eot $token - } else { - Finish $token $result - } + # - The HTTPS proxy did not create a socket. The pre-existing value + # (a "placeholder socket") is unchanged. + # - The proxy returned a valid HTTP response to the failed CONNECT + # request, and http::SecureProxyConnect copied this to $token, + # and also set ${token}(connection) set to "close". + # - Remove the error message $result so that Finish delivers this + # HTTP response to the caller. + set result {} + } + Finish $token $result + # Because socket creation failed, the placeholder "socket" must be + # "closed" and (if persistent) removed from the persistent sockets + # table. In the {proxy connect failed:} case Finish does this because + # the value of ${token}(connection) is "close". In the other cases here, + # it does so because $result is non-empty. } ##Log Leaving http::OpenSocket coroutine [info coroutine] - token $token return @@ -1758,10 +1837,12 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId set reusing $state(reusing) set sock $state(sock) - ##Log " ConfigureNewSocket" $token $sockOld ... -- $sock + set proxyUsed $state(proxyUsed) + ##Log " ConfigureNewSocket" $token $sockOld ... -- $reusing $sock $proxyUsed if {(!$reusing) && ($sock ne $sockOld)} { # Replace the placeholder value sockOld with sock. @@ -1770,6 +1851,8 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { && ($socketMapping($state(socketinfo)) eq $sockOld) } { set socketMapping($state(socketinfo)) $sock + set socketProxyId($state(socketinfo)) $proxyUsed + # tokens that use the placeholder $sockOld are updated below. ##Log set socketMapping($state(socketinfo)) $sock } @@ -1809,6 +1892,7 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { # 1. Amend the token's (sock). ##Log set ${tok}(sock) $sock set ${tok}(sock) $sock + set ${tok}(proxyUsed) $proxyUsed # 2. Schedule the token's HTTP request. # Every token in socketPhQueue(*) has reusing 1 alreadyQueued 0. @@ -1839,7 +1923,7 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { # waiting until the read(s) in progress are finished). # socketRdQueue($connId) List of tokens that are queued for reading later. # socketWrQueue($connId) List of tokens that are queued for writing later. -# socketPhQueue($connId) List of tokens that are queued to use a placeholder +# socketPhQueue($sock) List of tokens that are queued to use a placeholder # socket, when the real socket has not yet been created. # socketClosing($connId) (boolean) true iff a server response header indicates # that the server will close the connection at the end of @@ -1848,6 +1932,11 @@ proc http::ConfigureNewSocket {token sockOld DoLater} { # part-completed transactions if the socket closes early. # socketCoEvent($connId) Identifier for the "after idle" event that will launch # an OpenSocket coroutine to open or re-use a socket. +# socketProxyId($connId) The type of proxy that this socket uses: values are +# those of state(proxyUsed) i.e. none, HttpProxy, +# SecureProxy, and SecureProxyFailed. +# The value is not used for anything by http, its purpose +# is to set the value of state() for caller information. # ------------------------------------------------------------------------------ @@ -1903,6 +1992,7 @@ proc http::ScheduleRequest {token} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId set Unfinished 0 @@ -2048,6 +2138,7 @@ proc http::Connected {token proto phost srvurl} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId variable $token upvar 0 $token state @@ -2325,7 +2416,8 @@ proc http::Connected {token proto phost srvurl} { # If any other requests are in flight or pipelined/queued, they will # be discarded. } elseif {$state(status) eq ""} { - # ...https handshake errors come here. + # https handshake errors come here, for + # Tcl 8.7 without http::SecureProxyConnect, and for Tcl 8.6. set msg [registerError $sock] registerError $sock {} if {$msg eq {}} { @@ -2386,6 +2478,7 @@ proc http::DoneRequest {token} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId variable $token upvar 0 $token state @@ -2717,6 +2810,7 @@ proc http::ReplayIfDead {token doing} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId variable $token upvar 0 $token state @@ -2960,6 +3054,7 @@ proc http::ReplayCore {newQueue} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId if {[llength $newQueue] == 0} { # Nothing to do. @@ -2979,6 +3074,7 @@ proc http::ReplayCore {newQueue} { if {![ReInit $token]} { Log FAILED in http::ReplayCore - NO tmp vars + Log ReplayCore reject $token Finish $token {cannot send this request again} return } @@ -2993,6 +3089,7 @@ proc http::ReplayCore {newQueue} { set state(reusing) 0 set state(ReusingPlaceholder) 0 set state(alreadyQueued) 0 + Log ReplayCore replay $token # Give the socket a placeholder name before it is created. set sock HTTP_PLACEHOLDER_[incr TmpSockCounter] @@ -3005,7 +3102,9 @@ proc http::ReplayCore {newQueue} { set ${tok}(reusing) 1 set ${tok}(sock) $sock lappend socketPhQueue($sock) $tok + Log ReplayCore replay $tok } else { + Log ReplayCore reject $tok set ${tok}(reusing) 1 set ${tok}(sock) NONE Finish $tok {cannot send this request again} @@ -3309,6 +3408,7 @@ proc http::Write {token} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId variable $token upvar 0 $token state @@ -3421,6 +3521,7 @@ proc http::Event {sock token} { variable socketClosing variable socketPlayCmd variable socketCoEvent + variable socketProxyId variable $token upvar 0 $token state @@ -3473,8 +3574,15 @@ proc http::Event {sock token} { # If any other requests are in flight or pipelined/queued, # they will be discarded. } else { + # https handshake errors come here, for + # Tcl 8.7 with http::SecureProxyConnect. + set msg [registerError $sock] + registerError $sock {} + if {$msg eq {}} { + set msg $nsl + } Log ^X$tk end of response (error) - token $token - Finish $token $nsl + Finish $token $msg return } } elseif {$nsl >= 0} { @@ -4882,21 +4990,18 @@ proc http::socketForTls {args} { # # Return Value: a socket identifier # ------------------------------------------------------------------------------ -proc http::AllDone {varName args} { - set $varName done - return -} proc http::SecureProxyConnect {args} { variable http variable ConnectVar variable ConnectCounter + variable failedProxyValues set varName ::http::ConnectVar([incr ConnectCounter]) # Extract (non-proxy) target from args. set host [lindex $args end-3] set port [lindex $args end-2] - set args [lremove $args end-3 end-2] + set args [lreplace $args end-3 end-2] # Proxy server URL for connection. # This determines where the socket is opened. @@ -4918,8 +5023,12 @@ proc http::SecureProxyConnect {args} { # Record in the token that this is a proxy call. set token [lindex $args $targ+1] upvar 0 ${token} state - set state(proxyUsed) SecureProxy set tim $state(-timeout) + set state(proxyUsed) SecureProxyFailed + # This value is overwritten with "SecureProxy" below if the CONNECT is + # successful. If it is unsuccessful, the socket will be closed + # below, and so in this unsuccessful case there are no other transactions + # whose (proxyUsed) must be updated. } else { set tim 0 } @@ -4941,8 +5050,11 @@ proc http::SecureProxyConnect {args} { variable $token2 upvar 0 $token2 state2 - # Setting this variable overrides the HTTP request line and allows + # Kludges: + # Setting this variable overrides the HTTP request line and also allows # -headers to override the Connection: header set by -keepalive. + # The arguments "-keepalive 0" ensure that when Finish is called for an + # unsuccessful request, the socket is always closed. set state2(bypass) "CONNECT $host:$port HTTP/1.1" AsyncTransaction $token2 @@ -4961,41 +5073,90 @@ proc http::SecureProxyConnect {args} { } unset $varName - set sock $state2(sock) - set code $state2(responseCode) - if {[string is integer -strict $code] && ($code >= 200) && ($code < 300)} { - # All OK. The caller in tls will now call "tls::import $sock". - # Do not use Finish, which will close (sock). - # Other tidying done in http::Event. - array unset state2 - } elseif {$targ != -1} { - # Bad HTTP status code; token is known. - # Copy from state2 to state, including (sock). - foreach name [array names state2] { - set state($name) $state2($name) + if { ($state2(state) ne "complete") + || ($state2(status) ne "ok") + || (![string is integer -strict $state2(responseCode)]) + } { + set msg {the HTTP request to the proxy server did not return a valid\ + and complete response} + if {[info exists state2(error)]} { + append msg ": " [lindex $state2(error) 0] } - set state(proxyUsed) SecureProxy - set state(proxyFail) failed + cleanup $token2 + return -code error $msg + } - # Do not use Finish, which will close (sock). - # Other tidying done in http::Event. - array unset state2 + set code $state2(responseCode) - # Error message detected by http::OpenSocket. - return -code error "proxy connect failed: $code" - } else { - # Bad HTTP status code; token is not known because option -type - # (cf. targ) was not passed through tcltls, and so the script - # cannot write to state(*). - # Do not use Finish, which will close (sock). - # Other tidying done in http::Event. - array unset state2 + if {($code >= 200) && ($code < 300)} { + # All OK. The caller in package tls will now call "tls::import $sock". + # The cleanup command does not close $sock. + # Other tidying was done in http::Event. - # Error message detected by http::OpenSocket. - return -code error "proxy connect failed: $code\n$block" + # If this is a persistent socket, any other transactions that are + # already marked to use the socket will have their (proxyUsed) updated + # when http::OpenSocket calls http::ConfigureNewSocket. + set state(proxyUsed) SecureProxy + set sock $state2(sock) + cleanup $token2 + return $sock } - return $sock + if {$targ != -1} { + # Non-OK HTTP status code; token is known because option -type + # (cf. targ) was passed through tcltls, and so the useful + # parts of the proxy's response can be copied to state(*). + # Do not copy state2(sock). + # Return the proxy response to the caller of geturl. + foreach name $failedProxyValues { + if {[info exists state2($name)]} { + set state($name) $state2($name) + } + } + set state(connection) close + set msg "proxy connect failed: $code" + # - This error message will be detected by http::OpenSocket and will + # cause it to present the proxy's HTTP response as that of the + # original $token transaction, identified only by state(proxyUsed) + # as the response of the proxy. + # - The cases where this would mislead the caller of http::geturl are + # given a different value of msg (below) so that http::OpenSocket will + # treat them as errors, but will preserve the $token array for + # inspection by the caller. + # - Status code 305 (Proxy Required) was deprecated for security reasons + # in RFC 2616 (June 1999) and in any case should never be served by a + # proxy. + # - Other 3xx responses from the proxy are inappropriate, and should not + # occur. + # - A 401 response from the proxy is inappropriate, and should not + # occur. It would be confusing if returned to the caller. + + if {($code >= 300) && ($code < 400)} { + set msg "the proxy server responded to the HTTP request with an\ + inappropriate $code redirect" + set loc [responseHeaderValue $token2 location] + if {$loc ne {}} { + append msg "to " $loc + } + } elseif {($code == 401)} { + set msg "the proxy server responded to the HTTP request with an\ + inappropriate 401 request for target-host credentials" + } else { + } + } else { + set msg "connection to proxy failed with status code $code" + } + + # - ${token2}(sock) has already been closed because -keepalive 0. + # - Error return does not pass the socket ID to the + # $token transaction, which retains its socket placeholder. + cleanup $token2 + return -code error $msg +} + +proc http::AllDone {varName args} { + set $varName done + return } diff --git a/tests/httpProxy.test b/tests/httpProxy.test index 90fe828..d8bd6b7 100644 --- a/tests/httpProxy.test +++ b/tests/httpProxy.test @@ -26,6 +26,10 @@ proc bgerror {args} { puts stderr $errorInfo } +proc stopMe {token} { + set ${token}(z) done +} + if {![info exists ThreadLevel]} { if {[catch {package require Thread}] == 0} { set ValueRange {0 1 2} @@ -85,40 +89,44 @@ test httpProxy-1.1.$ThreadLevel {squid is running - ipv4 noauth} -constraints {n } -body { set token [http::geturl http://$n4host:$n4port/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 400 none} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed]" +} -result {complete ok 400 -- none} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res } test httpProxy-1.2.$ThreadLevel {squid is running - ipv6 noauth} -constraints {needsSquid} -setup { } -body { set token [http::geturl http://\[$n6host\]:$n6port/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 400 none} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed]" +} -result {complete ok 400 -- none} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res } test httpProxy-1.3.$ThreadLevel {squid is running - ipv4 auth} -constraints {needsSquid} -setup { } -body { set token [http::geturl http://$a4host:$a4port/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 400 none} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed]" +} -result {complete ok 400 -- none} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res } test httpProxy-1.4.$ThreadLevel {squid is running - ipv6 auth} -constraints {needsSquid} -setup { } -body { set token [http::geturl http://\[$a6host\]:$a6port/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 400 none} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed]" +} -result {complete ok 400 -- none} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res } test httpProxy-2.1.$ThreadLevel {http no-proxy no-auth} -constraints {needsSquid} -setup { @@ -126,10 +134,12 @@ test httpProxy-2.1.$ThreadLevel {http no-proxy no-auth} -constraints {needsSquid } -body { set token [http::geturl http://www.google.com/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 200 none} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res } test httpProxy-2.2.$ThreadLevel {https no-proxy no-auth} -constraints {needsSquid needsTls} -setup { @@ -137,10 +147,12 @@ test httpProxy-2.2.$ThreadLevel {https no-proxy no-auth} -constraints {needsSqui } -body { set token [http::geturl https://www.google.com/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 200 none} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res } test httpProxy-2.3.$ThreadLevel {http with-proxy ipv4 no-auth} -constraints {needsSquid} -setup { @@ -148,10 +160,12 @@ test httpProxy-2.3.$ThreadLevel {http with-proxy ipv4 no-auth} -constraints {nee } -body { set token [http::geturl http://www.google.com/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 200 HttpProxy} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- HttpProxy -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res http::config -proxyhost {} -proxyport {} -proxynot {} } @@ -160,34 +174,40 @@ test httpProxy-2.4.$ThreadLevel {https with-proxy ipv4 no-auth} -constraints {ne } -body { set token [http::geturl https://www.google.com/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 200 SecureProxy} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- SecureProxy -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res http::config -proxyhost {} -proxyport {} -proxynot {} } test httpProxy-2.5.$ThreadLevel {http with-proxy ipv6 no-auth} -constraints {needsSquid} -setup { - http::config -proxyhost $n6host -proxyport $n6port -proxynot {127.0.0.1 localhost} -proxyauth {} + http::config -proxyhost $n6host -proxyport $n6port -proxynot {::1 localhost} -proxyauth {} } -body { set token [http::geturl http://www.google.com/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 200 HttpProxy} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- HttpProxy -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res http::config -proxyhost {} -proxyport {} -proxynot {} } test httpProxy-2.6.$ThreadLevel {https with-proxy ipv6 no-auth} -constraints {needsSquid needsTls} -setup { - http::config -proxyhost $n6host -proxyport $n6port -proxynot {127.0.0.1 localhost} -proxyauth {} + http::config -proxyhost $n6host -proxyport $n6port -proxynot {::1 localhost} -proxyauth {} } -body { set token [http::geturl https://www.google.com/] set ri [http::responseInfo $token] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed]" -} -result {complete ok 200 SecureProxy} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- SecureProxy -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res + unset -nocomplain token ri res http::config -proxyhost {} -proxyport {} -proxynot {} } @@ -198,10 +218,12 @@ test httpProxy-3.1.$ThreadLevel {http no-proxy with-auth valid-creds-provided} - set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 none 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -212,10 +234,12 @@ test httpProxy-3.2.$ThreadLevel {https no-proxy with-auth valid-creds-provided} set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 none 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -226,10 +250,12 @@ test httpProxy-3.3.$ThreadLevel {http with-proxy ipv4 with-auth valid-creds-prov set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 HttpProxy 1 1} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- HttpProxy 1 1 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -240,38 +266,332 @@ test httpProxy-3.4.$ThreadLevel {https with-proxy ipv4 with-auth valid-creds-pro set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 SecureProxy 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- SecureProxy 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } test httpProxy-3.5.$ThreadLevel {http with-proxy ipv6 with-auth valid-creds-provided} -constraints {needsSquid} -setup { - http::config -proxyhost $a6host -proxyport $a6port -proxynot {127.0.0.1 localhost} -proxyauth $aliceCreds + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $aliceCreds } -body { set token [http::geturl http://www.google.com/] set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 HttpProxy 1 1} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- HttpProxy 1 1 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } test httpProxy-3.6.$ThreadLevel {https with-proxy ipv6 with-auth valid-creds-provided} -constraints {needsSquid needsTls} -setup { - http::config -proxyhost $a6host -proxyport $a6port -proxynot {127.0.0.1 localhost} -proxyauth $aliceCreds + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $aliceCreds } -body { set token [http::geturl https://www.google.com/] set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 SecureProxy 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- SecureProxy 0 0 -- -1} -cleanup { + http::cleanup $token + unset -nocomplain token ri res pos1 pos2 + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.7.$ThreadLevel {http with-proxy ipv4 with-auth valid-creds-provided; check that 2nd valid request with creds is possible, and keep-alive works} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth $aliceCreds + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.7x.$ThreadLevel {http with-proxy ipv4 with-auth 1st request no-creds-provided; check that 2nd request with creds is possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth {} + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] + + http::config -proxyauth $aliceCreds +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.8.$ThreadLevel {https with-proxy ipv4 with-auth valid-creds-provided; check that 2nd valid request with creds is possible, and keep-alive works} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth $aliceCreds + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- SecureProxy 0 0 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.8x.$ThreadLevel {https with-proxy ipv4 with-auth 1st request no-creds-provided; check that 2nd request with creds is possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth {} + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] + + http::config -proxyauth $aliceCreds +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- SecureProxy 0 0 -- -1 done 0} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.9.$ThreadLevel {http with-proxy ipv6 with-auth valid-creds-provided; check that 2nd valid request with creds is possible, and keep-alive works} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $aliceCreds + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.9p.$ThreadLevel {http with-proxy ipv6 with-auth valid-creds-provided; check that 2nd valid request with creds is possible, and keep-alive works, pipelining requested and possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $aliceCreds +} -body { + set can0 [after 6000 {http::reset $token0; set ${token0}(z) timeout}] + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] +after idle { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can +} + vwait ${token0}(z) + after cancel $can0 + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token0 token ri res pos1 pos2 can0 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.9x.$ThreadLevel {http with-proxy ipv6 with-auth 1st request no-creds-provided; check that 2nd request with creds is possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] + + http::config -proxyauth $aliceCreds +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.10.$ThreadLevel {https with-proxy ipv6 with-auth valid-creds-provided; check that 2nd valid request with creds is possible, and keep-alive works} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $aliceCreds + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- SecureProxy 0 0 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.10p.$ThreadLevel {https with-proxy ipv6 with-auth valid-creds-provided; check that 2nd valid request with creds is possible, and keep-alive works, pipelining requested and possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $aliceCreds +} -body { + set can0 [after 6000 {http::reset $token0; set ${token0}(z) timeout}] + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] +after idle { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token0; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can +} + vwait ${token0}(z) + after cancel $can0 + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- SecureProxy 0 0 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can0 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-3.10x.$ThreadLevel {https with-proxy ipv6 with-auth 1st request no-creds-provided; check that 2nd request with creds is possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] + + http::config -proxyauth $aliceCreds +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 200 -- SecureProxy 0 0 -- -1 done 0} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -282,10 +602,12 @@ test httpProxy-4.1.$ThreadLevel {http no-proxy with-auth no-creds-provided} -con set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 none 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -296,10 +618,12 @@ test httpProxy-4.2.$ThreadLevel {https no-proxy with-auth no-creds-provided} -co set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 none 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -310,10 +634,12 @@ test httpProxy-4.3.$ThreadLevel {http with-proxy ipv4 with-auth no-creds-provide set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 HttpProxy 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- HttpProxy 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -324,38 +650,217 @@ test httpProxy-4.4.$ThreadLevel {https with-proxy ipv4 with-auth no-creds-provid set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 SecureProxy 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- SecureProxyFailed 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } test httpProxy-4.5.$ThreadLevel {http with-proxy ipv6 with-auth no-creds-provided} -constraints {needsSquid} -setup { - http::config -proxyhost $a6host -proxyport $a6port -proxynot {127.0.0.1 localhost} -proxyauth {} + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} } -body { set token [http::geturl http://www.google.com/] set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 HttpProxy 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- HttpProxy 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } test httpProxy-4.6.$ThreadLevel {https with-proxy ipv6 with-auth no-creds-provided} -constraints {needsSquid needsTls} -setup { - http::config -proxyhost $a6host -proxyport $a6port -proxynot {127.0.0.1 localhost} -proxyauth {} + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} } -body { set token [http::geturl https://www.google.com/] set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 SecureProxy 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- SecureProxyFailed 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-4.7.$ThreadLevel {http with-proxy ipv4 with-auth no-creds-provided; check that 2nd request is possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth {} + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- HttpProxy 0 0 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-4.8.$ThreadLevel {https with-proxy ipv4 with-auth no-creds-provided; check that 2nd request is possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth {} + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- SecureProxyFailed 0 0 -- -1 done 0} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-4.9.$ThreadLevel {http with-proxy ipv6 with-auth no-creds-provided; check that 2nd request is possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- HttpProxy 0 0 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-4.9p.$ThreadLevel {http with-proxy ipv6 with-auth no-creds-provided; check that 2nd request is possible, pipelining requested and possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} +} -body { + set can0 [after 6000 {http::reset $token0; set ${token0}(z) timeout}] + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] +after idle { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token0; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can +} + vwait ${token0}(z) + after cancel $can0 + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- HttpProxy 0 0 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can0 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-4.10.$ThreadLevel {https with-proxy ipv6 with-auth no-creds-provided; check that 2nd request is possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- SecureProxyFailed 0 0 -- -1 done 0} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-4.10p.$ThreadLevel {https with-proxy ipv6 with-auth no-creds-provided; check that 2nd request is possible, pipelining requested but not possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth {} +} -body { + set can0 [after 6000 {http::reset $token0; set ${token0}(z) timeout}] + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + +after idle { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can +} + vwait ${token0}(z) + after cancel $can0 + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $aliceCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- SecureProxyFailed 0 0 -- -1 done 0} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can0 can same + array unset ::http::socketMapping http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -366,10 +871,12 @@ test httpProxy-5.1.$ThreadLevel {http no-proxy with-auth bad-creds-provided} -co set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 none 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -380,10 +887,12 @@ test httpProxy-5.2.$ThreadLevel {https no-proxy with-auth bad-creds-provided} -c set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 200 none 0 0} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 200 -- none 0 0 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -394,10 +903,12 @@ test httpProxy-5.3.$ThreadLevel {http with-proxy ipv4 with-auth bad-creds-provid set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 HttpProxy 1 1} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- HttpProxy 1 1 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -408,38 +919,216 @@ test httpProxy-5.4.$ThreadLevel {https with-proxy ipv4 with-auth bad-creds-provi set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 SecureProxy 1 1} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- SecureProxyFailed 1 1 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } test httpProxy-5.5.$ThreadLevel {http with-proxy ipv6 with-auth bad-creds-provided} -constraints {needsSquid} -setup { - http::config -proxyhost $a6host -proxyport $a6port -proxynot {127.0.0.1 localhost} -proxyauth $badCreds + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $badCreds } -body { set token [http::geturl http://www.google.com/] set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 HttpProxy 1 1} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- HttpProxy 1 1 -- -1} -cleanup { http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token ri res pos1 pos2 http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } test httpProxy-5.6.$ThreadLevel {https with-proxy ipv6 with-auth bad-creds-provided} -constraints {needsSquid needsTls} -setup { - http::config -proxyhost $a6host -proxyport $a6port -proxynot {127.0.0.1 localhost} -proxyauth $badCreds + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $badCreds } -body { set token [http::geturl https://www.google.com/] set ri [http::responseInfo $token] set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] - set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}]" -} -result {complete ok 407 SecureProxy 1 1} -cleanup { + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*]" +} -result {complete ok 407 -- SecureProxyFailed 1 1 -- -1} -cleanup { + http::cleanup $token + unset -nocomplain token ri res pos1 pos2 + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-5.7.$ThreadLevel {http with-proxy ipv4 with-auth bad-creds-provided; check that 2nd request is possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth $badCreds + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-5.7p.$ThreadLevel {http with-proxy ipv4 with-auth bad-creds-provided; check that 2nd request is possible, pipelining requested and possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth $badCreds +} -body { + set can0 [after 6000 {http::reset $token0; set ${token0}(z) timeout}] + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + # Use the same caution as for the corresponding https test. +after idle { + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can +} + vwait ${token0}(z) + after cancel $can0 + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can0 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-5.8.$ThreadLevel {https with-proxy ipv4 with-auth bad-creds-provided; check that 2nd request is possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth $badCreds + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- SecureProxyFailed 1 1 -- -1 done 0} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-5.8p.$ThreadLevel {https with-proxy ipv4 with-auth bad-creds-provided; check that 2nd request is possible, pipelining requested but not possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a4host -proxyport $a4port -proxynot {127.0.0.1 localhost} -proxyauth $badCreds +} -body { + set can0 [after 6000 {http::reset $token0; set ${token0}(z) timeout}] + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. +after idle { + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can +} + vwait ${token0}(z) + after cancel $can0 + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- SecureProxyFailed 1 1 -- -1 done 0} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can0 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-5.9.$ThreadLevel {http with-proxy ipv6 with-auth bad-creds-provided; check that 2nd request is possible} -constraints {needsSquid} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $badCreds + set token0 [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # Use the same caution as for the corresponding https test. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl http://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- HttpProxy 1 1 -- -1 done 1} -cleanup { + http::cleanup $token0 + http::cleanup $token + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping + http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} +} + +test httpProxy-5.10.$ThreadLevel {https with-proxy ipv6 with-auth bad-creds-provided; check that 2nd request is possible} -constraints {needsSquid needsTls} -setup { + array unset ::http::socketMapping + http::config -proxyhost $a6host -proxyport $a6port -proxynot {::1 localhost} -proxyauth $badCreds + set token0 [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000] +} -body { + # If a bug passes the socket of a failed CONNECT to the main request, an infinite + # wait can occur despite -timeout. Fix this with http::reset; to do this the call + # to http::geturl must be async so we have $token for use as argument of reset. + set can [after 6000 {http::reset $token; set ${token}(z) timeout}] + set token [http::geturl https://www.google.com/ -keepalive 1 -timeout 5000 -command stopMe] + vwait ${token}(z) + after cancel $can + + set ri [http::responseInfo $token] + set pos1 [lsearch -exact [string tolower [set ${token}(requestHeaders)]] proxy-authorization] + set pos2 [lsearch -exact [set ${token}(requestHeaders)] $badCreds] + set same [string equal [set ${token0}(sock)] [set ${token}(sock)]] + set res "[dict get $ri stage] [dict get $ri status] [dict get $ri responseCode] --\ + [dict get $ri proxyUsed] [expr {$pos1 > -1}] [expr {$pos2 > -1}] --\ + [lsearch -glob [array get ::http::socketMapping] HTTP_PLACEHOLDER_*] [set ${token}(z)] $same" +} -result {complete ok 407 -- SecureProxyFailed 1 1 -- -1 done 0} -cleanup { + http::cleanup $token0 http::cleanup $token - unset -nocomplain ri res pos1 pos2 + unset -nocomplain token0 token ri res pos1 pos2 can same + array unset ::http::socketMapping http::config -proxyhost {} -proxyport {} -proxynot {} -proxyauth {} } @@ -447,6 +1136,7 @@ test httpProxy-5.6.$ThreadLevel {https with-proxy ipv6 with-auth bad-creds-provi unset -nocomplain n4host n6host n4port n6port a4host a6host a4port a6port aliceCreds badCreds rename bgerror {} +rename stopMe {} ::tcltest::cleanupTests |
