public override void ChannelActive(IChannelHandlerContext ctx)
            {
                CompositeBufferPartialWriteDoesNotCorruptDataInitServerConfig(ctx.Channel.Configuration, _soSndBuf);
                // First single write
                int offset = _soSndBuf - 100;

                ctx.WriteAsync(_expectedContent.RetainedSlice(_expectedContent.ReaderIndex, offset));

                // Build and write CompositeByteBuf
                CompositeByteBuffer compositeByteBuf = ctx.Allocator.CompositeBuffer();

                compositeByteBuf.AddComponent(true,
                                              _expectedContent.RetainedSlice(_expectedContent.ReaderIndex + offset, 50));
                offset += 50;
                compositeByteBuf.AddComponent(true,
                                              _expectedContent.RetainedSlice(_expectedContent.ReaderIndex + offset, 200));
                offset += 200;
                ctx.WriteAsync(compositeByteBuf);

                // Write a single buffer that is smaller than the second component of the CompositeByteBuf
                // above but small enough to fit in the remaining space allowed by the soSndBuf amount.
                ctx.WriteAsync(_expectedContent.RetainedSlice(_expectedContent.ReaderIndex + offset, 50));
                offset += 50;

                // Write the remainder of the content
                ctx.WriteAndFlushAsync(_expectedContent.RetainedSlice(_expectedContent.ReaderIndex + offset,
                                                                      _expectedContent.ReadableBytes - _expectedContent.ReaderIndex - offset))
                .CloseOnComplete(ctx.Channel);
            }
Beispiel #2
0
        static IByteBuffer NewCompositeBuffer(IByteBufferAllocator alloc)
        {
            CompositeByteBuffer compositeByteBuf = alloc.CompositeBuffer();

            compositeByteBuf.AddComponent(true, alloc.DirectBuffer(4).WriteInt(100));
            compositeByteBuf.AddComponent(true, alloc.DirectBuffer(8).WriteLong(123));
            compositeByteBuf.AddComponent(true, alloc.DirectBuffer(8).WriteLong(456));
            Assert.Equal(ExpectedBytes, compositeByteBuf.ReadableBytes);
            return(compositeByteBuf);
        }
        public void RemoveLastComponentWithOthersLeft()
        {
            CompositeByteBuffer buf = Unpooled.CompositeBuffer();

            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 1, 2 }));
            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 1, 2 }));
            Assert.Equal(2, buf.NumComponents);
            buf.RemoveComponent(1);
            Assert.Equal(1, buf.NumComponents);
            buf.Release();
        }
Beispiel #4
0
        public void TestNioBuffersMaxCount()
        {
            TestChannel channel = new TestChannel();

            ChannelOutboundBuffer buffer = new ChannelOutboundBuffer(channel);

            CompositeByteBuffer comp = Unpooled.CompositeBuffer(256);
            IByteBuffer         buf  = Unpooled.DirectBuffer().WriteBytes(Encoding.ASCII.GetBytes("buf1"));

            for (int i = 0; i < 65; i++)
            {
                comp.AddComponent(true, buf.Copy());
            }
            Assert.Equal(65, comp.IoBufferCount);
            buffer.AddMessage(comp, comp.ReadableBytes, channel.VoidPromise());
            Assert.Equal(0, buffer.NioBufferCount); // Should still be 0 as not flushed yet
            buffer.AddFlush();
            int maxCount = 10;                      // less than comp.nioBufferCount()
            var buffers  = buffer.GetSharedBufferList(maxCount, int.MaxValue);

            Assert.True(buffer.NioBufferCount <= maxCount); // Should not be greater than maxCount
            for (int i = 0; i < buffer.NioBufferCount; i++)
            {
                Assert.Equal(buffers[i], buf.GetIoBuffer(buf.ReaderIndex, buf.ReadableBytes));
            }
            Release(buffer);
            buf.Release();
        }
        public void FullConsolidation()
        {
            CompositeByteBuffer buf = Unpooled.CompositeBuffer(int.MaxValue);

            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 1 }));
            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 2, 3 }));
            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 4, 5, 6 }));
            buf.Consolidate();

            Assert.Equal(1, buf.NumComponents);
            Assert.True(buf.HasArray);
            Assert.NotNull(buf.Array);
            Assert.Equal(0, buf.ArrayOffset);

            buf.Release();
        }
