View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.client5.http.impl.nio;
29  
30  import java.net.InetAddress;
31  import java.net.InetSocketAddress;
32  import java.net.SocketAddress;
33  import java.util.concurrent.Future;
34  
35  import org.apache.hc.client5.http.DnsResolver;
36  import org.apache.hc.client5.http.SchemePortResolver;
37  import org.apache.hc.client5.http.config.TlsConfig;
38  import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
39  import org.apache.hc.client5.http.nio.AsyncClientConnectionOperator;
40  import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
41  import org.apache.hc.client5.http.routing.RoutingSupport;
42  import org.apache.hc.core5.concurrent.CallbackContribution;
43  import org.apache.hc.core5.concurrent.ComplexFuture;
44  import org.apache.hc.core5.concurrent.FutureCallback;
45  import org.apache.hc.core5.concurrent.FutureContribution;
46  import org.apache.hc.core5.http.HttpHost;
47  import org.apache.hc.core5.http.URIScheme;
48  import org.apache.hc.core5.http.config.Lookup;
49  import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
50  import org.apache.hc.core5.http.protocol.HttpContext;
51  import org.apache.hc.core5.reactor.ConnectionInitiator;
52  import org.apache.hc.core5.reactor.IOSession;
53  import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
54  import org.apache.hc.core5.util.Args;
55  import org.apache.hc.core5.util.Timeout;
56  
57  final class DefaultAsyncClientConnectionOperator implements AsyncClientConnectionOperator {
58  
59      private final SchemePortResolver schemePortResolver;
60      private final MultihomeIOSessionRequester sessionRequester;
61      private final Lookup<TlsStrategy> tlsStrategyLookup;
62  
63      DefaultAsyncClientConnectionOperator(
64              final Lookup<TlsStrategy> tlsStrategyLookup,
65              final SchemePortResolver schemePortResolver,
66              final DnsResolver dnsResolver) {
67          this.tlsStrategyLookup = Args.notNull(tlsStrategyLookup, "TLS strategy lookup");
68          this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
69          this.sessionRequester = new MultihomeIOSessionRequester(dnsResolver);
70      }
71  
72      @Override
73      public Future<ManagedAsyncClientConnection> connect(
74              final ConnectionInitiator connectionInitiator,
75              final HttpHost host,
76              final SocketAddress localAddress,
77              final Timeout connectTimeout,
78              final Object attachment,
79              final FutureCallback<ManagedAsyncClientConnection> callback) {
80          return connect(connectionInitiator, host, localAddress, connectTimeout,
81              attachment, null, callback);
82      }
83  
84      @Override
85      public Future<ManagedAsyncClientConnection> connect(
86              final ConnectionInitiator connectionInitiator,
87              final HttpHost host,
88              final SocketAddress localAddress,
89              final Timeout connectTimeout,
90              final Object attachment,
91              final HttpContext context,
92              final FutureCallback<ManagedAsyncClientConnection> callback) {
93          Args.notNull(connectionInitiator, "Connection initiator");
94          Args.notNull(host, "Host");
95          final ComplexFuture<ManagedAsyncClientConnection> future = new ComplexFuture<>(callback);
96          final HttpHost remoteEndpoint = RoutingSupport.normalize(host, schemePortResolver);
97          final InetAddress remoteAddress = host.getAddress();
98          final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
99          final TlsConfig tlsConfig = attachment instanceof TlsConfig ? (TlsConfig) attachment : TlsConfig.DEFAULT;
100         final Future<IOSession> sessionFuture = sessionRequester.connect(
101                 connectionInitiator,
102                 remoteEndpoint,
103                 remoteAddress != null ? new InetSocketAddress(remoteAddress, remoteEndpoint.getPort()) : null,
104                 localAddress,
105                 connectTimeout,
106                 tlsConfig.getHttpVersionPolicy(),
107                 new FutureCallback<IOSession>() {
108 
109                     @Override
110                     public void completed(final IOSession session) {
111                         final DefaultManagedAsyncClientConnection connection = new DefaultManagedAsyncClientConnection(session);
112                         if (tlsStrategy != null && URIScheme.HTTPS.same(host.getSchemeName())) {
113                             try {
114                                 final Timeout socketTimeout = connection.getSocketTimeout();
115                                 final Timeout handshakeTimeout = tlsConfig.getHandshakeTimeout();
116                                 tlsStrategy.upgrade(
117                                         connection,
118                                         host,
119                                         attachment,
120                                         handshakeTimeout != null ? handshakeTimeout : connectTimeout,
121                                         new FutureContribution<TransportSecurityLayer>(future) {
122 
123                                             @Override
124                                             public void completed(final TransportSecurityLayer transportSecurityLayer) {
125                                                 connection.setSocketTimeout(socketTimeout);
126                                                 future.completed(connection);
127                                             }
128 
129                                         });
130                             } catch (final Exception ex) {
131                                 future.failed(ex);
132                             }
133                         } else {
134                             future.completed(connection);
135                         }
136                     }
137 
138                     @Override
139                     public void failed(final Exception ex) {
140                         future.failed(ex);
141                     }
142 
143                     @Override
144                     public void cancelled() {
145                         future.cancel();
146                     }
147 
148                 });
149         future.setDependency(sessionFuture);
150         return future;
151     }
152 
153     @Override
154     public void upgrade(
155             final ManagedAsyncClientConnection connection,
156             final HttpHost host,
157             final Object attachment) {
158         upgrade(connection, host, attachment, null, null);
159     }
160 
161     @Override
162     public void upgrade(
163             final ManagedAsyncClientConnection connection,
164             final HttpHost host,
165             final Object attachment,
166             final HttpContext context) {
167         upgrade(connection, host, attachment, context, null);
168     }
169 
170     @Override
171     public void upgrade(
172             final ManagedAsyncClientConnection connection,
173             final HttpHost host,
174             final Object attachment,
175             final HttpContext context,
176             final FutureCallback<ManagedAsyncClientConnection> callback) {
177         final TlsStrategy tlsStrategy = tlsStrategyLookup != null ? tlsStrategyLookup.lookup(host.getSchemeName()) : null;
178         if (tlsStrategy != null) {
179             tlsStrategy.upgrade(
180                     connection,
181                     host,
182                     attachment,
183                     null,
184                     new CallbackContribution<TransportSecurityLayer>(callback) {
185 
186                         @Override
187                         public void completed(final TransportSecurityLayer transportSecurityLayer) {
188                             if (callback != null) {
189                                 callback.completed(connection);
190                             }
191                         }
192 
193                     });
194         }
195 
196     }
197 
198 }