< prev index next >

src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/AbstractAsyncSSLConnection.java

Print this page

        

@@ -26,13 +26,23 @@
 package jdk.incubator.http;
 
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
-import jdk.incubator.http.internal.common.ExceptionallyCloseable;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLParameters;
+
+import jdk.incubator.http.internal.common.SSLTube;
+import jdk.incubator.http.internal.common.Log;
+import jdk.incubator.http.internal.common.Utils;
 
 
 /**
  * Asynchronous version of SSLConnection.
  *

@@ -50,36 +60,129 @@
  *       a single class - and simply use different factory methods to
  *       create different wrappees, but this is left up for further cleanup.
  *
  */
 abstract class AbstractAsyncSSLConnection extends HttpConnection
-               implements AsyncConnection, ExceptionallyCloseable {
-
-
-    AbstractAsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client) {
+{
+    protected final SSLEngine engine;
+    protected final String serverName;
+    protected final SSLParameters sslParameters;
+
+    AbstractAsyncSSLConnection(InetSocketAddress addr,
+                               HttpClientImpl client,
+                               String serverName,
+                               String[] alpn) {
         super(addr, client);
+        this.serverName = serverName;
+        SSLContext context = client.theSSLContext();
+        sslParameters = createSSLParameters(client, serverName, alpn);
+        Log.logParams(sslParameters);
+        engine = createEngine(context, sslParameters);
     }
 
-    abstract SSLEngine getEngine();
-    abstract AsyncSSLDelegate sslDelegate();
     abstract HttpConnection plainConnection();
-    abstract HttpConnection downgrade();
+    abstract SSLTube getConnectionFlow();
+
+    final CompletableFuture<String> getALPN() {
+        assert connected();
+        return getConnectionFlow().getALPN();
+    }
+
+    final SSLEngine getEngine() { return engine; }
+
+    private static SSLParameters createSSLParameters(HttpClientImpl client,
+                                                     String serverName,
+                                                     String[] alpn) {
+        SSLParameters sslp = client.sslParameters();
+        SSLParameters sslParameters = Utils.copySSLParameters(sslp);
+        if (alpn != null) {
+            Log.logSSL("AbstractAsyncSSLConnection: Setting application protocols: {0}",
+                       Arrays.toString(alpn));
+            sslParameters.setApplicationProtocols(alpn);
+        } else {
+            Log.logSSL("AbstractAsyncSSLConnection: no applications set!");
+        }
+        if (serverName != null) {
+            sslParameters.setServerNames(List.of(new SNIHostName(serverName)));
+        }
+        return sslParameters;
+    }
+
+    private static SSLEngine createEngine(SSLContext context,
+                                          SSLParameters sslParameters) {
+        SSLEngine engine = context.createSSLEngine();
+        engine.setUseClientMode(true);
+        engine.setSSLParameters(sslParameters);
+        return engine;
+    }
 
     @Override
     final boolean isSecure() {
         return true;
     }
 
-    // Blocking read functions not used here
+    // Support for WebSocket/RawChannelImpl which unfortunately
+    // still depends on synchronous read/writes.
+    // It should be removed when RawChannelImpl moves to using asynchronous APIs.
+    static final class SSLConnectionChannel extends DetachedConnectionChannel {
+        final DetachedConnectionChannel delegate;
+        final SSLDelegate sslDelegate;
+        SSLConnectionChannel(DetachedConnectionChannel delegate, SSLDelegate sslDelegate) {
+            this.delegate = delegate;
+            this.sslDelegate = sslDelegate;
+        }
+
+        SocketChannel channel() {
+            return delegate.channel();
+        }
+
+        @Override
+        ByteBuffer read() throws IOException {
+            SSLDelegate.WrapperResult r = sslDelegate.recvData(ByteBuffer.allocate(8192));
+            // TODO: check for closure
+            int n = r.result.bytesProduced();
+            if (n > 0) {
+                return r.buf;
+            } else if (n == 0) {
+                return Utils.EMPTY_BYTEBUFFER;
+            } else {
+                return null;
+            }
+        }
+        @Override
+        long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+            long l = SSLDelegate.countBytes(buffers, start, number);
+            SSLDelegate.WrapperResult r = sslDelegate.sendData(buffers, start, number);
+            if (r.result.getStatus() == SSLEngineResult.Status.CLOSED) {
+                if (l > 0) {
+                    throw new IOException("SSLHttpConnection closed");
+                }
+            }
+            return l;
+        }
+        @Override
+        public void shutdownInput() throws IOException {
+            delegate.shutdownInput();
+        }
     @Override
-    protected final ByteBuffer readImpl() throws IOException {
-        throw new UnsupportedOperationException("Not supported.");
+        public void shutdownOutput() throws IOException {
+            delegate.shutdownOutput();
+        }
+        @Override
+        public void close() {
+            delegate.close();
+        }
     }
 
-    // whenReceivedResponse only used in HTTP/1.1 (Http1Exchange)
-    // AbstractAsyncSSLConnection is only used with HTTP/2
+    // Support for WebSocket/RawChannelImpl which unfortunately
+    // still depends on synchronous read/writes.
+    // It should be removed when RawChannelImpl moves to using asynchronous APIs.
     @Override
-    final CompletableFuture<Void> whenReceivingResponse() {
-        throw new UnsupportedOperationException("Not supported.");
+    DetachedConnectionChannel detachChannel() {
+        assert client() != null;
+        DetachedConnectionChannel detachedChannel = plainConnection().detachChannel();
+        SSLDelegate sslDelegate = new SSLDelegate(engine,
+                                                  detachedChannel.channel());
+        return new SSLConnectionChannel(detachedChannel, sslDelegate);
     }
 
 }
< prev index next >