1 /* 2 * Copyright (c) 2015, 2017, 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.incubator.http; 27 28 import java.io.IOException; 29 import java.io.UncheckedIOException; 30 import java.net.InetSocketAddress; 31 import java.nio.ByteBuffer; 32 import java.nio.channels.SocketChannel; 33 import java.util.concurrent.CompletableFuture; 34 import javax.net.ssl.SSLEngineResult.Status; 35 import javax.net.ssl.SSLParameters; 36 import jdk.incubator.http.SSLDelegate.WrapperResult; 37 38 import jdk.incubator.http.internal.common.ByteBufferReference; 39 import jdk.incubator.http.internal.common.Utils; 40 41 /** 42 * An SSL tunnel built on a Plain (CONNECT) TCP tunnel. 43 */ 44 class SSLTunnelConnection extends HttpConnection { 45 46 final PlainTunnelingConnection delegate; 47 protected SSLDelegate sslDelegate; 48 private volatile boolean connected; 49 final String serverName; 50 51 @Override 52 public void connect() throws IOException, InterruptedException { 53 delegate.connect(); 54 this.sslDelegate = new SSLDelegate(delegate.channel(), client, null, serverName); 55 connected = true; 56 } 57 58 @Override 59 boolean connected() { 60 return connected && delegate.connected(); 61 } 62 63 @Override 64 public CompletableFuture<Void> connectAsync() { 65 return delegate.connectAsync() 66 .thenAccept((Void v) -> { 67 try { 68 // can this block? 69 this.sslDelegate = new SSLDelegate(delegate.channel(), 70 client, 71 null, serverName); 72 connected = true; 73 } catch (IOException e) { 74 throw new UncheckedIOException(e); 75 } 76 }); 77 } 78 79 SSLTunnelConnection(InetSocketAddress addr, 80 HttpClientImpl client, 81 InetSocketAddress proxy) 82 { 83 super(addr, client); 84 this.serverName = Utils.getServerName(addr); 85 delegate = new PlainTunnelingConnection(addr, proxy, client); 86 } 87 88 /** 89 * Create an SSLTunnelConnection from an existing connected AsyncSSLTunnelConnection. 90 * Used when downgrading from HTTP/2 to HTTP/1.1 91 */ 92 SSLTunnelConnection(AsyncSSLTunnelConnection c) { 93 super(c.address, c.client); 94 this.delegate = c.plainConnection(); 95 AsyncSSLDelegate adel = c.sslDelegate(); 96 this.sslDelegate = new SSLDelegate(adel.engine, delegate.channel(), client, adel.serverName); 97 this.serverName = adel.serverName; 98 connected = c.connected(); 99 } 100 101 @Override 102 SSLParameters sslParameters() { 103 return sslDelegate.getSSLParameters(); 104 } 105 106 @Override 107 public String toString() { 108 return "SSLTunnelConnection: " + super.toString(); 109 } 110 111 private static long countBytes(ByteBuffer[] buffers, int start, int number) { 112 long c = 0; 113 for (int i=0; i<number; i++) { 114 c+= buffers[start+i].remaining(); 115 } 116 return c; 117 } 118 119 @Override 120 ConnectionPool.CacheKey cacheKey() { 121 return ConnectionPool.cacheKey(address, delegate.proxyAddr); 122 } 123 124 @Override 125 long write(ByteBuffer[] buffers, int start, int number) throws IOException { 126 //debugPrint("Send", buffers, start, number); 127 long l = countBytes(buffers, start, number); 128 WrapperResult r = sslDelegate.sendData(buffers, start, number); 129 if (r.result.getStatus() == Status.CLOSED) { 130 if (l > 0) { 131 throw new IOException("SSLHttpConnection closed"); 132 } 133 } 134 return l; 135 } 136 137 @Override 138 long write(ByteBuffer buffer) throws IOException { 139 //debugPrint("Send", buffer); 140 long l = buffer.remaining(); 141 WrapperResult r = sslDelegate.sendData(buffer); 142 if (r.result.getStatus() == Status.CLOSED) { 143 if (l > 0) { 144 throw new IOException("SSLHttpConnection closed"); 145 } 146 } 147 return l; 148 } 149 150 @Override 151 void writeAsync(ByteBufferReference[] buffers) throws IOException { 152 write(ByteBufferReference.toBuffers(buffers), 0, buffers.length); 153 } 154 155 @Override 156 void writeAsyncUnordered(ByteBufferReference[] buffers) throws IOException { 157 write(ByteBufferReference.toBuffers(buffers), 0, buffers.length); 158 } 159 160 @Override 161 void flushAsync() throws IOException { 162 // nothing to do 163 } 164 165 @Override 166 public void close() { 167 Utils.close(delegate.channel()); 168 } 169 170 @Override 171 void shutdownInput() throws IOException { 172 delegate.channel().shutdownInput(); 173 } 174 175 @Override 176 void shutdownOutput() throws IOException { 177 delegate.channel().shutdownOutput(); 178 } 179 180 @Override 181 protected ByteBuffer readImpl() throws IOException { 182 ByteBuffer buf = Utils.getBuffer(); 183 184 WrapperResult r = sslDelegate.recvData(buf); 185 return r.buf; 186 } 187 188 @Override 189 SocketChannel channel() { 190 return delegate.channel(); 191 } 192 193 @Override 194 CompletableFuture<Void> whenReceivingResponse() { 195 return delegate.whenReceivingResponse(); 196 } 197 198 @Override 199 boolean isSecure() { 200 return true; 201 } 202 203 @Override 204 boolean isProxied() { 205 return true; 206 } 207 }