Repository: netty/netty
Issue: WebSocketServerProtocolHandler breaks ChannelHandler's exceptionCaught behavior
Labels: defect

`WebSocketServerProtocolHandler` overrides `exceptionCaught` method. If an exception happens in the pipeline before `WebSocketServerProtocolHandler` it closes the channel, leaving the Handlers that follow it unable to handle the `Exception`.
This is the `WebSocketServerProtocolHandler's` `exceptionCaught` code:

``` java
@Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (cause instanceof WebSocketHandshakeException) {
            FullHttpResponse response = new DefaultFullHttpResponse(
                    HTTP_1_1, HttpResponseStatus.BAD_REQUEST, Unpooled.wrappedBuffer(cause.getMessage().getBytes()));
            ctx.channel().writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        } else {
            ctx.close();
        }
    }
```

This is my scenario: after an successful handshake, the server has this pipeline:
`Pipeline = [wsdecoder, wsencoder, WS403Responder, WebSocketServerProtocolHandler, domainHandler, DefaultChannelPipeline$TailContext#0]`

My server logic is in domainHandler. I set `maxFrameSize` in `WebSocketServerProtocolHandler` to be 1MB. If I send a file bigger than this wsdecoder (`WebSocket08FrameDecoder`) calls protocolViolation, which sends an `CloseWebSocketFrame` to the client and throws an `CorruptedFrameException`. This exception is then captured by `WebSocketServerProtocolHandler's` `exceptionCaught` that closes the channel and doesn't call the next handler's `exceptionCaught` (my domain handler) leaving me no chance to change the behavior.

This is the `WebSocket08FrameDecoder's` `protocolViolation` code:

``` java
private void protocolViolation(ChannelHandlerContext ctx, CorruptedFrameException ex) {
        state = State.CORRUPT;
        if (ctx.channel().isActive()) {
            Object closeMessage;
            if (receivedClosingHandshake) {
                closeMessage = Unpooled.EMPTY_BUFFER;
            } else {
                closeMessage = new CloseWebSocketFrame(1002, null);
            }
            ctx.writeAndFlush(closeMessage).addListener(ChannelFutureListener.CLOSE);
        }
        throw ex;
    }
```

Thanks for this amazing framework, I'm learning a lot thanks to you :-)

Saludos.


