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 2024/07/08 13:57:25 UTC

(httpcomponents-core) branch 5.2.x updated: Attempt to shut down the connection gracefully in case of a TLS handshake exception

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

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


The following commit(s) were added to refs/heads/5.2.x by this push:
     new 8be0cf2ad Attempt to shut down the connection gracefully in case of a TLS handshake exception
8be0cf2ad is described below

commit 8be0cf2ad1cde0776da5cfb508240c42d77e1e2d
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Fri Jul 5 16:57:15 2024 +0200

    Attempt to shut down the connection gracefully in case of a TLS handshake exception
---
 .../impl/nio/AbstractH2StreamMultiplexer.java      |  3 +++
 .../http/impl/nio/AbstractHttp1StreamDuplexer.java |  3 +++
 .../apache/hc/core5/reactor/ssl/SSLIOSession.java  | 22 ++++++++++++++++------
 3 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java
index 03ac7302e..3066cc346 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/AbstractH2StreamMultiplexer.java
@@ -42,6 +42,7 @@ import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLSession;
 
 import org.apache.hc.core5.concurrent.CancellableDependency;
@@ -698,6 +699,8 @@ abstract class AbstractH2StreamMultiplexer implements Identifiable, HttpConnecti
             final CloseMode closeMode;
             if (cause instanceof ConnectionClosedException) {
                 closeMode = CloseMode.GRACEFUL;
+            } else if (cause instanceof SSLHandshakeException) {
+                closeMode = CloseMode.GRACEFUL;
             } else if (cause instanceof IOException) {
                 closeMode = CloseMode.IMMEDIATE;
             } else {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
index 90684952f..60fb8f886 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/nio/AbstractHttp1StreamDuplexer.java
@@ -36,6 +36,7 @@ import java.nio.channels.WritableByteChannel;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLSession;
 
 import org.apache.hc.core5.http.ConnectionClosedException;
@@ -165,6 +166,8 @@ abstract class AbstractHttp1StreamDuplexer<IncomingMessage extends HttpMessage,
             final CloseMode closeMode;
             if (cause instanceof ConnectionClosedException) {
                 closeMode = CloseMode.GRACEFUL;
+            } else if (cause instanceof SSLHandshakeException) {
+                closeMode = CloseMode.GRACEFUL;
             } else if (cause instanceof IOException) {
                 closeMode = CloseMode.IMMEDIATE;
             } else {
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 ae0c1882b..b48c49543 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
@@ -232,8 +232,12 @@ public class SSLIOSession implements IOSession {
                 }
                 final IOEventHandler handler = session.getHandler();
                 if (handshakeStateRef.get() != TLSHandShakeState.COMPLETE) {
-                    session.close(CloseMode.GRACEFUL);
-                    close(CloseMode.IMMEDIATE);
+                    if (cause instanceof SSLHandshakeException) {
+                        close(CloseMode.GRACEFUL);
+                    } else {
+                        session.close(CloseMode.GRACEFUL);
+                        close(CloseMode.IMMEDIATE);
+                    }
                 }
                 if (handler != null) {
                     handler.exception(protocolSession, cause);
@@ -467,13 +471,17 @@ public class SSLIOSession implements IOSession {
                 this.sslEngine.closeOutbound();
                 this.outboundClosedCount.incrementAndGet();
             }
-            if (this.status == Status.CLOSING && this.sslEngine.isOutboundDone()
+            final HandshakeStatus handshakeStatus = this.sslEngine.getHandshakeStatus();
+            if (this.status == Status.CLOSING
+                    && (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING || handshakeStatus == HandshakeStatus.FINISHED)
+                    && !this.outEncrypted.hasData()
+                    && this.sslEngine.isOutboundDone()
                     && (this.endOfStream || this.sslEngine.isInboundDone())) {
                 this.status = Status.CLOSED;
             }
             // Abnormal session termination
             if (this.status.compareTo(Status.CLOSING) <= 0 && this.endOfStream
-                    && this.sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) {
+                    && handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
                 this.status = Status.CLOSED;
             }
             if (this.status == Status.CLOSED) {
@@ -484,7 +492,7 @@ public class SSLIOSession implements IOSession {
                 return;
             }
             // Is there a task pending?
-            if (this.sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            if (handshakeStatus == HandshakeStatus.NEED_TASK) {
                 doRunTask();
             }
             // Need to toggle the event mask for this channel?
@@ -527,7 +535,7 @@ public class SSLIOSession implements IOSession {
     private int sendEncryptedData() throws IOException {
         this.session.getLock().lock();
         try {
-            if (!this.outEncrypted.hasData()) {
+            if (this.status == Status.ACTIVE && !this.outEncrypted.hasData()) {
                 // If the buffer isn't acquired or is empty, call write() with an empty buffer.
                 // This will ensure that tests performed by write() still take place without
                 // having to acquire and release an empty buffer (e.g. connection closed,
@@ -719,6 +727,8 @@ public class SSLIOSession implements IOSession {
                     // in the JSSE provider. For instance
                     // com.android.org.conscrypt.NativeCrypto#SSL_get_shutdown can
                     // throw NPE at this point
+                    doHandshake(this);
+                    sendEncryptedData();
                     updateEventMask();
                 } catch (final CancelledKeyException ex) {
                     this.session.close(CloseMode.GRACEFUL);