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.net.InetSocketAddress; 30 import java.nio.ByteBuffer; 31 import java.util.concurrent.CompletableFuture; 32 import javax.net.ssl.SSLEngine; 33 import jdk.incubator.http.internal.common.ExceptionallyCloseable; 34 35 36 /** 37 * Asynchronous version of SSLConnection. 38 * 39 * There are two concrete implementations of this class: AsyncSSLConnection 40 * and AsyncSSLTunnelConnection. 41 * This abstraction is useful when downgrading from HTTP/2 to HTTP/1.1 over 42 * an SSL connection. See ExchangeImpl::get in the case where an ALPNException 43 * is thrown. 44 * 45 * Note: An AsyncSSLConnection wraps a PlainHttpConnection, while an 46 * AsyncSSLTunnelConnection wraps a PlainTunnelingConnection. 47 * If both these wrapped classes where made to inherit from a 48 * common abstraction then it might be possible to merge 49 * AsyncSSLConnection and AsyncSSLTunnelConnection back into 50 * a single class - and simply use different factory methods to 51 * create different wrappees, but this is left up for further cleanup. 52 * 53 */ 54 abstract class AbstractAsyncSSLConnection extends HttpConnection 55 implements AsyncConnection, ExceptionallyCloseable { 56 57 58 AbstractAsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client) { 59 super(addr, client); 60 } 61 62 abstract SSLEngine getEngine(); 63 abstract AsyncSSLDelegate sslDelegate(); 64 abstract HttpConnection plainConnection(); 65 abstract HttpConnection downgrade(); 66 67 @Override 68 final boolean isSecure() { 69 return true; 70 } 71 72 // Blocking read functions not used here 73 @Override 74 protected final ByteBuffer readImpl() throws IOException { 75 throw new UnsupportedOperationException("Not supported."); 76 } 77 78 // whenReceivedResponse only used in HTTP/1.1 (Http1Exchange) 79 // AbstractAsyncSSLConnection is only used with HTTP/2 80 @Override 81 final CompletableFuture<Void> whenReceivingResponse() { 82 throw new UnsupportedOperationException("Not supported."); 83 } 84 85 } | 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.net.InetSocketAddress; 30 import java.nio.ByteBuffer; 31 import java.nio.channels.SocketChannel; 32 import java.util.Arrays; 33 import java.util.List; 34 import java.util.concurrent.CompletableFuture; 35 import javax.net.ssl.SNIHostName; 36 import javax.net.ssl.SSLContext; 37 import javax.net.ssl.SSLEngine; 38 import javax.net.ssl.SSLEngineResult; 39 import javax.net.ssl.SSLParameters; 40 41 import jdk.incubator.http.internal.common.SSLTube; 42 import jdk.incubator.http.internal.common.Log; 43 import jdk.incubator.http.internal.common.Utils; 44 45 46 /** 47 * Asynchronous version of SSLConnection. 48 * 49 * There are two concrete implementations of this class: AsyncSSLConnection 50 * and AsyncSSLTunnelConnection. 51 * This abstraction is useful when downgrading from HTTP/2 to HTTP/1.1 over 52 * an SSL connection. See ExchangeImpl::get in the case where an ALPNException 53 * is thrown. 54 * 55 * Note: An AsyncSSLConnection wraps a PlainHttpConnection, while an 56 * AsyncSSLTunnelConnection wraps a PlainTunnelingConnection. 57 * If both these wrapped classes where made to inherit from a 58 * common abstraction then it might be possible to merge 59 * AsyncSSLConnection and AsyncSSLTunnelConnection back into 60 * a single class - and simply use different factory methods to 61 * create different wrappees, but this is left up for further cleanup. 62 * 63 */ 64 abstract class AbstractAsyncSSLConnection extends HttpConnection 65 { 66 protected final SSLEngine engine; 67 protected final String serverName; 68 protected final SSLParameters sslParameters; 69 70 AbstractAsyncSSLConnection(InetSocketAddress addr, 71 HttpClientImpl client, 72 String serverName, 73 String[] alpn) { 74 super(addr, client); 75 this.serverName = serverName; 76 SSLContext context = client.theSSLContext(); 77 sslParameters = createSSLParameters(client, serverName, alpn); 78 Log.logParams(sslParameters); 79 engine = createEngine(context, sslParameters); 80 } 81 82 abstract HttpConnection plainConnection(); 83 abstract SSLTube getConnectionFlow(); 84 85 final CompletableFuture<String> getALPN() { 86 assert connected(); 87 return getConnectionFlow().getALPN(); 88 } 89 90 final SSLEngine getEngine() { return engine; } 91 92 private static SSLParameters createSSLParameters(HttpClientImpl client, 93 String serverName, 94 String[] alpn) { 95 SSLParameters sslp = client.sslParameters(); 96 SSLParameters sslParameters = Utils.copySSLParameters(sslp); 97 if (alpn != null) { 98 Log.logSSL("AbstractAsyncSSLConnection: Setting application protocols: {0}", 99 Arrays.toString(alpn)); 100 sslParameters.setApplicationProtocols(alpn); 101 } else { 102 Log.logSSL("AbstractAsyncSSLConnection: no applications set!"); 103 } 104 if (serverName != null) { 105 sslParameters.setServerNames(List.of(new SNIHostName(serverName))); 106 } 107 return sslParameters; 108 } 109 110 private static SSLEngine createEngine(SSLContext context, 111 SSLParameters sslParameters) { 112 SSLEngine engine = context.createSSLEngine(); 113 engine.setUseClientMode(true); 114 engine.setSSLParameters(sslParameters); 115 return engine; 116 } 117 118 @Override 119 final boolean isSecure() { 120 return true; 121 } 122 123 // Support for WebSocket/RawChannelImpl which unfortunately 124 // still depends on synchronous read/writes. 125 // It should be removed when RawChannelImpl moves to using asynchronous APIs. 126 static final class SSLConnectionChannel extends DetachedConnectionChannel { 127 final DetachedConnectionChannel delegate; 128 final SSLDelegate sslDelegate; 129 SSLConnectionChannel(DetachedConnectionChannel delegate, SSLDelegate sslDelegate) { 130 this.delegate = delegate; 131 this.sslDelegate = sslDelegate; 132 } 133 134 SocketChannel channel() { 135 return delegate.channel(); 136 } 137 138 @Override 139 ByteBuffer read() throws IOException { 140 SSLDelegate.WrapperResult r = sslDelegate.recvData(ByteBuffer.allocate(8192)); 141 // TODO: check for closure 142 int n = r.result.bytesProduced(); 143 if (n > 0) { 144 return r.buf; 145 } else if (n == 0) { 146 return Utils.EMPTY_BYTEBUFFER; 147 } else { 148 return null; 149 } 150 } 151 @Override 152 long write(ByteBuffer[] buffers, int start, int number) throws IOException { 153 long l = SSLDelegate.countBytes(buffers, start, number); 154 SSLDelegate.WrapperResult r = sslDelegate.sendData(buffers, start, number); 155 if (r.result.getStatus() == SSLEngineResult.Status.CLOSED) { 156 if (l > 0) { 157 throw new IOException("SSLHttpConnection closed"); 158 } 159 } 160 return l; 161 } 162 @Override 163 public void shutdownInput() throws IOException { 164 delegate.shutdownInput(); 165 } 166 @Override 167 public void shutdownOutput() throws IOException { 168 delegate.shutdownOutput(); 169 } 170 @Override 171 public void close() { 172 delegate.close(); 173 } 174 } 175 176 // Support for WebSocket/RawChannelImpl which unfortunately 177 // still depends on synchronous read/writes. 178 // It should be removed when RawChannelImpl moves to using asynchronous APIs. 179 @Override 180 DetachedConnectionChannel detachChannel() { 181 assert client() != null; 182 DetachedConnectionChannel detachedChannel = plainConnection().detachChannel(); 183 SSLDelegate sslDelegate = new SSLDelegate(engine, 184 detachedChannel.channel()); 185 return new SSLConnectionChannel(detachedChannel, sslDelegate); 186 } 187 188 } |