Beispiel #6
0
        public void TestNioBuffersExpand2()
        {
            TestChannel channel = new TestChannel();

            ChannelOutboundBuffer buffer = new ChannelOutboundBuffer(channel);

            CompositeByteBuffer comp = Unpooled.CompositeBuffer(256);
            IByteBuffer         buf  = Unpooled.DirectBuffer().WriteBytes(Encoding.ASCII.GetBytes("buf1"));

            for (int i = 0; i < 65; i++)
            {
                comp.AddComponent(true, buf.Copy());
            }
            buffer.AddMessage(comp, comp.ReadableBytes, channel.VoidPromise());

            Assert.Equal(0, buffer.NioBufferCount); // Should still be 0 as not flushed yet
            buffer.AddFlush();
            var buffers = buffer.GetSharedBufferList();

            Assert.Equal(65, buffer.NioBufferCount);
            for (int i = 0; i < buffer.NioBufferCount; i++)
            {
                if (i < 65)
                {
                    Assert.Equal(buffers[i], buf.GetIoBuffer(buf.ReaderIndex, buf.ReadableBytes));
                }
                else
                {
                    Assert.Null(buffers[i].Array);
                }
            }
            Release(buffer);
            buf.Release();
        }
        public void RangedConsolidation()
        {
            CompositeByteBuffer buf = Unpooled.CompositeBuffer(int.MaxValue);

            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 1 }));
            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 2, 3 }));
            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 4, 5, 6 }));
            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 7, 8, 9, 10 }));
            buf.Consolidate(1, 2);

            Assert.Equal(3, buf.NumComponents);
            Assert.Equal(Unpooled.WrappedBuffer(new byte[] { 1 }), buf[0]);
            Assert.Equal(Unpooled.WrappedBuffer(new byte[] { 2, 3, 4, 5, 6 }), buf[1]);
            Assert.Equal(Unpooled.WrappedBuffer(new byte[] { 7, 8, 9, 10 }), buf[2]);

            buf.Release();
        }
