4242import org .apache .hc .client5 .http .UnsupportedSchemeException ;
4343import org .apache .hc .client5 .http .impl .ConnPoolSupport ;
4444import org .apache .hc .client5 .http .impl .DefaultSchemePortResolver ;
45+ import org .apache .hc .client5 .http .io .DetachedSocketFactory ;
4546import org .apache .hc .client5 .http .io .HttpClientConnectionOperator ;
4647import org .apache .hc .client5 .http .io .ManagedHttpClientConnection ;
47- import org .apache .hc .client5 .http .protocol .HttpClientContext ;
4848import org .apache .hc .client5 .http .socket .ConnectionSocketFactory ;
4949import org .apache .hc .client5 .http .socket .LayeredConnectionSocketFactory ;
5050import org .apache .hc .core5 .annotation .Contract ;
5151import org .apache .hc .core5 .annotation .Internal ;
5252import org .apache .hc .core5 .annotation .ThreadingBehavior ;
5353import org .apache .hc .core5 .http .ConnectionClosedException ;
5454import org .apache .hc .core5 .http .HttpHost ;
55+ import org .apache .hc .core5 .http .URIScheme ;
5556import org .apache .hc .core5 .http .config .Lookup ;
5657import org .apache .hc .core5 .http .io .SocketConfig ;
5758import org .apache .hc .core5 .http .protocol .HttpContext ;
59+ import org .apache .hc .core5 .io .Closer ;
5860import org .apache .hc .core5 .util .Args ;
5961import org .apache .hc .core5 .util .TimeValue ;
6062import org .apache .hc .core5 .util .Timeout ;
7274@ Contract (threading = ThreadingBehavior .STATELESS )
7375public class DefaultHttpClientConnectionOperator implements HttpClientConnectionOperator {
7476
75- static final String SOCKET_FACTORY_REGISTRY = "http.socket-factory-registry" ;
76-
7777 private static final Logger LOG = LoggerFactory .getLogger (DefaultHttpClientConnectionOperator .class );
7878
79+ static final DetachedSocketFactory PLAIN_SOCKET_FACTORY = new DetachedSocketFactory () {
80+
81+ @ Override
82+ public Socket create (final Proxy socksProxy ) throws IOException {
83+ return socksProxy == null ? new Socket () : new Socket (socksProxy );
84+ }
85+
86+ };
87+
88+ private final DetachedSocketFactory detachedSocketFactory ;
7989 private final Lookup <ConnectionSocketFactory > socketFactoryRegistry ;
8090 private final SchemePortResolver schemePortResolver ;
8191 private final DnsResolver dnsResolver ;
8292
8393 public DefaultHttpClientConnectionOperator (
94+ final DetachedSocketFactory detachedSocketFactory ,
8495 final Lookup <ConnectionSocketFactory > socketFactoryRegistry ,
8596 final SchemePortResolver schemePortResolver ,
8697 final DnsResolver dnsResolver ) {
8798 super ();
88- Args .notNull (socketFactoryRegistry , "Socket factory registry " );
89- this .socketFactoryRegistry = socketFactoryRegistry ;
99+ this . detachedSocketFactory = Args .notNull (detachedSocketFactory , "Plain socket factory " );
100+ this .socketFactoryRegistry = Args . notNull ( socketFactoryRegistry , "Socket factory registry" ) ;
90101 this .schemePortResolver = schemePortResolver != null ? schemePortResolver :
91102 DefaultSchemePortResolver .INSTANCE ;
92103 this .dnsResolver = dnsResolver != null ? dnsResolver :
93104 SystemDefaultDnsResolver .INSTANCE ;
94105 }
95106
96- @ SuppressWarnings ("unchecked" )
97- private Lookup <ConnectionSocketFactory > getSocketFactoryRegistry (final HttpContext context ) {
98- Lookup <ConnectionSocketFactory > reg = (Lookup <ConnectionSocketFactory >) context .getAttribute (
99- SOCKET_FACTORY_REGISTRY );
100- if (reg == null ) {
101- reg = this .socketFactoryRegistry ;
102- }
103- return reg ;
107+ public DefaultHttpClientConnectionOperator (
108+ final Lookup <ConnectionSocketFactory > socketFactoryRegistry ,
109+ final SchemePortResolver schemePortResolver ,
110+ final DnsResolver dnsResolver ) {
111+ this (PLAIN_SOCKET_FACTORY , socketFactoryRegistry , schemePortResolver , dnsResolver );
104112 }
105113
106114 @ Override
@@ -128,11 +136,6 @@ public void connect(
128136 Args .notNull (host , "Host" );
129137 Args .notNull (socketConfig , "Socket config" );
130138 Args .notNull (context , "Context" );
131- final Lookup <ConnectionSocketFactory > registry = getSocketFactoryRegistry (context );
132- final ConnectionSocketFactory sf = registry .lookup (host .getSchemeName ());
133- if (sf == null ) {
134- throw new UnsupportedSchemeException (host .getSchemeName () + " protocol is not supported" );
135- }
136139 final InetAddress [] remoteAddresses ;
137140 if (host .getAddress () != null ) {
138141 remoteAddresses = new InetAddress [] { host .getAddress () };
@@ -154,47 +157,59 @@ public void connect(
154157
155158 final Timeout soTimeout = socketConfig .getSoTimeout ();
156159 final SocketAddress socksProxyAddress = socketConfig .getSocksProxyAddress ();
157- final Proxy proxy = socksProxyAddress != null ? new Proxy (Proxy .Type .SOCKS , socksProxyAddress ) : null ;
160+ final Proxy socksProxy = socksProxyAddress != null ? new Proxy (Proxy .Type .SOCKS , socksProxyAddress ) : null ;
158161 final int port = this .schemePortResolver .resolve (host );
159162 for (int i = 0 ; i < remoteAddresses .length ; i ++) {
160163 final InetAddress address = remoteAddresses [i ];
161164 final boolean last = i == remoteAddresses .length - 1 ;
162-
163- Socket sock = sf .createSocket (proxy , context );
164- if (soTimeout != null ) {
165- sock .setSoTimeout (soTimeout .toMillisecondsIntBound ());
166- }
167- sock .setReuseAddress (socketConfig .isSoReuseAddress ());
168- sock .setTcpNoDelay (socketConfig .isTcpNoDelay ());
169- sock .setKeepAlive (socketConfig .isSoKeepAlive ());
170- if (socketConfig .getRcvBufSize () > 0 ) {
171- sock .setReceiveBufferSize (socketConfig .getRcvBufSize ());
172- }
173- if (socketConfig .getSndBufSize () > 0 ) {
174- sock .setSendBufferSize (socketConfig .getSndBufSize ());
175- }
176-
177- final int linger = socketConfig .getSoLinger ().toMillisecondsIntBound ();
178- if (linger >= 0 ) {
179- sock .setSoLinger (true , linger );
180- }
181- conn .bind (sock );
182-
183165 final InetSocketAddress remoteAddress = new InetSocketAddress (address , port );
184166 if (LOG .isDebugEnabled ()) {
185167 LOG .debug ("{}:{} connecting {}->{} ({})" ,
186168 host .getHostName (), host .getPort (), localAddress , remoteAddress , connectTimeout );
187169 }
170+ final Socket socket = detachedSocketFactory .create (socksProxy );
188171 try {
189- sock = sf .connectSocket (sock , host , remoteAddress , localAddress , connectTimeout , attachment , context );
190- conn .bind (sock );
172+ conn .bind (socket );
173+ if (soTimeout != null ) {
174+ socket .setSoTimeout (soTimeout .toMillisecondsIntBound ());
175+ }
176+ socket .setReuseAddress (socketConfig .isSoReuseAddress ());
177+ socket .setTcpNoDelay (socketConfig .isTcpNoDelay ());
178+ socket .setKeepAlive (socketConfig .isSoKeepAlive ());
179+ if (socketConfig .getRcvBufSize () > 0 ) {
180+ socket .setReceiveBufferSize (socketConfig .getRcvBufSize ());
181+ }
182+ if (socketConfig .getSndBufSize () > 0 ) {
183+ socket .setSendBufferSize (socketConfig .getSndBufSize ());
184+ }
185+
186+ final int linger = socketConfig .getSoLinger ().toMillisecondsIntBound ();
187+ if (linger >= 0 ) {
188+ socket .setSoLinger (true , linger );
189+ }
190+
191+ if (localAddress != null ) {
192+ socket .bind (localAddress );
193+ }
194+ socket .connect (remoteAddress , TimeValue .isPositive (connectTimeout ) ? connectTimeout .toMillisecondsIntBound () : 0 );
195+ conn .bind (socket );
191196 conn .setSocketTimeout (soTimeout );
192197 if (LOG .isDebugEnabled ()) {
193198 LOG .debug ("{}:{} connected {}->{} as {}" ,
194199 host .getHostName (), host .getPort (), localAddress , remoteAddress , ConnPoolSupport .getId (conn ));
195200 }
201+ final ConnectionSocketFactory connectionSocketFactory = socketFactoryRegistry != null ? socketFactoryRegistry .lookup (host .getSchemeName ()) : null ;
202+ if (connectionSocketFactory instanceof LayeredConnectionSocketFactory && URIScheme .HTTPS .same (host .getSchemeName ())) {
203+ final LayeredConnectionSocketFactory lsf = (LayeredConnectionSocketFactory ) connectionSocketFactory ;
204+ final Socket upgradedSocket = lsf .createLayeredSocket (socket , host .getHostName (), port , attachment , context );
205+ conn .bind (upgradedSocket );
206+ }
196207 return ;
208+ } catch (final RuntimeException ex ) {
209+ Closer .closeQuietly (socket );
210+ throw ex ;
197211 } catch (final IOException ex ) {
212+ Closer .closeQuietly (socket );
198213 if (last ) {
199214 if (LOG .isDebugEnabled ()) {
200215 LOG .debug ("{}:{} connection to {} failed ({}); terminating operation" ,
@@ -225,9 +240,7 @@ public void upgrade(
225240 final HttpHost host ,
226241 final Object attachment ,
227242 final HttpContext context ) throws IOException {
228- final HttpClientContext clientContext = HttpClientContext .adapt (context );
229- final Lookup <ConnectionSocketFactory > registry = getSocketFactoryRegistry (clientContext );
230- final ConnectionSocketFactory sf = registry .lookup (host .getSchemeName ());
243+ final ConnectionSocketFactory sf = socketFactoryRegistry .lookup (host .getSchemeName ());
231244 if (sf == null ) {
232245 throw new UnsupportedSchemeException (host .getSchemeName () +
233246 " protocol is not supported" );
0 commit comments