You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2020/12/02 10:42:36 UTC

[httpcomponents-core] branch master updated: Bug fix: do not attempt to shut down non-blocking TLS session gracefully in case the TLS handshake has not been fully completed

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git


The following commit(s) were added to refs/heads/master by this push:
     new 21d06c4  Bug fix: do not attempt to shut down non-blocking TLS session gracefully in case the TLS handshake has not been fully completed
21d06c4 is described below

commit 21d06c483a2a2624d17c769aef8ea3b0604714b9
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sun Nov 29 11:41:41 2020 +0100

    Bug fix: do not attempt to shut down non-blocking TLS session gracefully in case the TLS handshake has not been fully completed
---
 .../hc/core5/testing/nio/H2TLSIntegrationTest.java | 11 -----------
 .../apache/hc/core5/reactor/ssl/SSLIOSession.java  | 22 ++++++++++++++--------
 2 files changed, 14 insertions(+), 19 deletions(-)

diff --git a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java
index 5dcc7f8..0833c57 100644
--- a/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java
+++ b/httpcore5-testing/src/test/java/org/apache/hc/core5/testing/nio/H2TLSIntegrationTest.java
@@ -70,12 +70,9 @@ import org.apache.hc.core5.reactor.ssl.TlsDetails;
 import org.apache.hc.core5.ssl.SSLContexts;
 import org.apache.hc.core5.testing.SSLTestContexts;
 import org.apache.hc.core5.testing.classic.LoggingConnPoolListener;
-import org.apache.hc.core5.util.ReflectionUtils;
 import org.apache.hc.core5.util.Timeout;
 import org.hamcrest.CoreMatchers;
 import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExternalResource;
@@ -118,13 +115,6 @@ public class H2TLSIntegrationTest {
 
     };
 
-    private static int javaVersion;
-
-    @BeforeClass
-    public static void determineJavaVersion() {
-        javaVersion = ReflectionUtils.determineJRELevel();
-    }
-
     @Test
     public void testTLSSuccess() throws Exception {
         server = AsyncServerBootstrap.bootstrap()
@@ -387,7 +377,6 @@ public class H2TLSIntegrationTest {
 
     @Test
     public void testWeakCiphersDisabledByDefault() throws Exception {
-        Assume.assumeTrue("Java version must be 1.8 or lesser",  javaVersion <= 8);
         requester = H2RequesterBootstrap.bootstrap()
                 .setIOReactorConfig(IOReactorConfig.custom()
                         .setSoTimeout(TIMEOUT)
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java
index 8530858..b5d34a9 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/ssl/SSLIOSession.java
@@ -35,6 +35,7 @@ import java.nio.channels.CancelledKeyException;
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.SelectionKey;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.Lock;
 
 import javax.net.ssl.SSLContext;
@@ -70,6 +71,8 @@ import org.apache.hc.core5.util.Timeout;
 @Internal
 public class SSLIOSession implements IOSession {
 
+    enum TLSHandShakeState { READY, INITIALIZED, HANDSHAKING, COMPLETE }
+
     private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
 
     private final NamedEndpoint targetEndpoint;
@@ -85,13 +88,13 @@ public class SSLIOSession implements IOSession {
     private final Timeout connectTimeout;
     private final SSLMode sslMode;
     private final AtomicInteger outboundClosedCount;
+    private final AtomicReference<TLSHandShakeState> handshakeStateRef;
     private final IOEventHandler internalEventHandler;
 
     private int appEventMask;
 
     private volatile boolean endOfStream;
     private volatile Status status = Status.ACTIVE;
-    private volatile boolean initialized;
     private volatile Timeout socketTimeout;
     private volatile TlsDetails tlsDetails;
 
@@ -148,19 +151,20 @@ public class SSLIOSession implements IOSession {
         final int appBufferSize = sslSession.getApplicationBufferSize();
         this.inPlain = SSLManagedBuffer.create(sslBufferMode, appBufferSize);
         this.outboundClosedCount = new AtomicInteger(0);
+        this.handshakeStateRef = new AtomicReference<>(TLSHandShakeState.READY);
         this.connectTimeout = connectTimeout;
         this.internalEventHandler = new IOEventHandler() {
 
             @Override
             public void connected(final IOSession protocolSession) throws IOException {
-                if (!initialized) {
+                if (handshakeStateRef.compareAndSet(TLSHandShakeState.READY, TLSHandShakeState.INITIALIZED)) {
                     initialize();
                 }
             }
 
             @Override
             public void inputReady(final IOSession protocolSession, final ByteBuffer src) throws IOException {
-                if (!initialized) {
+                if (handshakeStateRef.compareAndSet(TLSHandShakeState.READY, TLSHandShakeState.INITIALIZED)) {
                     initialize();
                 }
                 receiveEncryptedData();
@@ -171,7 +175,7 @@ public class SSLIOSession implements IOSession {
 
             @Override
             public void outputReady(final IOSession protocolSession) throws IOException {
-                if (!initialized) {
+                if (handshakeStateRef.compareAndSet(TLSHandShakeState.READY, TLSHandShakeState.INITIALIZED)) {
                     initialize();
                 }
                 encryptData();
@@ -192,6 +196,10 @@ public class SSLIOSession implements IOSession {
             @Override
             public void exception(final IOSession protocolSession, final Exception cause) {
                 final IOEventHandler handler = session.getHandler();
+                if (handshakeStateRef.get() != TLSHandShakeState.COMPLETE) {
+                    session.close(CloseMode.GRACEFUL);
+                    close(CloseMode.IMMEDIATE);
+                }
                 if (handler != null) {
                     handler.exception(SSLIOSession.this, cause);
                 }
@@ -221,8 +229,6 @@ public class SSLIOSession implements IOSession {
     }
 
     private void initialize() throws IOException {
-        Asserts.check(!this.initialized, "SSL I/O session already initialized");
-
         // Save the initial socketTimeout of the underlying IOSession, to be restored after the handshake is finished
         this.socketTimeout = this.session.getSocketTimeout();
         if (connectTimeout != null) {
@@ -245,7 +251,7 @@ public class SSLIOSession implements IOSession {
             if (this.initializer != null) {
                 this.initializer.initialize(this.targetEndpoint, this.sslEngine);
             }
-            this.initialized = true;
+            this.handshakeStateRef.set(TLSHandShakeState.HANDSHAKING);
             this.sslEngine.beginHandshake();
 
             this.inEncrypted.release();
@@ -592,7 +598,7 @@ public class SSLIOSession implements IOSession {
             if (this.status != Status.ACTIVE) {
                 throw new ClosedChannelException();
             }
-            if (!this.initialized) {
+            if (this.handshakeStateRef.get() == TLSHandShakeState.READY) {
                 return 0;
             }
             final ByteBuffer outEncryptedBuf = this.outEncrypted.acquire();