Beispiel #8
0
        private IByteBuffer CompressContent(IChannelHandlerContext ctx, WebSocketFrame msg)
        {
            if (_encoder is null)
            {
                _encoder = new EmbeddedChannel(
                    ZlibCodecFactory.NewZlibEncoder(
                        ZlibWrapper.None,
                        _compressionLevel,
                        _windowSize,
                        8));
            }

            _ = _encoder.WriteOutbound(msg.Content.Retain());

            CompositeByteBuffer fullCompressedContent = ctx.Allocator.CompositeBuffer();

            while (true)
            {
                var partCompressedContent = _encoder.ReadOutbound <IByteBuffer>();
                if (partCompressedContent is null)
                {
                    break;
                }

                if (!partCompressedContent.IsReadable())
                {
                    _ = partCompressedContent.Release();
                    continue;
                }

                _ = fullCompressedContent.AddComponent(true, partCompressedContent);
            }

            if (fullCompressedContent.NumComponents <= 0)
            {
                _ = fullCompressedContent.Release();
                ThrowHelper.ThrowCodecException_CannotReadCompressedBuf();
            }

            if (msg.IsFinalFragment && _noContext)
            {
                Cleanup();
            }

            IByteBuffer compressedContent;

            if (RemoveFrameTail(msg))
            {
                int realLength = fullCompressedContent.ReadableBytes - FrameTail.ReadableBytes;
                compressedContent = fullCompressedContent.Slice(0, realLength);
            }
            else
            {
                compressedContent = fullCompressedContent;
            }
            return(compressedContent);
        }
        public void AddEmptyBufferInMiddle()
        {
            CompositeByteBuffer cbuf = Unpooled.CompositeBuffer();
            IByteBuffer         buf1 = Unpooled.Buffer().WriteByte(1);

            cbuf.AddComponent(true, buf1);
            cbuf.AddComponent(true, Unpooled.Empty);
            IByteBuffer buf3 = Unpooled.Buffer().WriteByte(2);

            cbuf.AddComponent(true, buf3);

            Assert.Equal(2, cbuf.ReadableBytes);
            Assert.Equal((byte)1, cbuf.ReadByte());
            Assert.Equal((byte)2, cbuf.ReadByte());

            Assert.Same(Unpooled.Empty, cbuf.InternalComponent(1));
            Assert.NotSame(Unpooled.Empty, cbuf.InternalComponentAtOffset(1));
            cbuf.Release();
        }
        public void ComponentMustBeDuplicate()
        {
            CompositeByteBuffer buf = Unpooled.CompositeBuffer();

            buf.AddComponent(Unpooled.Buffer(4, 6).SetIndex(1, 3));
            Assert.IsAssignableFrom <AbstractDerivedByteBuffer>(buf[0]);
            Assert.Equal(4, buf[0].Capacity);
            Assert.Equal(6, buf[0].MaxCapacity);
            Assert.Equal(2, buf[0].ReadableBytes);
            buf.Release();
        }
        public void AddEmptyBufferRelease()
        {
            CompositeByteBuffer cbuf = Unpooled.CompositeBuffer();
            IByteBuffer         buf  = Unpooled.Buffer();

            Assert.Equal(1, buf.ReferenceCount);
            cbuf.AddComponent(buf);
            Assert.Equal(1, buf.ReferenceCount);

            cbuf.Release();
            Assert.Equal(0, buf.ReferenceCount);
        }
        public void CompositeToSingleBuffer()
        {
            CompositeByteBuffer buf = Unpooled.CompositeBuffer(3);

            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 1, 2, 3 }));
            Assert.Equal(1, buf.NumComponents);

            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 4 }));
            Assert.Equal(2, buf.NumComponents);

            buf.AddComponent(Unpooled.WrappedBuffer(new byte[] { 5, 6 }));
            Assert.Equal(3, buf.NumComponents);

            // NOTE: hard-coding 6 here, since it seems like addComponent doesn't bump the writer index.
            // I'm unsure as to whether or not this is correct behavior
            ArraySegment <byte> nioBuffer = buf.GetIoBuffer(0, 6);

            Assert.Equal(6, nioBuffer.Count);
            Assert.True(nioBuffer.Array.SequenceEqual(new byte[] { 1, 2, 3, 4, 5, 6 }));

            buf.Release();
        }
        public void NestedLayout()
        {
            CompositeByteBuffer buf = Unpooled.CompositeBuffer();

            buf.AddComponent(
                Unpooled.CompositeBuffer()
                .AddComponent(Unpooled.WrappedBuffer(new byte[] { 1, 2 }))
                .AddComponent(Unpooled.WrappedBuffer(new byte[] { 3, 4 })).Slice(1, 2));

            ArraySegment <byte>[] nioBuffers = buf.GetIoBuffers(0, 2);
            Assert.Equal(2, nioBuffers.Length);
            Assert.Equal((byte)2, nioBuffers[0].Array[nioBuffers[0].Offset]);
            Assert.Equal((byte)3, nioBuffers[1].Array[nioBuffers[1].Offset]);
            buf.Release();
        }
