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 2019/06/07 12:29:52 UTC

[httpcomponents-core] branch bug-fixes updated: Improved protocol I/O logging

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

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


The following commit(s) were added to refs/heads/bug-fixes by this push:
     new 6511775  Improved protocol I/O logging
6511775 is described below

commit 6511775e779e31ea4f7f1e86824daeb9c823cbdf
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Fri Jun 7 14:15:36 2019 +0200

    Improved protocol I/O logging
---
 .../impl/nio/bootstrap/H2RequesterBootstrap.java   |  7 +--
 .../impl/nio/bootstrap/H2ServerBootstrap.java      |  8 ++--
 .../impl/nio/bootstrap/Http2AsyncRequester.java    |  3 +-
 .../nio/bootstrap/Http2MultiplexingRequester.java  |  3 +-
 .../Http2MultiplexingRequesterBootstrap.java       |  7 ++-
 .../apache/hc/core5/benchmark/HttpBenchmark.java   | 44 ++++++++++++++++--
 .../hc/core5/testing/nio/LoggingIOSession.java     | 54 ++++++++++++++++++++--
 .../testing/nio/LoggingIOSessionDecorator.java     |  8 ++--
 .../testing/nio/LoggingIOSessionListener.java      | 31 ++++---------
 .../core5/http/impl/bootstrap/AsyncRequester.java  |  3 +-
 .../impl/bootstrap/AsyncRequesterBootstrap.java    |  7 +--
 .../hc/core5/http/impl/bootstrap/AsyncServer.java  |  3 +-
 .../http/impl/bootstrap/AsyncServerBootstrap.java  |  8 ++--
 .../http/impl/bootstrap/HttpAsyncRequester.java    |  3 +-
 .../core5/http/impl/bootstrap/HttpAsyncServer.java |  4 +-
 .../core5/reactor/DefaultConnectingIOReactor.java  |  2 +-
 .../core5/reactor/DefaultListeningIOReactor.java   |  2 +-
 .../hc/core5/reactor/InternalDataChannel.java      | 10 +---
 .../hc/core5/reactor/SingleCoreIOReactor.java      | 27 ++++-------
 19 files changed, 146 insertions(+), 88 deletions(-)

diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java
index 256c8a9..79d5d49 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2RequesterBootstrap.java
@@ -61,6 +61,7 @@ import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
@@ -87,7 +88,7 @@ public class H2RequesterBootstrap {
     private PoolConcurrencyPolicy poolConcurrencyPolicy;
     private TlsStrategy tlsStrategy;
     private Timeout handshakeTimeout;
-    private Decorator<IOSession> ioSessionDecorator;
+    private Decorator<ProtocolIOSession> ioSessionDecorator;
     private IOSessionListener sessionListener;
     private Http2StreamListener streamListener;
     private Http1StreamListener http1StreamListener;
@@ -195,9 +196,9 @@ public class H2RequesterBootstrap {
     }
 
     /**
-     * Assigns {@link IOSession} {@link Decorator} instance.
+     * Assigns {@link ProtocolIOSession} {@link Decorator} instance.
      */
-    public final H2RequesterBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
+    public final H2RequesterBootstrap setIOSessionDecorator(final Decorator<ProtocolIOSession> ioSessionDecorator) {
         this.ioSessionDecorator = ioSessionDecorator;
         return this;
     }
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
index 1a51590..649b775 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/H2ServerBootstrap.java
@@ -69,8 +69,8 @@ import org.apache.hc.core5.http2.ssl.H2ServerTlsStrategy;
 import org.apache.hc.core5.net.InetAddressUtils;
 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.Timeout;
 
@@ -93,7 +93,7 @@ public class H2ServerBootstrap {
     private H1Config h1Config;
     private TlsStrategy tlsStrategy;
     private Timeout handshakeTimeout;
-    private Decorator<IOSession> ioSessionDecorator;
+    private Decorator<ProtocolIOSession> ioSessionDecorator;
     private IOSessionListener sessionListener;
     private Http2StreamListener http2StreamListener;
     private Http1StreamListener http1StreamListener;
@@ -179,9 +179,9 @@ public class H2ServerBootstrap {
     }
 
     /**
-     * Assigns {@link IOSession} {@link Decorator} instance.
+     * Assigns {@link ProtocolIOSession} {@link Decorator} instance.
      */
-    public final H2ServerBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
+    public final H2ServerBootstrap setIOSessionDecorator(final Decorator<ProtocolIOSession> ioSessionDecorator) {
         this.ioSessionDecorator = ioSessionDecorator;
         return this;
     }
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2AsyncRequester.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2AsyncRequester.java
index 06c167a..128c100 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2AsyncRequester.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2AsyncRequester.java
@@ -41,6 +41,7 @@ import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Timeout;
 
 /**
@@ -61,7 +62,7 @@ public class Http2AsyncRequester extends HttpAsyncRequester {
             final HttpVersionPolicy versionPolicy,
             final IOReactorConfig ioReactorConfig,
             final IOEventHandlerFactory eventHandlerFactory,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final ManagedConnPool<HttpHost, IOSession> connPool) {
         super(ioReactorConfig, eventHandlerFactory, ioSessionDecorator, sessionListener, connPool);
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequester.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequester.java
index f3608a3..63bfbbf 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequester.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequester.java
@@ -71,6 +71,7 @@ import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
@@ -91,7 +92,7 @@ public class Http2MultiplexingRequester extends AsyncRequester{
     public Http2MultiplexingRequester(
             final IOReactorConfig ioReactorConfig,
             final IOEventHandlerFactory eventHandlerFactory,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final Resolver<HttpHost, InetSocketAddress> addressResolver,
             final TlsStrategy tlsStrategy) {
diff --git a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequesterBootstrap.java b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequesterBootstrap.java
index 2ec7801..afd7fc7 100644
--- a/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequesterBootstrap.java
+++ b/httpcore5-h2/src/main/java/org/apache/hc/core5/http2/impl/nio/bootstrap/Http2MultiplexingRequesterBootstrap.java
@@ -48,7 +48,6 @@ import org.apache.hc.core5.http2.ssl.H2ClientTlsStrategy;
 import org.apache.hc.core5.reactor.IOEventHandler;
 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
 import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Args;
@@ -68,7 +67,7 @@ public class Http2MultiplexingRequesterBootstrap {
     private H2Config h2Config;
     private TlsStrategy tlsStrategy;
     private boolean strictALPNHandshake;
-    private Decorator<IOSession> ioSessionDecorator;
+    private Decorator<ProtocolIOSession> ioSessionDecorator;
     private IOSessionListener sessionListener;
     private Http2StreamListener streamListener;
 
@@ -126,9 +125,9 @@ public class Http2MultiplexingRequesterBootstrap {
     }
 
     /**
-     * Assigns {@link IOSession} {@link Decorator} instance.
+     * Assigns {@link ProtocolIOSession} {@link Decorator} instance.
      */
-    public final Http2MultiplexingRequesterBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
+    public final Http2MultiplexingRequesterBootstrap setIOSessionDecorator(final Decorator<ProtocolIOSession> ioSessionDecorator) {
         this.ioSessionDecorator = ioSessionDecorator;
         return this;
     }
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
index e3a6c02..d8c1910 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
@@ -69,9 +69,15 @@ import org.apache.hc.core5.http2.protocol.H2RequestConnControl;
 import org.apache.hc.core5.http2.protocol.H2RequestContent;
 import org.apache.hc.core5.http2.protocol.H2RequestTargetHost;
 import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.net.NamedEndpoint;
 import org.apache.hc.core5.reactor.Command;
+import org.apache.hc.core5.reactor.IOEventHandler;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
+import org.apache.hc.core5.reactor.ssl.SSLBufferMode;
+import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
+import org.apache.hc.core5.reactor.ssl.SSLSessionVerifier;
+import org.apache.hc.core5.reactor.ssl.TlsDetails;
 import org.apache.hc.core5.ssl.SSLContextBuilder;
 import org.apache.hc.core5.ssl.SSLContexts;
 import org.apache.hc.core5.ssl.TrustStrategy;
@@ -172,11 +178,11 @@ public class HttpBenchmark {
                 .setHttpProcessor(builder.build())
                 .setTlsStrategy(new BasicClientTlsStrategy(sslContext))
                 .setVersionPolicy(versionPolicy)
-                .setIOSessionDecorator(new Decorator<IOSession>() {
+                .setIOSessionDecorator(new Decorator<ProtocolIOSession>() {
 
                     @Override
-                    public IOSession decorate(final IOSession ioSession) {
-                        return new IOSession() {
+                    public ProtocolIOSession decorate(final ProtocolIOSession ioSession) {
+                        return new ProtocolIOSession() {
 
                             @Override
                             public String getId() {
@@ -317,6 +323,36 @@ public class HttpBenchmark {
                                 ioSession.close(closeMode);
                             }
 
+                            @Override
+                            public NamedEndpoint getInitialEndpoint() {
+                                return ioSession.getInitialEndpoint();
+                            }
+
+                            @Override
+                            public IOEventHandler getHandler() {
+                                return ioSession.getHandler();
+                            }
+
+                            @Override
+                            public void upgrade(final IOEventHandler handler) {
+                                ioSession.upgrade(handler);
+                            }
+
+                            @Override
+                            public void startTls(final SSLContext sslContext,
+                                                 final NamedEndpoint endpoint,
+                                                 final SSLBufferMode sslBufferMode,
+                                                 final SSLSessionInitializer initializer,
+                                                 final SSLSessionVerifier verifier,
+                                                 final Timeout handshakeTimeout) throws UnsupportedOperationException {
+                                ioSession.startTls(
+                                        sslContext, endpoint, sslBufferMode, initializer, verifier, handshakeTimeout);
+                            }
+
+                            @Override
+                            public TlsDetails getTlsDetails() {
+                                return ioSession.getTlsDetails();
+                            }
                         };
                     }
 
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSession.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSession.java
index b29beb2..65acd74 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSession.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSession.java
@@ -34,21 +34,29 @@ import java.nio.channels.ByteChannel;
 import java.nio.channels.SelectionKey;
 import java.util.concurrent.locks.Lock;
 
+import javax.net.ssl.SSLContext;
+
 import org.apache.hc.core5.io.CloseMode;
+import org.apache.hc.core5.net.NamedEndpoint;
 import org.apache.hc.core5.reactor.Command;
-import org.apache.hc.core5.reactor.IOSession;
+import org.apache.hc.core5.reactor.IOEventHandler;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
+import org.apache.hc.core5.reactor.ssl.SSLBufferMode;
+import org.apache.hc.core5.reactor.ssl.SSLSessionInitializer;
+import org.apache.hc.core5.reactor.ssl.SSLSessionVerifier;
+import org.apache.hc.core5.reactor.ssl.TlsDetails;
 import org.apache.hc.core5.testing.classic.Wire;
 import org.apache.hc.core5.util.Timeout;
 import org.slf4j.Logger;
 
-public class LoggingIOSession implements IOSession {
+public class LoggingIOSession implements ProtocolIOSession {
 
     private final Logger log;
     private final Wire wireLog;
-    private final IOSession session;
+    private final ProtocolIOSession session;
     private final ByteChannel channel;
 
-    public LoggingIOSession(final IOSession session, final Logger log, final Logger wireLog) {
+    public LoggingIOSession(final ProtocolIOSession session, final Logger log, final Logger wireLog) {
         super();
         this.session = session;
         this.log = log;
@@ -56,7 +64,7 @@ public class LoggingIOSession implements IOSession {
         this.channel = wireLog != null ? new LoggingByteChannel() : session.channel();
     }
 
-    public LoggingIOSession(final IOSession session, final Logger log) {
+    public LoggingIOSession(final ProtocolIOSession session, final Logger log) {
         this(session, log, null);
     }
 
@@ -211,6 +219,42 @@ public class LoggingIOSession implements IOSession {
     }
 
     @Override
+    public NamedEndpoint getInitialEndpoint() {
+        return this.session.getInitialEndpoint();
+    }
+
+    @Override
+    public IOEventHandler getHandler() {
+        return this.session.getHandler();
+    }
+
+    @Override
+    public void upgrade(final IOEventHandler handler) {
+        if (this.log.isDebugEnabled()) {
+            this.log.debug(this.session + " Protocol upgrade: " + (handler != null ? handler.getClass() : null));
+        }
+        this.session.upgrade(handler);
+    }
+
+    @Override
+    public void startTls(final SSLContext sslContext,
+                         final NamedEndpoint endpoint,
+                         final SSLBufferMode sslBufferMode,
+                         final SSLSessionInitializer initializer,
+                         final SSLSessionVerifier verifier,
+                         final Timeout handshakeTimeout) throws UnsupportedOperationException {
+        if (this.log.isDebugEnabled()) {
+            this.log.debug(this.session + " Start TLS");
+        }
+        this.session.startTls(sslContext, endpoint, sslBufferMode, initializer, verifier, handshakeTimeout);
+    }
+
+    @Override
+    public TlsDetails getTlsDetails() {
+        return this.session.getTlsDetails();
+    }
+
+    @Override
     public String toString() {
         return this.session.toString();
     }
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionDecorator.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionDecorator.java
index ac33f40..4cf5994 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionDecorator.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionDecorator.java
@@ -28,11 +28,11 @@
 package org.apache.hc.core5.testing.nio;
 
 import org.apache.hc.core5.function.Decorator;
-import org.apache.hc.core5.reactor.IOSession;
-import org.slf4j.LoggerFactory;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class LoggingIOSessionDecorator implements Decorator<IOSession> {
+public class LoggingIOSessionDecorator implements Decorator<ProtocolIOSession> {
 
     public final static LoggingIOSessionDecorator INSTANCE = new LoggingIOSessionDecorator();
 
@@ -42,7 +42,7 @@ public class LoggingIOSessionDecorator implements Decorator<IOSession> {
     }
 
     @Override
-    public IOSession decorate(final IOSession ioSession) {
+    public ProtocolIOSession decorate(final ProtocolIOSession ioSession) {
         final Logger sessionLog = LoggerFactory.getLogger(ioSession.getClass());
         return new LoggingIOSession(ioSession, sessionLog, wireLog);
     }
diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java
index 6a785ca..988c9cb 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/testing/nio/LoggingIOSessionListener.java
@@ -28,7 +28,6 @@
 package org.apache.hc.core5.testing.nio;
 
 import org.apache.hc.core5.http.ConnectionClosedException;
-import org.apache.hc.core5.net.InetAddressUtils;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
 import org.apache.hc.core5.testing.classic.LoggingSupport;
@@ -47,49 +46,49 @@ public class LoggingIOSessionListener implements IOSessionListener {
     @Override
     public void tlsStarted(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " TLS session started: " + formatSession(session));
+            connLog.debug(session + " TLS session started");
         }
     }
 
     @Override
     public void tlsInbound(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " TLS inbound: " + formatSession(session));
+            connLog.debug(session + " TLS inbound");
         }
     }
 
     @Override
     public void tlsOutbound(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " TLS outbound: " + formatSession(session));
+            connLog.debug(session + " TLS outbound");
         }
     }
 
     @Override
     public void connected(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " connected: " + formatSession(session));
+            connLog.debug(session + " connected");
         }
     }
 
     @Override
     public void inputReady(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " input ready: " + formatSession(session));
+            connLog.debug(session + " input ready");
         }
     }
 
     @Override
     public void outputReady(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " output ready: " + formatSession(session));
+            connLog.debug(session + " output ready");
         }
     }
 
     @Override
     public void timeout(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " timeout: " + formatSession(session));
+            connLog.debug(session + " timeout");
         }
     }
 
@@ -98,26 +97,14 @@ public class LoggingIOSessionListener implements IOSessionListener {
         if (ex instanceof ConnectionClosedException) {
             return;
         }
-        connLog.error(LoggingSupport.getId(session) + " " + ex.getMessage(), ex);
+        connLog.error(session + " " + ex.getMessage(), ex);
     }
 
     @Override
     public void disconnected(final IOSession session) {
         if (connLog.isDebugEnabled()) {
-            connLog.debug(LoggingSupport.getId(session) + " disconnected");
+            connLog.debug(session + " disconnected");
         }
     }
 
-    private static String formatSession(final IOSession session) {
-        final StringBuilder buffer = new StringBuilder(90);
-        if (session.isClosed()) {
-            buffer.append("closed");
-        } else {
-            InetAddressUtils.formatAddress(buffer, session.getLocalAddress());
-            buffer.append("<->");
-            InetAddressUtils.formatAddress(buffer, session.getRemoteAddress());
-        }
-        return buffer.toString();
-    }
-
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequester.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequester.java
index f9a9beb..29a2983 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequester.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequester.java
@@ -50,6 +50,7 @@ import org.apache.hc.core5.reactor.IOReactorService;
 import org.apache.hc.core5.reactor.IOReactorStatus;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
@@ -68,7 +69,7 @@ public class AsyncRequester extends AbstractConnectionInitiatorBase implements I
     public AsyncRequester(
             final IOEventHandlerFactory eventHandlerFactory,
             final IOReactorConfig ioReactorConfig,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final Callback<IOSession> sessionShutdownCallback,
             final Resolver<HttpHost, InetSocketAddress> addressResolver) {
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequesterBootstrap.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequesterBootstrap.java
index 1432394..06b9e49 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequesterBootstrap.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncRequesterBootstrap.java
@@ -49,6 +49,7 @@ import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Timeout;
 
 /**
@@ -70,7 +71,7 @@ public class AsyncRequesterBootstrap {
     private PoolConcurrencyPolicy poolConcurrencyPolicy;
     private TlsStrategy tlsStrategy;
     private Timeout handshakeTimeout;
-    private Decorator<IOSession> ioSessionDecorator;
+    private Decorator<ProtocolIOSession> ioSessionDecorator;
     private IOSessionListener sessionListener;
     private Http1StreamListener streamListener;
     private ConnPoolListener<HttpHost> connPoolListener;
@@ -168,9 +169,9 @@ public class AsyncRequesterBootstrap {
     }
 
     /**
-     * Assigns {@link IOSession} {@link Decorator} instance.
+     * Assigns {@link ProtocolIOSession} {@link Decorator} instance.
      */
-    public final AsyncRequesterBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
+    public final AsyncRequesterBootstrap setIOSessionDecorator(final Decorator<ProtocolIOSession> ioSessionDecorator) {
         this.ioSessionDecorator = ioSessionDecorator;
         return this;
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServer.java
index 04a4630..4eb09c5 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServer.java
@@ -50,6 +50,7 @@ import org.apache.hc.core5.reactor.IOReactorStatus;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
 import org.apache.hc.core5.reactor.ListenerEndpoint;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.TimeValue;
 
 /**
@@ -63,7 +64,7 @@ public class AsyncServer extends AbstractConnectionInitiatorBase implements IORe
     public AsyncServer(
             final IOEventHandlerFactory eventHandlerFactory,
             final IOReactorConfig ioReactorConfig,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final Callback<IOSession> sessionShutdownCallback) {
         this.ioReactor = new DefaultListeningIOReactor(
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java
index 2efe675..509ea98 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/AsyncServerBootstrap.java
@@ -62,8 +62,8 @@ import org.apache.hc.core5.http.protocol.UriPatternType;
 import org.apache.hc.core5.net.InetAddressUtils;
 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.Timeout;
 
@@ -85,7 +85,7 @@ public class AsyncServerBootstrap {
     private ConnectionReuseStrategy connStrategy;
     private TlsStrategy tlsStrategy;
     private Timeout handshakeTimeout;
-    private Decorator<IOSession> ioSessionDecorator;
+    private Decorator<ProtocolIOSession> ioSessionDecorator;
     private IOSessionListener sessionListener;
     private Http1StreamListener streamListener;
 
@@ -163,9 +163,9 @@ public class AsyncServerBootstrap {
     }
 
     /**
-     * Assigns {@link IOSession} {@link Decorator} instance.
+     * Assigns {@link ProtocolIOSession} {@link Decorator} instance.
      */
-    public final AsyncServerBootstrap setIOSessionDecorator(final Decorator<IOSession> ioSessionDecorator) {
+    public final AsyncServerBootstrap setIOSessionDecorator(final Decorator<ProtocolIOSession> ioSessionDecorator) {
         this.ioSessionDecorator = ioSessionDecorator;
         return this;
     }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncRequester.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncRequester.java
index 13dafe5..0dff2f7 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncRequester.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncRequester.java
@@ -72,6 +72,7 @@ import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
 import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
@@ -92,7 +93,7 @@ public class HttpAsyncRequester extends AsyncRequester implements ConnPoolContro
     public HttpAsyncRequester(
             final IOReactorConfig ioReactorConfig,
             final IOEventHandlerFactory eventHandlerFactory,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final ManagedConnPool<HttpHost, IOSession> connPool) {
         super(eventHandlerFactory, ioReactorConfig, ioSessionDecorator, sessionListener,
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncServer.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncServer.java
index 46c1cbd..e965742 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncServer.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpAsyncServer.java
@@ -31,8 +31,8 @@ import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.http.nio.command.ShutdownCommand;
 import org.apache.hc.core5.reactor.IOEventHandlerFactory;
 import org.apache.hc.core5.reactor.IOReactorConfig;
-import org.apache.hc.core5.reactor.IOSession;
 import org.apache.hc.core5.reactor.IOSessionListener;
+import org.apache.hc.core5.reactor.ProtocolIOSession;
 
 /**
  * HTTP/1.1 server side message exchange handler.
@@ -48,7 +48,7 @@ public class HttpAsyncServer extends AsyncServer {
     public HttpAsyncServer(
             final IOEventHandlerFactory eventHandlerFactory,
             final IOReactorConfig ioReactorConfig,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener) {
         super(eventHandlerFactory, ioReactorConfig, ioSessionDecorator, sessionListener,
                         ShutdownCommand.GRACEFUL_NORMAL_CALLBACK);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultConnectingIOReactor.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultConnectingIOReactor.java
index a421ecb..1b10cde 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultConnectingIOReactor.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultConnectingIOReactor.java
@@ -65,7 +65,7 @@ public class DefaultConnectingIOReactor extends AbstractIOReactorBase {
             final IOEventHandlerFactory eventHandlerFactory,
             final IOReactorConfig ioReactorConfig,
             final ThreadFactory threadFactory,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final Callback<IOSession> sessionShutdownCallback) {
         Args.notNull(eventHandlerFactory, "Event handler factory");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultListeningIOReactor.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultListeningIOReactor.java
index 64500c9..aad2664 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultListeningIOReactor.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/DefaultListeningIOReactor.java
@@ -83,7 +83,7 @@ public class DefaultListeningIOReactor extends AbstractIOReactorBase implements
             final IOReactorConfig ioReactorConfig,
             final ThreadFactory dispatchThreadFactory,
             final ThreadFactory listenerThreadFactory,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final Callback<IOSession> sessionShutdownCallback) {
         Args.notNull(eventHandlerFactory, "Event handler factory");
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/InternalDataChannel.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/InternalDataChannel.java
index 61b3207..c2f78f5 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/InternalDataChannel.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/InternalDataChannel.java
@@ -395,18 +395,12 @@ final class InternalDataChannel extends InternalChannel implements ProtocolIOSes
 
     @Override
     public String toString() {
-        final StringBuilder buf = new StringBuilder();
         final SSLIOSession tlsSession = tlsSessionRef.get();
         if (tlsSession != null) {
-            buf.append(tlsSession);
+            return tlsSession.toString();
         } else {
-            buf.append(ioSession);
+            return ioSession.toString();
         }
-        final IOEventHandler handler = getHandler();
-        if (handler != null) {
-            buf.append(handler);
-        }
-        return buf.toString();
     }
 
 }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
index 412ce30..b36f16a 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
@@ -45,7 +45,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.hc.core5.concurrent.FutureCallback;
 import org.apache.hc.core5.function.Callback;
 import org.apache.hc.core5.function.Decorator;
-import org.apache.hc.core5.io.CloseMode;
 import org.apache.hc.core5.io.Closer;
 import org.apache.hc.core5.net.NamedEndpoint;
 import org.apache.hc.core5.util.Args;
@@ -57,7 +56,7 @@ class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements Connect
 
     private final IOEventHandlerFactory eventHandlerFactory;
     private final IOReactorConfig reactorConfig;
-    private final Decorator<IOSession> ioSessionDecorator;
+    private final Decorator<ProtocolIOSession> ioSessionDecorator;
     private final IOSessionListener sessionListener;
     private final Callback<IOSession> sessionShutdownCallback;
     private final Queue<InternalDataChannel> closedSessions;
@@ -71,7 +70,7 @@ class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements Connect
             final Queue<ExceptionEvent> auditLog,
             final IOEventHandlerFactory eventHandlerFactory,
             final IOReactorConfig reactorConfig,
-            final Decorator<IOSession> ioSessionDecorator,
+            final Decorator<ProtocolIOSession> ioSessionDecorator,
             final IOSessionListener sessionListener,
             final Callback<IOSession> sessionShutdownCallback) {
         super(auditLog);
@@ -170,11 +169,7 @@ class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements Connect
     private void processEvents(final Set<SelectionKey> selectedKeys) {
         for (final SelectionKey key : selectedKeys) {
             final InternalChannel channel = (InternalChannel) key.attachment();
-            try {
-                channel.handleIOEvent(key.readyOps());
-            } catch (final CancelledKeyException ex) {
-                channel.close(CloseMode.GRACEFUL);
-            }
+            channel.handleIOEvent(key.readyOps());
         }
         selectedKeys.clear();
     }
@@ -200,12 +195,10 @@ class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements Connect
             } catch (final ClosedChannelException ex) {
                 return;
             }
-            IOSession ioSession = new IOSessionImpl(key, socketChannel);
-            if (ioSessionDecorator != null) {
-                ioSession = ioSessionDecorator.decorate(ioSession);
-            }
+            final IOSession ioSession = new IOSessionImpl(key, socketChannel);
             final InternalDataChannel dataChannel = new InternalDataChannel(ioSession, null, sessionListener, closedSessions);
-            dataChannel.upgrade(this.eventHandlerFactory.createHandler(dataChannel, null));
+            final ProtocolIOSession protocolSession = ioSessionDecorator != null ? ioSessionDecorator.decorate(dataChannel) : dataChannel;
+            dataChannel.upgrade(this.eventHandlerFactory.createHandler(protocolSession, null));
             dataChannel.setSocketTimeout(this.reactorConfig.getSoTimeout());
             key.attach(dataChannel);
             dataChannel.handleIOEvent(SelectionKey.OP_CONNECT);
@@ -337,12 +330,10 @@ class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements Connect
                     final SocketChannel socketChannel,
                     final NamedEndpoint namedEndpoint,
                     final Object attachment) {
-                IOSession ioSession = new IOSessionImpl(key, socketChannel);
-                if (ioSessionDecorator != null) {
-                    ioSession = ioSessionDecorator.decorate(ioSession);
-                }
+                final IOSession ioSession = new IOSessionImpl(key, socketChannel);
                 final InternalDataChannel dataChannel = new InternalDataChannel(ioSession, namedEndpoint, sessionListener, closedSessions);
-                dataChannel.upgrade(eventHandlerFactory.createHandler(dataChannel, attachment));
+                final ProtocolIOSession protocolSession = ioSessionDecorator != null ? ioSessionDecorator.decorate(dataChannel) : dataChannel;
+                dataChannel.upgrade(eventHandlerFactory.createHandler(protocolSession, attachment));
                 dataChannel.setSocketTimeout(reactorConfig.getSoTimeout());
                 return dataChannel;
             }