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  package org.apache.hc.core5.http2.nio.pool;
28  
29  import java.net.InetSocketAddress;
30  import java.util.concurrent.Future;
31  
32  import org.apache.hc.core5.annotation.Contract;
33  import org.apache.hc.core5.annotation.ThreadingBehavior;
34  import org.apache.hc.core5.concurrent.CallbackContribution;
35  import org.apache.hc.core5.concurrent.FutureCallback;
36  import org.apache.hc.core5.function.Callback;
37  import org.apache.hc.core5.function.Resolver;
38  import org.apache.hc.core5.http.HttpHost;
39  import org.apache.hc.core5.http.URIScheme;
40  import org.apache.hc.core5.http.impl.DefaultAddressResolver;
41  import org.apache.hc.core5.http.nio.command.ShutdownCommand;
42  import org.apache.hc.core5.http.nio.ssl.TlsStrategy;
43  import org.apache.hc.core5.http2.nio.command.PingCommand;
44  import org.apache.hc.core5.http2.nio.support.BasicPingHandler;
45  import org.apache.hc.core5.io.CloseMode;
46  import org.apache.hc.core5.reactor.AbstractIOSessionPool;
47  import org.apache.hc.core5.reactor.Command;
48  import org.apache.hc.core5.reactor.ConnectionInitiator;
49  import org.apache.hc.core5.reactor.IOSession;
50  import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
51  import org.apache.hc.core5.util.Args;
52  import org.apache.hc.core5.util.TimeValue;
53  import org.apache.hc.core5.util.Timeout;
54  
55  /**
56   * Pool of HTTP/2 message multiplexing capable connections.
57   *
58   * @since 5.0
59   */
60  @Contract(threading = ThreadingBehavior.SAFE)
61  public final class H2ConnPool extends AbstractIOSessionPool<HttpHost> {
62  
63      private final ConnectionInitiator connectionInitiator;
64      private final Resolver<HttpHost, InetSocketAddress> addressResolver;
65      private final TlsStrategy tlsStrategy;
66  
67      private volatile TimeValue validateAfterInactivity = TimeValue.NEG_ONE_MILLISECOND;
68  
69      public H2ConnPool(
70              final ConnectionInitiator connectionInitiator,
71              final Resolver<HttpHost, InetSocketAddress> addressResolver,
72              final TlsStrategy tlsStrategy) {
73          super();
74          this.connectionInitiator = Args.notNull(connectionInitiator, "Connection initiator");
75          this.addressResolver = addressResolver != null ? addressResolver : DefaultAddressResolver.INSTANCE;
76          this.tlsStrategy = tlsStrategy;
77      }
78  
79      public TimeValue getValidateAfterInactivity() {
80          return validateAfterInactivity;
81      }
82  
83      public void setValidateAfterInactivity(final TimeValue timeValue) {
84          this.validateAfterInactivity = timeValue;
85      }
86  
87      @Override
88      protected void closeSession(
89              final IOSession ioSession,
90              final CloseMode closeMode) {
91          if (closeMode == CloseMode.GRACEFUL) {
92              ioSession.enqueue(ShutdownCommand.GRACEFUL, Command.Priority.NORMAL);
93          } else {
94              ioSession.close(closeMode);
95          }
96      }
97  
98      @Override
99      protected Future<IOSession> connectSession(
100             final HttpHost namedEndpoint,
101             final Timeout connectTimeout,
102             final FutureCallback<IOSession> callback) {
103         final InetSocketAddress remoteAddress = addressResolver.resolve(namedEndpoint);
104         return connectionInitiator.connect(
105                 namedEndpoint,
106                 remoteAddress,
107                 null,
108                 connectTimeout,
109                 null,
110                 new CallbackContribution<IOSession>(callback) {
111 
112                     @Override
113                     public void completed(final IOSession ioSession) {
114                         if (tlsStrategy != null
115                                 && URIScheme.HTTPS.same(namedEndpoint.getSchemeName())
116                                 && ioSession instanceof TransportSecurityLayer) {
117                             tlsStrategy.upgrade(
118                                     (TransportSecurityLayer) ioSession,
119                                     namedEndpoint,
120                                     ioSession.getLocalAddress(),
121                                     ioSession.getRemoteAddress(),
122                                     null,
123                                     connectTimeout);
124                             ioSession.setSocketTimeout(connectTimeout);
125                         }
126                         callback.completed(ioSession);
127                     }
128 
129                 });
130     }
131 
132     @Override
133     protected void validateSession(
134             final IOSession ioSession,
135             final Callback<Boolean> callback) {
136         if (ioSession.isOpen()) {
137             final TimeValue timeValue = validateAfterInactivity;
138             if (TimeValue.isNonNegative(timeValue)) {
139                 final long lastAccessTime = Math.min(ioSession.getLastReadTime(), ioSession.getLastWriteTime());
140                 final long deadline = lastAccessTime + timeValue.toMilliseconds();
141                 if (deadline <= System.currentTimeMillis()) {
142                     final Timeout socketTimeoutMillis = ioSession.getSocketTimeout();
143                     ioSession.enqueue(new PingCommand(new BasicPingHandler(new Callback<Boolean>() {
144 
145                         @Override
146                         public void execute(final Boolean result) {
147                             ioSession.setSocketTimeout(socketTimeoutMillis);
148                             callback.execute(result);
149                         }
150 
151                     })), Command.Priority.NORMAL);
152                     return;
153                 }
154             }
155             callback.execute(true);
156         } else {
157             callback.execute(false);
158         }
159     }
160 
161 }