Beispiel #14
0
        public static ReadableBuffer Composite(IEnumerable <ReadableBuffer> buffers)
        {
            Contract.Requires(buffers != null);

            CompositeByteBuffer composite = Unpooled.CompositeBuffer();

            foreach (ReadableBuffer buf in buffers)
            {
                IByteBuffer byteBuffer = buf.buffer;
                if (byteBuffer.ReadableBytes > 0)
                {
                    composite.AddComponent(byteBuffer);
                }
            }

            return(new ReadableBuffer(composite));
        }
        static void AppendPartialContent(CompositeByteBuffer content, IByteBuffer partialContent)
        {
            Contract.Requires(content != null);
            Contract.Requires(partialContent != null);

            if (!partialContent.IsReadable())
            {
                return;
            }

            var buffer = (IByteBuffer)partialContent.Retain();

            content.AddComponent(buffer);

            // Note that WriterIndex must be manually increased
            content.SetWriterIndex(content.WriterIndex + buffer.ReadableBytes);
        }
        public void ForEachByteUnderLeakDetectionShouldNotThrowException()
        {
            CompositeByteBuffer buf = (CompositeByteBuffer)NewBuffer(8);

            Assert.True(buf is SimpleLeakAwareCompositeByteBuffer);
            CompositeByteBuffer comp = (CompositeByteBuffer)NewBuffer(8);

            Assert.True(comp is SimpleLeakAwareCompositeByteBuffer);

            IByteBuffer inner = comp.Allocator.DirectBuffer(1).WriteByte(0);

            comp.AddComponent(true, inner);
            buf.AddComponent(true, comp);

            Assert.Equal(-1, buf.ForEachByte(new AlwaysByteProcessor()));
            Assert.True(buf.Release());
        }
        public void DiscardSomeReadBytes()
        {
            CompositeByteBuffer cbuf = Unpooled.CompositeBuffer();
            int len = 8 * 4;

            for (int i = 0; i < len; i += 4)
            {
                IByteBuffer buf = Unpooled.Buffer().WriteInt(i);
                cbuf.AdjustCapacity(cbuf.WriterIndex);
                cbuf.AddComponent(buf).SetWriterIndex(i + 4);
            }
            cbuf.WriteByte(1);

            var me = new byte[len];

            cbuf.ReadBytes(me);
            cbuf.ReadByte();

            cbuf.DiscardSomeReadBytes();
            cbuf.Release();
        }
Beispiel #18
0
        void TestHttpResponseAndFrameInSameBuffer(bool codec)
        {
            string url = "ws://localhost:9999/ws";
            WebSocketClientHandshaker shaker = this.NewHandshaker(new Uri(url));
            var handshaker = new Handshaker(shaker);

            // use randomBytes helper from utils to check that it functions properly
            byte[] data = WebSocketUtil.RandomBytes(24);

            // Create a EmbeddedChannel which we will use to encode a BinaryWebsocketFrame to bytes and so use these
            // to test the actual handshaker.
            var factory = new WebSocketServerHandshakerFactory(url, null, false);
            IFullHttpRequest          request = shaker.NewHandshakeRequest();
            WebSocketServerHandshaker socketServerHandshaker = factory.NewHandshaker(request);

            request.Release();
            var websocketChannel = new EmbeddedChannel(socketServerHandshaker.NewWebSocketEncoder(),
                                                       socketServerHandshaker.NewWebsocketDecoder());

            Assert.True(websocketChannel.WriteOutbound(new BinaryWebSocketFrame(Unpooled.WrappedBuffer(data))));

            byte[] bytes = Encoding.ASCII.GetBytes("HTTP/1.1 101 Switching Protocols\r\nContent-Length: 0\r\n\r\n");

            CompositeByteBuffer compositeByteBuf = Unpooled.CompositeBuffer();

            compositeByteBuf.AddComponent(true, Unpooled.WrappedBuffer(bytes));
            for (; ;)
            {
                var frameBytes = websocketChannel.ReadOutbound <IByteBuffer>();
                if (frameBytes == null)
                {
                    break;
                }
                compositeByteBuf.AddComponent(true, frameBytes);
            }

            var ch = new EmbeddedChannel(new HttpObjectAggregator(int.MaxValue), new Handler(handshaker));

            if (codec)
            {
                ch.Pipeline.AddFirst(new HttpClientCodec());
            }
            else
            {
                ch.Pipeline.AddFirst(new HttpRequestEncoder(), new HttpResponseDecoder());
            }

            // We need to first write the request as HttpClientCodec will fail if we receive a response before a request
            // was written.
            shaker.HandshakeAsync(ch).Wait();
            for (; ;)
            {
                // Just consume the bytes, we are not interested in these.
                var buf = ch.ReadOutbound <IByteBuffer>();
                if (buf == null)
                {
                    break;
                }
                buf.Release();
            }
            Assert.True(ch.WriteInbound(compositeByteBuf));
            Assert.True(ch.Finish());

            var         frame  = ch.ReadInbound <BinaryWebSocketFrame>();
            IByteBuffer expect = Unpooled.WrappedBuffer(data);

            try
            {
                Assert.Equal(expect, frame.Content);
                Assert.True(frame.IsFinalFragment);
                Assert.Equal(0, frame.Rsv);
            }
            finally
            {
                expect.Release();
                frame.Release();
            }
        }
