11module ConnectionRequest
22
33using URIs, Sockets, Base64, LoggingExtras, ConcurrentUtilities, ExceptionUnwrapping
4- using MbedTLS: SSLContext, SSLConfig
5- using OpenSSL: SSLStream
4+ import MbedTLS
5+ import OpenSSL
66using .. Messages, .. IOExtras, .. Connections, .. Streams, .. Exceptions
77import .. SOCKET_TYPE_TLS
88
@@ -55,7 +55,7 @@ Close the connection if the request throws an exception.
5555Otherwise leave it open so that it can be reused.
5656"""
5757function connectionlayer (handler)
58- return function connections (req; proxy= getproxy (req. url. scheme, req. url. host), socket_type:: Type = TCPSocket, socket_type_tls:: Type = SOCKET_TYPE_TLS[] , readtimeout:: Int = 0 , connect_timeout:: Int = 30 , logerrors:: Bool = false , logtag= nothing , kw... )
58+ return function connections (req; proxy= getproxy (req. url. scheme, req. url. host), socket_type:: Type = TCPSocket, socket_type_tls:: Union{Nothing, Type} = nothing , readtimeout:: Int = 0 , connect_timeout:: Int = 30 , logerrors:: Bool = false , logtag= nothing , kw... )
5959 local io, stream
6060 if proxy != = nothing
6161 target_url = req. url
@@ -74,7 +74,7 @@ function connectionlayer(handler)
7474 end
7575
7676 connect_timeout = connect_timeout == 0 && readtimeout > 0 ? readtimeout : connect_timeout
77- IOType = sockettype (url, socket_type, socket_type_tls)
77+ IOType = sockettype (url, socket_type, socket_type_tls, get (kw, :sslconfig , nothing ) )
7878 start_time = time ()
7979 try
8080 io = newconnection (IOType, url. host, url. port; readtimeout= readtimeout, connect_timeout= connect_timeout, kw... )
@@ -148,7 +148,62 @@ function connectionlayer(handler)
148148 end
149149end
150150
151- sockettype (url:: URI , tcp, tls) = url. scheme in (" wss" , " https" ) ? tls : tcp
151+ function sockettype (url:: URI , socket_type_tcp, socket_type_tls, sslconfig)
152+ if url. scheme in (" wss" , " https" )
153+ tls_socket_type (socket_type_tls, sslconfig)
154+ else
155+ socket_type_tcp
156+ end
157+ end
158+
159+ """
160+ tls_socket_type(socket_type_tls, sslconfig)::Type
161+
162+ Find the best TLS socket type, given the values of these keyword arguments.
163+
164+ If both are `nothing` then we use the global default: `HTTP.SOCKET_TYPE_TLS[]`.
165+ If both are not `nothing` then they must agree:
166+ `sslconfig` must be of the right type to configure `socket_type_tls` or we throw an `ArgumentError`.
167+ """
168+ function tls_socket_type (socket_type_tls:: Union{Nothing, Type} ,
169+ sslconfig:: Union{Nothing, MbedTLS.SSLConfig, OpenSSL.SSLContext}
170+ ):: Type
171+
172+ socket_type_matching_sslconfig =
173+ if sslconfig isa MbedTLS. SSLConfig
174+ MbedTLS. SSLContext
175+ elseif sslconfig isa OpenSSL. SSLContext
176+ OpenSSL. SSLStream
177+ else
178+ nothing
179+ end
180+
181+ if socket_type_tls === socket_type_matching_sslconfig
182+ # Use the global default TLS socket if they're both nothing, or use
183+ # what they both specify if they're not nothing.
184+ isnothing (socket_type_tls) ? SOCKET_TYPE_TLS[] : socket_type_tls
185+ # If either is nothing, use the other one.
186+ elseif isnothing (socket_type_tls)
187+ socket_type_matching_sslconfig
188+ elseif isnothing (socket_type_matching_sslconfig)
189+ socket_type_tls
190+ else
191+ # If they specify contradictory types, throw an error.
192+ # Error thrown in noinline closure to avoid speed penalty in common case
193+ @noinline function err (socket_type_tls, sslconfig)
194+ msg = """
195+ Incompatible values for keyword args `socket_type_tls` and `sslconfig`:
196+ socket_type_tls=$socket_type_tls
197+ typeof(sslconfig)=$(typeof (sslconfig))
198+
199+ Make them match or provide only one of them.
200+ - the socket type MbedTLS.SSLContext is configured by MbedTLS.SSLConfig
201+ - the socket type OpenSSL.SSLStream is configured by OpenSSL.SSLContext"""
202+ throw (ArgumentError (msg))
203+ end
204+ err (socket_type_tls, sslconfig)
205+ end
206+ end
152207
153208function connect_tunnel (io, target_url, req)
154209 target = " $(URIs. hoststring (target_url. host)) :$(target_url. port) "
0 commit comments