@@ -25,6 +25,7 @@ using Sockets, LoggingExtras, NetworkOptions
2525using MbedTLS: SSLConfig, SSLContext, setup!, associate!, hostname!, handshake!
2626using MbedTLS, OpenSSL, ConcurrentUtilities
2727using .. IOExtras, .. Conditions, .. Exceptions
28+ using URIs: URI
2829
2930const nolimit = typemax (Int)
3031
@@ -73,6 +74,7 @@ Fields:
7374mutable struct Connection{IO_t <: IO } <: IO
7475 host:: String
7576 port:: String
77+ proxy:: Union{Nothing,String}
7678 idle_timeout:: Int
7779 require_ssl_verification:: Bool
7880 keepalive:: Bool
@@ -98,20 +100,21 @@ request parameters of host and port, and if ssl verification is required, if kee
98100and if an existing Connection was already created with the exact.
99101same parameters, we can re-use it (as long as it's not already being used, obviously).
100102"""
101- connectionkey (x:: Connection ) = (x. host, x. port, x. require_ssl_verification, x. keepalive, x. clientconnection)
103+ connectionkey (x:: Connection ) = (x. host, x. port, x. proxy, x . require_ssl_verification, x. keepalive, x. clientconnection)
102104
103- const ConnectionKeyType = Tuple{AbstractString, AbstractString, Bool, Bool, Bool}
105+ const ConnectionKeyType = Tuple{AbstractString, AbstractString, Union{Nothing,AbstractString}, Bool, Bool, Bool}
104106
105- Connection (host:: AbstractString , port:: AbstractString ,
107+ Connection (host:: AbstractString , port:: AbstractString , proxy :: Union{Nothing,AbstractString} ,
106108 idle_timeout:: Int ,
107109 require_ssl_verification:: Bool , keepalive:: Bool , io:: T , client= true ) where {T}=
108- Connection {T} (host, port, idle_timeout,
110+ Connection {T} (host, port, proxy, idle_timeout,
109111 require_ssl_verification, keepalive,
110112 safe_getpeername (io)... , localport (io),
111- io, client, PipeBuffer (), time (), false , false , IOBuffer (), nothing )
113+ io, client,
114+ PipeBuffer (), time (), false , false , IOBuffer (), nothing )
112115
113116Connection (io; require_ssl_verification:: Bool = true , keepalive:: Bool = true ) =
114- Connection (" " , " " , 0 , require_ssl_verification, keepalive, io, false )
117+ Connection (" " , " " , nothing , 0 , require_ssl_verification, keepalive, io, false )
115118
116119getrawstream (c:: Connection ) = c. io
117120
@@ -432,30 +435,59 @@ end
432435Find a reusable `Connection` in the `pool`,
433436or create a new `Connection` if required.
434437"""
435- function newconnection (:: Type{T} ,
436- host:: AbstractString ,
437- port:: AbstractString ;
438+ function newconnection (wrapconnection:: Function ,
439+ url:: URI ;
440+ proxy:: Union{Nothing, AbstractString} = nothing ,
441+ socket_type:: Type ,
442+ socket_type_tls:: Type ,
438443 pool:: Union{Nothing, Pool} = nothing ,
439444 connection_limit= nothing ,
440445 forcenew:: Bool = false ,
441446 idle_timeout= typemax (Int),
442- require_ssl_verification:: Bool = NetworkOptions. verify_host (host, " SSL" ),
447+ require_ssl_verification:: Bool = NetworkOptions. verify_host (url . host, " SSL" ),
443448 keepalive:: Bool = true ,
444- kw... ) where {T <: IO }
449+ kw... )
450+ IOType = sockettype (url, socket_type, socket_type_tls)
451+
445452 connection_limit_warning (connection_limit)
446- return acquire (
447- getpool (pool, T),
448- (host, port, require_ssl_verification, keepalive, true );
453+
454+ key = (url. host, url. port, proxy, require_ssl_verification, keepalive, true )
455+
456+ acquire (
457+ getpool (pool, IOType),
458+ key;
449459 forcenew= forcenew,
450460 isvalid= c-> connection_isvalid (c, Int (idle_timeout))) do
451- Connection (host, port,
461+
462+ if proxy != = nothing
463+ url = URI (proxy)
464+ end
465+
466+ innerIOType = sockettype (url, socket_type, socket_type_tls)
467+
468+ io = Connection (url. host, url. port, proxy,
452469 idle_timeout, require_ssl_verification, keepalive,
453- getconnection (T, host, port;
454- require_ssl_verification= require_ssl_verification, keepalive = keepalive, kw... )
470+ getconnection (innerIOType, url . host, url . port;
471+ require_ssl_verification, keepalive, kw... )
455472 )
473+
474+ try
475+ io = wrapconnection (io)
476+ catch ex
477+ @try Base. IOError close (io)
478+ rethrow (ex)
479+ end
480+
481+ if connectionkey (io) != key
482+ throw (ErrorException (string (" Connection error " , (;expected = connectionkey (io), key))))
483+ end
484+
485+ io
456486 end
457487end
458488
489+ sockettype (url:: URI , tcp, tls) = url. scheme in (" wss" , " https" ) ? tls : tcp
490+
459491function releaseconnection (c:: Connection{T} , reuse; pool:: Union{Nothing, Pool} = nothing , kw... ) where {T}
460492 c. timestamp = time ()
461493 release (getpool (pool, T), connectionkey (c), reuse ? c : nothing )
615647
616648function sslupgrade (:: Type{IOType} , c:: Connection{T} ,
617649 host:: AbstractString ;
618- pool:: Union{Nothing, Pool} = nothing ,
619650 require_ssl_verification:: Bool = NetworkOptions. verify_host (host, " SSL" ),
620651 keepalive:: Bool = true ,
621652 readtimeout:: Int = 0 ,
@@ -630,12 +661,9 @@ function sslupgrade(::Type{IOType}, c::Connection{T},
630661 else
631662 sslconnection (IOType, c. io, host; require_ssl_verification= require_ssl_verification, keepalive= keepalive, kw... )
632663 end
664+
633665 # success, now we turn it into a new Connection
634- conn = Connection (host, " " , 0 , require_ssl_verification, keepalive, tls)
635- # release the "old" one, but don't return the connection since we're hijacking the socket
636- release (getpool (pool, T), connectionkey (c))
637- # and return the new one
638- return acquire (() -> conn, getpool (pool, IOType), connectionkey (conn); forcenew= true )
666+ Connection (host," " , " " , 0 , require_ssl_verification, keepalive, tls)
639667end
640668
641669function Base. show (io:: IO , c:: Connection )
0 commit comments