Issue comments:
Investigating more on this issue, I found out that due to the channel being closed right after sending the `CloseWebSocketFrame`, the client is unable to process the `CloseWebSocketFrame`, rising an `Exception` while trying to process it (as far as I'm able to reason). I have, both in the client and the server, an `ActivityLoggingHandler` that logs the channel activity using SLF4J (without breaking the events flow through the pipeline). The exception thrown is this:

```
17:42:57.136 [nioEventLoopGroup-2-1] WARN  e.u.t.r.s.c.c.ActivityLoggingHandler - Caught exception procesing data from server /127.0.0.1:8080
java.io.IOException: Connection reset by peer
    at sun.nio.ch.FileDispatcherImpl.read0(Native Method) ~[na:1.7.0_65]
    at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39) ~[na:1.7.0_65]
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223) ~[na:1.7.0_65]
    at sun.nio.ch.IOUtil.read(IOUtil.java:192) ~[na:1.7.0_65]
    at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:379) ~[na:1.7.0_65]
    at io.netty.buffer.UnpooledUnsafeDirectByteBuf.setBytes(UnpooledUnsafeDirectByteBuf.java:446) ~[netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:878) ~[netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:225) ~[netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:114) ~[netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:507) [netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:464) [netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:378) [netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:350) [netty-all-4.0.20.Final.jar:4.0.20.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) [netty-all-4.0.20.Final.jar:4.0.20.Final]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_65]
17:42:57.137 [nioEventLoopGroup-2-1] INFO  e.u.t.r.s.c.c.ActivityLoggingHandler - Server /127.0.0.1:8080 closed the connection.
```

Saludos!

I also observed this XXX and YYY both consume exceptions.  My simple fix is just to override exceptionCaught with:

```
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
      try {
        // Allow the pipeline to deal with the exception before the parent.
        ctx.fireExceptionCaught(cause);
      } finally {
        super.exceptionCaught(ctx, cause);
      }
    }
```

Before this fixed, I get a closed channel with no explanation:
```
java.lang.Exception: connection closed
	at com.civitaslearning.phonehome.server.TunnelServerBootstrapConfiguration$ServerTunnelChannelInitializer.lambda$initChannel$0(TunnelServerBootstrapConfiguration.java:186) ~[main/:?]
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:507) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:500) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:479) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:420) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:104) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPromise.trySuccess(DefaultChannelPromise.java:82) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannel$CloseFuture.setClosed(AbstractChannel.java:1058) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.doClose0(AbstractChannel.java:686) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:664) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannel$AbstractUnsafe.close(AbstractChannel.java:607) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.close(DefaultChannelPipeline.java:1276) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.logging.LoggingHandler.close(LoggingHandler.java:217) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler$8.operationComplete(SslHandler.java:1630) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler$8.operationComplete(SslHandler.java:1619) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:507) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:481) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:420) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.addListener(DefaultPromise.java:163) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:93) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:28) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler.safeClose(SslHandler.java:1619) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler.closeOutboundAndChannel(SslHandler.java:1430) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler.close(SslHandler.java:575) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelOutboundHandlerAdapter.close(ChannelOutboundHandlerAdapter.java:71) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelDuplexHandler.close(ChannelDuplexHandler.java:73) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelOutboundHandlerAdapter.close(ChannelOutboundHandlerAdapter.java:71) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelDuplexHandler.close(ChannelDuplexHandler.java:73) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelDuplexHandler.close(ChannelDuplexHandler.java:73) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelDuplexHandler.close(ChannelDuplexHandler.java:73) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.logging.LoggingHandler.close(LoggingHandler.java:217) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeClose(AbstractChannelHandlerContext.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:608) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.close(AbstractChannelHandlerContext.java:465) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPipeline.close(DefaultChannelPipeline.java:964) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannel.close(AbstractChannel.java:234) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelFutureListener$1.operationComplete(ChannelFutureListener.java:44) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.ChannelFutureListener$1.operationComplete(ChannelFutureListener.java:41) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:507) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:481) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:420) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultPromise.addListener(DefaultPromise.java:163) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:93) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPromise.addListener(DefaultChannelPromise.java:28) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.protocolViolation(WebSocket08FrameDecoder.java:424) [netty-codec-http-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.protocolViolation(WebSocket08FrameDecoder.java:412) [netty-codec-http-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.decode(WebSocket08FrameDecoder.java:277) [netty-codec-http-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) [netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) [netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1240) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1041) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) [netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) [netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:233) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:559) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:476) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_121]
```

After the fix, I get a clear stack trace showing the error:
```
io.netty.handler.codec.CorruptedFrameException: Max frame length of 65536 has been exceeded.
	at io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.protocolViolation(WebSocket08FrameDecoder.java:412) ~[netty-codec-http-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.decode(WebSocket08FrameDecoder.java:277) ~[netty-codec-http-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) ~[netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) ~[netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1240) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1041) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:411) [netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:248) [netty-codec-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:233) [netty-handler-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:624) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:559) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:476) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:438) [netty-transport-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144) [netty-common-4.1.9.Final.jar:4.1.9.Final]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_121]
```

I got this because compression was, in some cases _increasing_ the size of the message, and I was creating messages with sizes exactly equal to the max frame size.  I'm going to open another bug about that -- it seems that compression should be dropped if it leads to a larger frame.
I want to improve this -- the silent close bit our project twice, once when it was 100% our own fault caused by a mis-configuration between client and server and a silent close only for large messages and once because of #6663.  I see 2 easy and one harder solution, and I am not at all sure which one makes most sense:

1. (trivial) Add a simple warn (or info?) message when the close happens, particularly when caused by a protocol violation or similar which can be caused by simple misconfiguration.
2. (trivial) Re-fire the exceptionCaught event and then close, with our without try/finally.
3. (harder) Alter implementations of `WebSocketFrameDecoder`to avoid throwing known errors, since they are caught and swallowed in `WebSocketProtocolHandler`/`WebSocketProtocolServerHandler`, anyway.  Instead, just log and close there.  Note that `WebSocket08FrameDecoder#protocolViolation` closes the channel after the response, anyway.

Please advise.  If there's a better solution, I'm happing implementing that, too.
I think 2) would be fine @mkw . Thanks!
Fixed by https://github.com/netty/netty/pull/6688

Pull request review comments:

Patch that resolved the issue:
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java
index bb150e39b09..7037ae34686 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketProtocolHandler.java
@@ -39,6 +39,7 @@ protected void decode(ChannelHandlerContext ctx, WebSocketFrame frame, List<Obje
 
     @Override
     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        ctx.fireExceptionCaught(cause);
         ctx.close();
     }
 }
diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java
index e6e7e38b74e..6b5ef13af53 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocketServerProtocolHandler.java
@@ -178,6 +178,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E
                     HTTP_1_1, HttpResponseStatus.BAD_REQUEST, Unpooled.wrappedBuffer(cause.getMessage().getBytes()));
             ctx.channel().writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
         } else {
+            ctx.fireExceptionCaught(cause);
             ctx.close();
         }
     }


Test patch: