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