1 /*
2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.internal.net.http;
27 
28 import java.net.InetSocketAddress;
29 import java.nio.channels.SocketChannel;
30 import java.util.concurrent.CompletableFuture;
31 import java.net.http.HttpHeaders;
32 import java.util.function.Function;
33 import jdk.internal.net.http.common.MinimalFuture;
34 import jdk.internal.net.http.common.SSLTube;
35 import jdk.internal.net.http.common.Utils;
36 
37 /**
38  * An SSL tunnel built on a Plain (CONNECT) TCP tunnel.
39  */
40 class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
41 
42     final PlainTunnelingConnection plainConnection;
43     final PlainHttpPublisher writePublisher;
44     volatile SSLTube flow;
45 
AsyncSSLTunnelConnection(InetSocketAddress addr, HttpClientImpl client, String[] alpn, InetSocketAddress proxy, HttpHeaders proxyHeaders)46     AsyncSSLTunnelConnection(InetSocketAddress addr,
47                              HttpClientImpl client,
48                              String[] alpn,
49                              InetSocketAddress proxy,
50                              HttpHeaders proxyHeaders)
51     {
52         super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn);
53         this.plainConnection = new PlainTunnelingConnection(addr, proxy, client, proxyHeaders);
54         this.writePublisher = new PlainHttpPublisher();
55     }
56 
57     @Override
connectAsync(Exchange<?> exchange)58     public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
59         if (debug.on()) debug.log("Connecting plain tunnel connection");
60         // This will connect the PlainHttpConnection flow, so that
61         // its HttpSubscriber and HttpPublisher are subscribed to the
62         // SocketTube
63         return plainConnection
64                 .connectAsync(exchange)
65                 .thenApply( unused -> {
66                     if (debug.on()) debug.log("creating SSLTube");
67                     // create the SSLTube wrapping the SocketTube, with the given engine
68                     flow = new SSLTube(engine,
69                                        client().theExecutor(),
70                                        client().getSSLBufferSupplier()::recycle,
71                                        plainConnection.getConnectionFlow());
72                     return null;} );
73     }
74 
75     @Override
finishConnect()76     public CompletableFuture<Void> finishConnect() {
77         // The actual ALPN value, which may be the empty string, is not
78         // interesting at this point, only that the handshake has completed.
79         return getALPN()
80                 .handle((String unused, Throwable ex) -> {
81                     if (ex == null) {
82                         return plainConnection.finishConnect();
83                     } else {
84                         plainConnection.close();
85                         return MinimalFuture.<Void>failedFuture(ex);
86                     } })
87                 .thenCompose(Function.identity());
88     }
89 
90     @Override
91     boolean isTunnel() { return true; }
92 
93     @Override
94     boolean connected() {
95         return plainConnection.connected(); // && sslDelegate.connected();
96     }
97 
98     @Override
99     HttpPublisher publisher() { return writePublisher; }
100 
101     @Override
102     public String toString() {
103         return "AsyncSSLTunnelConnection: " + super.toString();
104     }
105 
106     @Override
107     ConnectionPool.CacheKey cacheKey() {
108         return ConnectionPool.cacheKey(address, plainConnection.proxyAddr);
109     }
110 
111     @Override
112     public void close() {
113         plainConnection.close();
114     }
115 
116     @Override
117     SocketChannel channel() {
118         return plainConnection.channel();
119     }
120 
121     @Override
122     boolean isProxied() {
123         return true;
124     }
125 
126     @Override
127     SSLTube getConnectionFlow() {
128        return flow;
129    }
130 }
131