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