File: System\Net\Http\BrotliCompressedContent.cs
Web Access
Project: src\runtime\src\libraries\System.Net.Http\src\System.Net.Http.csproj (System.Net.Http)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.IO.Compression;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;

namespace System.Net.Http
{
    /// <summary>
    /// Provides HTTP content that compresses the inner content using the Brotli content coding.
    /// </summary>
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("wasi")]
    public sealed class BrotliCompressedContent : HttpContent
    {
        private const string Encoding = "br";

        private readonly HttpContent _content;
        private readonly BrotliCompressionOptions? _compressionOptions;
        private readonly CompressionLevel _compressionLevel;

        /// <summary>
        /// Initializes a new instance of the <see cref="BrotliCompressedContent"/> class that compresses the
        /// provided content using the Brotli content coding at the specified compression level.
        /// </summary>
        /// <param name="content">The HTTP content to compress.</param>
        /// <param name="compressionLevel">One of the enumeration values that indicates whether to emphasize speed or compression efficiency.</param>
        public BrotliCompressedContent(HttpContent content, CompressionLevel compressionLevel = CompressionLevel.Optimal)
        {
            ArgumentNullException.ThrowIfNull(content);
            CompressedContentCore.ValidateCompressionLevel(compressionLevel, nameof(compressionLevel));

            _compressionLevel = compressionLevel;
            _content = content;
            CompressedContentCore.InitializeHeaders(this, content, Encoding);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BrotliCompressedContent"/> class that compresses the
        /// provided content using the Brotli content coding and the specified compression options.
        /// </summary>
        /// <param name="content">The HTTP content to compress.</param>
        /// <param name="compressionOptions">The options used to fine-tune the compression.</param>
        public BrotliCompressedContent(HttpContent content, BrotliCompressionOptions compressionOptions)
        {
            ArgumentNullException.ThrowIfNull(content);
            ArgumentNullException.ThrowIfNull(compressionOptions);

            _compressionOptions = compressionOptions;
            _content = content;
            CompressedContentCore.InitializeHeaders(this, content, Encoding);
        }

        protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellationToken) =>
            CompressedContentCore.SerializeToStream(_content, CreateCompressionStream(stream), context, cancellationToken);

        protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) =>
            CompressedContentCore.SerializeToStreamAsync(_content, CreateCompressionStream(stream), context, CancellationToken.None);

        protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) =>
            CompressedContentCore.SerializeToStreamAsync(_content, CreateCompressionStream(stream), context, cancellationToken);

        protected internal override bool TryComputeLength(out long length)
        {
            // Compressed size is not known without actually compressing.
            length = 0;
            return false;
        }

        internal override bool AllowDuplex => false;

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _content.Dispose();
            }

            base.Dispose(disposing);
        }

        private BrotliStream CreateCompressionStream(Stream outputStream) =>
            _compressionOptions is null
                ? new BrotliStream(outputStream, _compressionLevel, leaveOpen: true)
                : new BrotliStream(outputStream, _compressionOptions, leaveOpen: true);
    }
}