public async Task It_Reads_Asynchronously()
        {
            // ARRANGE
            var buffer = Encoding.ASCII.GetBytes("foobarbaz");
            var innerStream = new MemoryStream(Encoding.ASCII.GetBytes("FOOBAR"));
            var stream = new PartiallyBufferedStream(buffer, 3, 3, innerStream);

            // ACT
            var content = await new StreamReader(stream, Encoding.ASCII).ReadToEndAsync();

            // ASSERT
            content.Should().Be("barFOOBAR");
        }
Пример #2
0
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            // add content encodings to the request
            var acceptEncoding = ContentEncodings
                .Where(p => AutomaticDecompression.HasFlag(p.Key))
                .Where(p => request.Headers.AcceptEncoding.All(c => c.Value.Equals(p.Value, StringComparison.OrdinalIgnoreCase)))
                .OrderBy(p => p.Key)
                .Select(p => p.Value);

            foreach (var encoding in acceptEncoding)
            {
                request.Headers.AcceptEncoding.Add(new StringWithQualityHeaderValue(encoding));
            }

            // get the response
            var response = await base.SendAsync(request, cancellationToken);

            // immediately return when the response body is empty or not compressed
            if (response.Content == null || !response.Content.Headers.ContentEncoding.Any())
            {
                return response;
            }

            // read the header
            var responseStream = await response.Content.ReadAsStreamAsync();
            var header = new byte[2];
            var headerLength = await responseStream.ReadAsync(header, 0, 2, cancellationToken);
            if (headerLength == 1)
            {
                headerLength += await responseStream.ReadAsync(header, 1, 2, cancellationToken);
            }
            
            if (headerLength < 2)
            {
                return response;
            }

            // include the header in the stream that gets decompressed
            var encodedStream = new PartiallyBufferedStream(header, 0, 2, responseStream);

            // try to decode the response
            Stream decodeStream = null;
            var contentEncoding = response.Content.Headers.ContentEncoding.First();
            if (AutomaticDecompression.HasFlag(DecompressionMethods.GZip) && contentEncoding.Equals(ContentEncodings[DecompressionMethods.GZip], StringComparison.OrdinalIgnoreCase))
            {
                // let gzip compress the stream, and exclude the Content-Encoding header
                decodeStream = new GZipStream(encodedStream, CompressionMode.Decompress);
            }
            else if (AutomaticDecompression.HasFlag(DecompressionMethods.Deflate) && contentEncoding.Equals(ContentEncodings[DecompressionMethods.Deflate], StringComparison.OrdinalIgnoreCase))
            {
                // decompress the stream as raw DEFLATE or zlib, depending on the header
                var noHeader = header[0] != ValidZlibCmfByte || !ValidZlibFlgBytes.Contains(header[1]);
                decodeStream = noHeader ? new DeflateStream(encodedStream, CompressionMode.Decompress) : new DeflateStream(responseStream, CompressionMode.Decompress);
            }

            if (decodeStream != null)
            {
                var decompressedContent = new StreamContent(decodeStream);
                foreach (var pair in response.Content.Headers)
                {
                    if (pair.Key.Equals("Content-Encoding", StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    decompressedContent.Headers.TryAddWithoutValidation(pair.Key, pair.Value);
                }

                response.Content = decompressedContent;
            }

            return response;
        }