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