/// <summary>
        ///   Uncompress a DEFLATE'd byte array into a byte array.
        /// </summary>
        ///
        /// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
        /// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
        /// <seealso cref="GZipStream.UncompressBuffer(byte[])">GZipStream.UncompressBuffer(byte[])</seealso>
        ///
        /// <param name="compressed">
        ///   A buffer containing data that has been compressed with DEFLATE.
        /// </param>
        ///
        /// <returns>The data in uncompressed form</returns>
        public static byte[] UncompressBuffer(byte[] compressed)
        {
            using (var input = new System.IO.MemoryStream(compressed))
            {
                System.IO.Stream decompressor = new DeflateStream( input, CompressionMode.Decompress );

                return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
            }
        }
        /// <summary>
        ///   Compress a byte array into a new byte array using DEFLATE.
        /// </summary>
        ///
        /// <remarks>
        ///   Uncompress it with <see cref="DeflateStream.UncompressBuffer(byte[])"/>.
        /// </remarks>
        ///
        /// <seealso cref="DeflateStream.CompressString(string)">DeflateStream.CompressString(string)</seealso>
        /// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
        /// <seealso cref="GZipStream.CompressBuffer(byte[])">GZipStream.CompressBuffer(byte[])</seealso>
        ///
        /// <param name="b">
        ///   A buffer to compress.
        /// </param>
        ///
        /// <returns>The data in compressed form</returns>
        public static byte[] CompressBuffer(byte[] b)
        {
            using (var ms = new System.IO.MemoryStream())
            {
                System.IO.Stream compressor =
                    new DeflateStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );

                ZlibBaseStream.CompressBuffer(b, compressor);
                return ms.ToArray();
            }
        }
        /// <summary>
        /// A function to decompress and return the data paramter with possible context takeover support (reusing the DeflateStream).
        /// </summary>
        private byte[] Decompress(byte[] data)
        {
            if (decompressorInputStream == null)
                decompressorInputStream = new System.IO.MemoryStream(data.Length + 4);

            decompressorInputStream.Write(data, 0, data.Length);

            // http://tools.ietf.org/html/rfc7692#section-7.2.2
            // Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the payload of the message.
            decompressorInputStream.Write(PerMessageCompression.Trailer, 0, PerMessageCompression.Trailer.Length);

            decompressorInputStream.Position = 0;

            if (decompressorDeflateStream == null)
            {
                decompressorDeflateStream = new DeflateStream(decompressorInputStream, CompressionMode.Decompress, CompressionLevel.Default, true, this.ServerMaxWindowBits);
                decompressorDeflateStream.FlushMode = FlushType.Sync;
            }

            if (decompressorOutputStream == null)
                decompressorOutputStream = new System.IO.MemoryStream();
            decompressorOutputStream.SetLength(0);

            int readCount;
            while ((readCount = decompressorDeflateStream.Read(copyBuffer, 0, copyBuffer.Length)) != 0)
                decompressorOutputStream.Write(copyBuffer, 0, readCount);

            decompressorDeflateStream.SetLength(0);

            byte[] result = decompressorOutputStream.ToArray();

            if (this.ServerNoContextTakeover)
            {
                decompressorDeflateStream.Dispose();
                decompressorDeflateStream = null;
            }

            return result;
        }
        protected byte[] DecodeStream(Stream streamToDecode)
        {
            streamToDecode.Seek(0, SeekOrigin.Begin);

            // The cache stores the decoded data
            var encoding = IsFromCache ? null : GetHeaderValues("content-encoding");

            Stream decoderStream = null;
            if (encoding == null)
                decoderStream = streamToDecode;
            else
            {
                switch (encoding[0])
                {
                    case "gzip": decoderStream = new Decompression.Zlib.GZipStream(streamToDecode, Decompression.Zlib.CompressionMode.Decompress); break;
                    case "deflate": decoderStream = new Decompression.Zlib.DeflateStream(streamToDecode, Decompression.Zlib.CompressionMode.Decompress); break;
                    default:
                        //identity, utf-8, etc.
                        decoderStream = streamToDecode;
                        break;
                }
            }

            using (var ms = new MemoryStream((int)streamToDecode.Length))
            {
                var buf = new byte[1024];
                int byteCount = 0;

                while ((byteCount = decoderStream.Read(buf, 0, buf.Length)) > 0)
                    ms.Write(buf, 0, byteCount);

                return ms.ToArray();
            }
        }
        /// <summary>
        /// A function to comress and return the data parameter with possible context takeover support (reusing the DeflateStream).
        /// </summary>
        private byte[] Compress(byte[] data)
        {
            if (compressorOutputStream == null)
                compressorOutputStream = new System.IO.MemoryStream();
            compressorOutputStream.SetLength(0);

            if (compressorDeflateStream == null)
            {
                compressorDeflateStream = new DeflateStream(compressorOutputStream, CompressionMode.Compress, this.Level, true, this.ClientMaxWindowBits);
                compressorDeflateStream.FlushMode = FlushType.Sync;
            }

            byte[] result = null;
            try
            {
                compressorDeflateStream.Write(data, 0, data.Length);
                compressorDeflateStream.Flush();

                compressorOutputStream.Position = 0;

                // http://tools.ietf.org/html/rfc7692#section-7.2.1
                // Remove 4 octets (that are 0x00 0x00 0xff 0xff) from the tail end. After this step, the last octet of the compressed data contains (possibly part of) the DEFLATE header bits with the "BTYPE" bits set to 00.
                compressorOutputStream.SetLength(compressorOutputStream.Length - 4);

                result = compressorOutputStream.ToArray();
            }
            finally
            {
                if (this.ClientNoContextTakeover)
                {
                    compressorDeflateStream.Dispose();
                    compressorDeflateStream = null;
                }
            }

            return result;
        }