1414
1515import NIOSSL
1616
17+ #if canImport(Darwin)
18+ import Darwin. C
19+ #elseif os(Linux) || os(FreeBSD) || os(Android)
20+ import Glibc
21+ #else
22+ #error("unsupported target operating system")
23+ #endif
24+
25+ extension String {
26+ var isIPAddress : Bool {
27+ var ipv4Address = in_addr ( )
28+ var ipv6Address = in6_addr ( )
29+ return self . withCString { host in
30+ inet_pton ( AF_INET, host, & ipv4Address) == 1 ||
31+ inet_pton ( AF_INET6, host, & ipv6Address) == 1
32+ }
33+ }
34+ }
35+
1736enum ConnectionPool {
1837 /// Used by the `ConnectionPool` to index its `HTTP1ConnectionProvider`s
1938 ///
@@ -24,15 +43,18 @@ enum ConnectionPool {
2443 var scheme : Scheme
2544 var connectionTarget : ConnectionTarget
2645 private var tlsConfiguration : BestEffortHashableTLSConfiguration ?
46+ var serverNameIndicatorOverride : String ?
2747
2848 init (
2949 scheme: Scheme ,
3050 connectionTarget: ConnectionTarget ,
31- tlsConfiguration: BestEffortHashableTLSConfiguration ? = nil
51+ tlsConfiguration: BestEffortHashableTLSConfiguration ? = nil ,
52+ serverNameIndicatorOverride: String ?
3253 ) {
3354 self . scheme = scheme
3455 self . connectionTarget = connectionTarget
3556 self . tlsConfiguration = tlsConfiguration
57+ self . serverNameIndicatorOverride = serverNameIndicatorOverride
3658 }
3759
3860 var description : String {
@@ -48,26 +70,44 @@ enum ConnectionPool {
4870 case . unixSocket( let socketPath) :
4971 hostDescription = socketPath
5072 }
51- return " \( self . scheme) :// \( hostDescription) TLS-hash: \( hash) "
73+ return " \( self . scheme) :// \( hostDescription) \( self . serverNameIndicatorOverride . map { " SNI: \( $0 ) " } ?? " " ) TLS-hash: \( hash) "
5274 }
5375 }
5476}
5577
78+ extension DeconstructedURL {
79+ func applyDNSOverride( _ dnsOverride: [ String : String ] ) -> ( ConnectionTarget , serverNameIndicatorOverride: String ? ) {
80+ guard
81+ let originalHost = self . connectionTarget. host,
82+ let hostOverride = dnsOverride [ originalHost]
83+ else {
84+ return ( self . connectionTarget, nil )
85+ }
86+ return (
87+ . init( remoteHost: hostOverride, port: self . connectionTarget. port ?? self . scheme. defaultPort) ,
88+ serverNameIndicatorOverride: originalHost. isIPAddress ? nil : originalHost
89+ )
90+ }
91+ }
92+
5693extension ConnectionPool . Key {
57- init ( url: DeconstructedURL , tlsConfiguration: TLSConfiguration ? ) {
94+ init ( url: DeconstructedURL , tlsConfiguration: TLSConfiguration ? , dnsOverride: [ String : String ] ) {
95+ let ( connectionTarget, serverNameIndicatorOverride) = url. applyDNSOverride ( dnsOverride)
5896 self . init (
5997 scheme: url. scheme,
60- connectionTarget: url . connectionTarget,
98+ connectionTarget: connectionTarget,
6199 tlsConfiguration: tlsConfiguration. map {
62100 BestEffortHashableTLSConfiguration ( wrapping: $0)
63- }
101+ } ,
102+ serverNameIndicatorOverride: serverNameIndicatorOverride
64103 )
65104 }
66105
67- init ( _ request: HTTPClient . Request ) {
106+ init ( _ request: HTTPClient . Request , dnsOverride : [ String : String ] = [ : ] ) {
68107 self . init (
69108 url: request. deconstructedURL,
70- tlsConfiguration: request. tlsConfiguration
109+ tlsConfiguration: request. tlsConfiguration,
110+ dnsOverride: dnsOverride
71111 )
72112 }
73113}
0 commit comments