123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- using System;
- using Best.HTTP.Shared.Compression.Zlib;
- using Best.HTTP.Shared.Logger;
- using Best.HTTP.Shared.PlatformSupport.Memory;
- using Best.HTTP.Shared.Streams;
- namespace Best.HTTP.Response.Decompression
- {
- public sealed class DeflateDecompressor : IDecompressor
- {
- private BufferPoolMemoryStream decompressorInputStream;
- private BufferPoolMemoryStream decompressorOutputStream;
- private DeflateStream decompressorStream;
- private int MinLengthToDecompress = 256;
- public static bool IsSupported = true;
- public DeflateDecompressor(int minLengthToDecompress)
- {
- this.MinLengthToDecompress = minLengthToDecompress;
- }
- public (BufferSegment decompressed, bool releaseTheOld) Decompress(BufferSegment segment, bool forceDecompress, bool dataCanBeLarger, LoggingContext context)
- {
- if (decompressorInputStream == null)
- decompressorInputStream = new BufferPoolMemoryStream(segment.Count);
- if (segment.Data != null)
- decompressorInputStream.Write(segment.Data, segment.Offset, segment.Count);
- if (!forceDecompress && decompressorInputStream.Length < MinLengthToDecompress)
- return (BufferSegment.Empty, true);
- decompressorInputStream.Position = 0;
- if (decompressorStream == null)
- {
- // Had to change from this
- // _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen);
- // this this:
- // _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.ZLIB, leaveOpen);
- // Because there are two bytes in the header additionally to what the deflate flavor expects that the zlib one handles fine.
- decompressorStream = new DeflateStream(decompressorInputStream,
- CompressionMode.Decompress,
- CompressionLevel.Default,
- true);
- decompressorStream.FlushMode = FlushType.Sync;
- }
- if (decompressorOutputStream == null)
- decompressorOutputStream = new BufferPoolMemoryStream();
- decompressorOutputStream.SetLength(0);
- byte[] copyBuffer = BufferPool.Get(1024, true);
- int readCount;
- int sumReadCount = 0;
- while ((readCount = decompressorStream.Read(copyBuffer, 0, copyBuffer.Length)) != 0)
- {
- decompressorOutputStream.Write(copyBuffer, 0, readCount);
- sumReadCount += readCount;
- }
- BufferPool.Release(copyBuffer);
- // If no read is done (returned with any data) don't zero out the input stream, as it would delete any not yet used data.
- if (sumReadCount > 0)
- decompressorStream.SetLength(0);
- byte[] result = decompressorOutputStream.ToArray(dataCanBeLarger, context);
- return (new BufferSegment(result, 0, dataCanBeLarger ? (int)decompressorOutputStream.Length : result.Length), true);
- }
- ~DeflateDecompressor()
- {
- Dispose();
- }
- public void Dispose()
- {
- if (decompressorInputStream != null)
- decompressorInputStream.Dispose();
- decompressorInputStream = null;
- if (decompressorOutputStream != null)
- decompressorOutputStream.Dispose();
- decompressorOutputStream = null;
- if (decompressorStream != null)
- {
- // If the decompressor closed before receiving data, or it's incomplete, disposing (eg. closing) it
- // throws an execption like this:
- // "Missing or incomplete GZIP trailer. Expected 8 bytes, got 0."
- try
- {
- decompressorStream.Dispose();
- }
- catch
- { }
- }
- decompressorStream = null;
- GC.SuppressFinalize(this);
- }
- }
- }
|