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.io.IOException;
31  import java.net.SocketAddress;
32  import java.util.concurrent.atomic.AtomicBoolean;
33  
34  import javax.net.ssl.SSLContext;
35  import javax.net.ssl.SSLSession;
36  
37  import org.apache.hc.client5.http.nio.ManagedAsyncClientConnection;
38  import org.apache.hc.core5.concurrent.FutureCallback;
39  import org.apache.hc.core5.http.EndpointDetails;
40  import org.apache.hc.core5.http.HttpConnection;
41  import org.apache.hc.core5.http.HttpVersion;
42  import org.apache.hc.core5.http.ProtocolVersion;
43  import org.apache.hc.core5.http.nio.command.ShutdownCommand;
44  import org.apache.hc.core5.io.CloseMode;
45  import org.apache.hc.core5.net.NamedEndpoint;
46  import org.apache.hc.core5.reactor.Command;
47  import org.apache.hc.core5.reactor.IOEventHandler;
48  import org.apache.hc.core5.reactor.IOSession;
49  import org.apache.hc.core5.reactor.ProtocolIOSession;
50  import org.apache.hc.core5.reactor.ssl.SSLBufferMode;
51  import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
52  import org.apache.hc.core5.reactor.ssl.SSLSessionVerifier;
53  import org.apache.hc.core5.reactor.ssl.TlsDetails;
54  import org.apache.hc.core5.reactor.ssl.TransportSecurityLayer;
55  import org.apache.hc.core5.util.Identifiable;
56  import org.apache.hc.core5.util.Timeout;
57  import org.slf4j.Logger;
58  import org.slf4j.LoggerFactory;
59  
60  final class DefaultManagedAsyncClientConnection implements ManagedAsyncClientConnection, Identifiable {
61  
62      private static final Logger LOG = LoggerFactory.getLogger(DefaultManagedAsyncClientConnection.class);
63  
64      private final IOSession ioSession;
65      private final Timeout socketTimeout;
66      private final AtomicBoolean closed;
67  
68      public DefaultManagedAsyncClientConnection(final IOSession ioSession) {
69          this.ioSession = ioSession;
70          this.socketTimeout = ioSession.getSocketTimeout();
71          this.closed = new AtomicBoolean();
72      }
73  
74      @Override
75      public String getId() {
76          return ioSession.getId();
77      }
78  
79      @Override
80      public void close(final CloseMode closeMode) {
81          if (this.closed.compareAndSet(false, true)) {
82              if (LOG.isDebugEnabled()) {
83                  LOG.debug("{} Shutdown connection {}", getId(), closeMode);
84              }
85              ioSession.close(closeMode);
86          }
87      }
88  
89      @Override
90      public void close() throws IOException {
91          if (this.closed.compareAndSet(false, true)) {
92              if (LOG.isDebugEnabled()) {
93                  LOG.debug("{} Close connection", getId());
94              }
95              ioSession.enqueue(new ShutdownCommand(CloseMode.GRACEFUL), Command.Priority.IMMEDIATE);
96          }
97      }
98  
99      @Override
100     public boolean isOpen() {
101         return ioSession.isOpen();
102     }
103 
104     @Override
105     public void setSocketTimeout(final Timeout timeout) {
106         ioSession.setSocketTimeout(timeout);
107     }
108 
109     @Override
110     public Timeout getSocketTimeout() {
111         return ioSession.getSocketTimeout();
112     }
113 
114     @Override
115     public SocketAddress getRemoteAddress() {
116         return ioSession.getRemoteAddress();
117     }
118 
119     @Override
120     public SocketAddress getLocalAddress() {
121         return ioSession.getLocalAddress();
122     }
123 
124     @Override
125     public EndpointDetails getEndpointDetails() {
126         final IOEventHandler handler = ioSession.getHandler();
127         if (handler instanceof HttpConnection) {
128             return ((HttpConnection) handler).getEndpointDetails();
129         }
130         return null;
131     }
132 
133     @Override
134     public ProtocolVersion getProtocolVersion() {
135         final IOEventHandler handler = ioSession.getHandler();
136         if (handler instanceof HttpConnection) {
137             final ProtocolVersion version = ((HttpConnection) handler).getProtocolVersion();
138             if (version != null) {
139                 return version;
140             }
141         }
142         return HttpVersion.DEFAULT;
143     }
144 
145     @Override
146     public void startTls(
147             final SSLContext sslContext,
148             final NamedEndpoint endpoint,
149             final SSLBufferMode sslBufferMode,
150             final SSLSessionInitializer initializer,
151             final SSLSessionVerifier verifier,
152             final Timeout handshakeTimeout,
153             final FutureCallback<TransportSecurityLayer> callback) throws UnsupportedOperationException {
154         if (LOG.isDebugEnabled()) {
155             LOG.debug("{} start TLS", getId());
156         }
157         if (ioSession instanceof TransportSecurityLayer) {
158             ((TransportSecurityLayer) ioSession).startTls(sslContext, endpoint, sslBufferMode, initializer, verifier,
159                 handshakeTimeout, callback);
160         } else {
161             throw new UnsupportedOperationException("TLS upgrade not supported");
162         }
163     }
164 
165     @Override
166     public void startTls(
167             final SSLContext sslContext,
168             final NamedEndpoint endpoint,
169             final SSLBufferMode sslBufferMode,
170             final SSLSessionInitializer initializer,
171             final SSLSessionVerifier verifier,
172             final Timeout handshakeTimeout) throws UnsupportedOperationException {
173         startTls(sslContext, endpoint, sslBufferMode, initializer, verifier, handshakeTimeout, null);
174     }
175 
176     @Override
177     public TlsDetails getTlsDetails() {
178         return ioSession instanceof TransportSecurityLayer ? ((TransportSecurityLayer) ioSession).getTlsDetails() : null;
179     }
180 
181     @Override
182     public SSLSession getSSLSession() {
183         final TlsDetails tlsDetails = getTlsDetails();
184         return tlsDetails != null ? tlsDetails.getSSLSession() : null;
185     }
186 
187     @Override
188     public void submitCommand(final Command command, final Command.Priority priority) {
189         if (LOG.isDebugEnabled()) {
190             LOG.debug("{} {} with {} priority", getId(), command.getClass().getSimpleName(), priority);
191         }
192         ioSession.enqueue(command, Command.Priority.IMMEDIATE);
193     }
194 
195     @Override
196     public void passivate() {
197         ioSession.setSocketTimeout(Timeout.ZERO_MILLISECONDS);
198     }
199 
200     @Override
201     public void activate() {
202         ioSession.setSocketTimeout(socketTimeout);
203     }
204 
205     @Override
206     public void switchProtocol(final String protocolId,
207                                final FutureCallback<ProtocolIOSession> callback) throws UnsupportedOperationException {
208         if (ioSession instanceof ProtocolIOSession) {
209             ((ProtocolIOSession) ioSession).switchProtocol(protocolId, callback);
210         } else {
211             throw new UnsupportedOperationException("Protocol switch not supported");
212         }
213     }
214 
215 }