Beispiel #19
0
        protected internal override void Decode(IChannelHandlerContext ctx, WebSocketFrame msg, List <object> output)
        {
            if (this.decoder == null)
            {
                if (!(msg is TextWebSocketFrame) && !(msg is BinaryWebSocketFrame))
                {
                    throw new CodecException($"unexpected initial frame type: {msg.GetType().Name}");
                }

                this.decoder = new EmbeddedChannel(ZlibCodecFactory.NewZlibDecoder(ZlibWrapper.None));
            }

            bool readable = msg.Content.IsReadable();

            this.decoder.WriteInbound(msg.Content.Retain());
            if (this.AppendFrameTail(msg))
            {
                this.decoder.WriteInbound(Unpooled.WrappedBuffer(FrameTail));
            }

            CompositeByteBuffer compositeUncompressedContent = ctx.Allocator.CompositeDirectBuffer();

            for (;;)
            {
                var partUncompressedContent = this.decoder.ReadInbound <IByteBuffer>();
                if (partUncompressedContent == null)
                {
                    break;
                }

                if (!partUncompressedContent.IsReadable())
                {
                    partUncompressedContent.Release();
                    continue;
                }

                compositeUncompressedContent.AddComponent(true, partUncompressedContent);
            }

            // Correctly handle empty frames
            // See https://github.com/netty/netty/issues/4348
            if (readable && compositeUncompressedContent.NumComponents <= 0)
            {
                compositeUncompressedContent.Release();
                throw new CodecException("cannot read uncompressed buffer");
            }

            if (msg.IsFinalFragment && this.noContext)
            {
                this.Cleanup();
            }

            WebSocketFrame outMsg;

            if (msg is TextWebSocketFrame)
            {
                outMsg = new TextWebSocketFrame(msg.IsFinalFragment, this.NewRsv(msg), compositeUncompressedContent);
            }
            else if (msg is BinaryWebSocketFrame)
            {
                outMsg = new BinaryWebSocketFrame(msg.IsFinalFragment, this.NewRsv(msg), compositeUncompressedContent);
            }
            else if (msg is ContinuationWebSocketFrame)
            {
                outMsg = new ContinuationWebSocketFrame(msg.IsFinalFragment, this.NewRsv(msg), compositeUncompressedContent);
            }
            else
            {
                throw new CodecException($"unexpected frame type: {msg.GetType().Name}");
            }

            output.Add(outMsg);
        }
        /// <summary>
        /// Flush the content of the given buffer to the remote peer.
        /// </summary>
        /// <param name="channelOutboundBuffer">The buffer to write to the remote peer.</param>
        protected override async void DoWrite(ChannelOutboundBuffer channelOutboundBuffer)
        {
            if (Logging.IsEnabled)
            {
                Logging.Enter(this, nameof(DoWrite));
            }

            if (channelOutboundBuffer == null)
            {
                throw new ArgumentNullException(nameof(channelOutboundBuffer), "The channel outbound buffer cannot be null.");
            }

            try
            {
                // The ChannelOutboundBuffer might have more than one message per MQTT packet that needs to be written to the websocket as a single frame.
                // One example of this is a PUBLISH packet, which encodes the payload and topic information as separate messages.
                // In order to reduce the number of frames sent to the websocket, we will consolidate the individual messages per MQTT packet into a single byte buffer.
                IByteBufferAllocator allocator = Configuration.Allocator;

                // The parameter "direct" is used to indicate if operations carried out in the CompositeByteBuffer should be treated as "unsafe".
                var compositeByteBuffer = new CompositeByteBuffer(allocator, direct: false, maxNumComponents: int.MaxValue);

                var bytesToBeWritten = new ArraySegment <byte>();
                _isWriteInProgress = true;

                while (true)
                {
                    object currentMessage = channelOutboundBuffer.Current;

                    // Once there are no more messages pending in ChannelOutboundBuffer, the "Current" property is returned as "null".
                    // This indicates that all pending messages have been dequeued from the ChannelOutboundBuffer and are ready to be written to the websocket.
                    if (currentMessage == null)
                    {
                        // This indicates that the ChannelOutboundBuffer had readable bytes and they have been added to the CompositeByteBuffer.
                        if (compositeByteBuffer.NumComponents > 0)
                        {
                            // All messages have been added to the CompositeByteBuffer and are now ready to be written to the socket.
                            bytesToBeWritten = compositeByteBuffer.GetIoBuffer();
                        }
                        break;
                    }

                    var byteBuffer = currentMessage as IByteBuffer;
                    Fx.AssertAndThrow(byteBuffer != null, "channelOutBoundBuffer contents must be of type IByteBuffer");

                    // If the byte buffer has readable bytes then add them to the CompositeByteBuffer.
                    if (byteBuffer.ReadableBytes != 0)
                    {
                        // There are two operations carried out while adding a byte buffer component to a CompositeByteBuffer:
                        // - Increase WriterIndex of the CompositeByteBuffer
                        //      - increases the count of readable bytes added to the CompositeByteBuffer.
                        // - Call the method Retain() on the byte buffer being added
                        //      - The property ReferenceCount of a byte buffer implementation maintains a counter of the no of messages available for dequeuing.
                        //        A ReferenceCount of 0 indicates that all messages have been flushed and the buffer can be deallocated.
                        //        By calling the method Retain() on each byte buffer component added to the CompositeByteBuffer,
                        //        we increase the ReferenceCount by 1 and mark them as ready for dequeuing.
                        compositeByteBuffer
                        .AddComponent(
                            increaseWriterIndex: true,
                            buffer: (IByteBuffer)byteBuffer.Retain());
                    }

                    // Once the readable bytes are added to the CompositeByteBuffer they can be removed from the ChannelOutboundBuffer
                    // and the next message, if any, can be processed.
                    channelOutboundBuffer.Remove();
                }

                if (bytesToBeWritten.Count > 0)
                {
                    if (Logging.IsEnabled)
                    {
                        Logging.Info(this, $"Writing bytes of size {bytesToBeWritten.Count} to the websocket", nameof(DoWrite));
                    }

                    await _webSocket.SendAsync(bytesToBeWritten, WebSocketMessageType.Binary, true, _writeCancellationTokenSource.Token).ConfigureAwait(false);
                }

                _isWriteInProgress = false;
            }
            catch (Exception e) when(!e.IsFatal())
            {
                // Since this method returns void, all exceptions must be handled here.

                _isWriteInProgress = false;
                Pipeline.FireExceptionCaught(e);
                await HandleCloseAsync().ConfigureAwait(false);
            }
            finally
            {
                if (Logging.IsEnabled)
                {
                    Logging.Exit(this, nameof(DoWrite));
                }
            }
        }
        private async Task TestGatheringWrite0(
            ServerBootstrap sb, Bootstrap cb, byte[] data, bool composite, bool autoRead)
        {
            sb.ChildOption(ChannelOption.AutoRead, autoRead);
            cb.Option(ChannelOption.AutoRead, autoRead);

            IPromise          serverDonePromise = new DefaultPromise();
            TestServerHandler sh = new TestServerHandler(autoRead, serverDonePromise, data.Length);
            TestHandler       ch = new TestHandler(autoRead);

            cb.Handler(ch);
            sb.ChildHandler(sh);

            IChannel sc = await sb.BindAsync();

            IChannel cc = await cb.ConnectAsync(sc.LocalAddress);

            for (int i = 0; i < data.Length;)
            {
                int length = Math.Min(s_random.Next(1024 * 8), data.Length - i);
                if (composite && i % 2 == 0)
                {
                    int firstBufLength       = length / 2;
                    CompositeByteBuffer comp = Unpooled.CompositeBuffer();
                    comp.AddComponent(true, Unpooled.WrappedBuffer(data, i, firstBufLength))
                    .AddComponent(true, Unpooled.WrappedBuffer(data, i + firstBufLength, length - firstBufLength));
                    cc.WriteAsync(comp).Ignore();
                }
                else
                {
                    cc.WriteAsync(Unpooled.WrappedBuffer(data, i, length)).Ignore();
                }
                i += length;
            }

            var cf = cc.WriteAndFlushAsync(Unpooled.Empty);

            Assert.NotEqual(cc.VoidPromise().Task, cf);
            try
            {
                Assert.True(cf.Wait(60000));
                await cf;
            }
            catch (Exception)
            {
                throw;
            }

            await serverDonePromise.Task;
            await sh._channel.CloseAsync();

            await ch._channel.CloseAsync();

            await sc.CloseAsync();

            if (sh._exception.Value != null && !(sh._exception.Value is SocketException || (sh._exception.Value is ChannelException chexc && chexc.InnerException is OperationException) || sh._exception.Value is OperationException))
            {
                throw sh._exception.Value;
            }
            if (sh._exception.Value != null)
            {
                throw sh._exception.Value;
            }
            if (ch._exception.Value != null && !(ch._exception.Value is SocketException || (sh._exception.Value is ChannelException chexc1 && chexc1.InnerException is OperationException) || sh._exception.Value is OperationException))
            {
                throw ch._exception.Value;
            }
            if (ch._exception.Value != null)
            {
                throw ch._exception.Value;
            }
            IByteBuffer expected = Unpooled.WrappedBuffer(data);

            Assert.Equal(expected, sh._received);
            expected.Release();
            sh._received.Release();
        }
        protected internal override void Encode(IChannelHandlerContext ctx, WebSocketFrame msg, List <object> output)
        {
            if (this.encoder == null)
            {
                this.encoder = new EmbeddedChannel(
                    ZlibCodecFactory.NewZlibEncoder(
                        ZlibWrapper.None,
                        this.compressionLevel,
                        this.windowSize,
                        8));
            }

            this.encoder.WriteOutbound(msg.Content.Retain());

            CompositeByteBuffer fullCompressedContent = ctx.Allocator.CompositeBuffer();

            for (;;)
            {
                var partCompressedContent = this.encoder.ReadOutbound <IByteBuffer>();
                if (partCompressedContent == null)
                {
                    break;
                }

                if (!partCompressedContent.IsReadable())
                {
                    partCompressedContent.Release();
                    continue;
                }

                fullCompressedContent.AddComponent(true, partCompressedContent);
            }

            if (fullCompressedContent.NumComponents <= 0)
            {
                fullCompressedContent.Release();
                throw new CodecException("cannot read compressed buffer");
            }

            if (msg.IsFinalFragment && this.noContext)
            {
                this.Cleanup();
            }

            IByteBuffer compressedContent;

            if (this.RemoveFrameTail(msg))
            {
                int realLength = fullCompressedContent.ReadableBytes - FrameTail.Length;
                compressedContent = fullCompressedContent.Slice(0, realLength);
            }
            else
            {
                compressedContent = fullCompressedContent;
            }

            WebSocketFrame outMsg;

            if (msg is TextWebSocketFrame)
            {
                outMsg = new TextWebSocketFrame(msg.IsFinalFragment, this.Rsv(msg), compressedContent);
            }
            else if (msg is BinaryWebSocketFrame)
            {
                outMsg = new BinaryWebSocketFrame(msg.IsFinalFragment, this.Rsv(msg), compressedContent);
            }
            else if (msg is ContinuationWebSocketFrame)
            {
                outMsg = new ContinuationWebSocketFrame(msg.IsFinalFragment, this.Rsv(msg), compressedContent);
            }
            else
            {
                throw new CodecException($"unexpected frame type: {msg.GetType().Name}");
            }

            output.Add(outMsg);
        }