File: System\Net\Http\Headers\TransferCodingHeaderValue.cs
Web Access
Project: src\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.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
 
namespace System.Net.Http.Headers
{
    public class TransferCodingHeaderValue : ICloneable
    {
        // Use UnvalidatedObjectCollection<T> since we may have multiple parameters with the same name.
        private UnvalidatedObjectCollection<NameValueHeaderValue>? _parameters;
        private string _value = null!; // empty constructor only used internally and value set with non null
 
        public string Value => _value;
 
        public ICollection<NameValueHeaderValue> Parameters => _parameters ??= new UnvalidatedObjectCollection<NameValueHeaderValue>();
 
        internal TransferCodingHeaderValue()
        {
        }
 
        protected TransferCodingHeaderValue(TransferCodingHeaderValue source)
        {
            Debug.Assert(source != null);
 
            _value = source._value;
            _parameters = source._parameters.Clone();
        }
 
        public TransferCodingHeaderValue(string value)
        {
            HeaderUtilities.CheckValidToken(value);
            _value = value;
        }
 
        public static TransferCodingHeaderValue Parse(string input)
        {
            int index = 0;
            return (TransferCodingHeaderValue)TransferCodingHeaderParser.SingleValueParser.ParseValue(
                input, null, ref index);
        }
 
        public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out TransferCodingHeaderValue? parsedValue)
        {
            int index = 0;
            parsedValue = null;
 
            if (TransferCodingHeaderParser.SingleValueParser.TryParseValue(input, null, ref index, out object? output))
            {
                parsedValue = (TransferCodingHeaderValue)output!;
                return true;
            }
            return false;
        }
 
        internal static int GetTransferCodingLength(string input, int startIndex,
            Func<TransferCodingHeaderValue> transferCodingCreator, out TransferCodingHeaderValue? parsedValue)
        {
            Debug.Assert(transferCodingCreator != null);
            Debug.Assert(startIndex >= 0);
 
            parsedValue = null;
 
            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
            {
                return 0;
            }
 
            // Caller must remove leading whitespace. If not, we'll return 0.
            int valueLength = HttpRuleParser.GetTokenLength(input, startIndex);
 
            if (valueLength == 0)
            {
                return 0;
            }
 
            string value = input.Substring(startIndex, valueLength);
            int current = startIndex + valueLength;
            current += HttpRuleParser.GetWhitespaceLength(input, current);
            TransferCodingHeaderValue transferCodingHeader;
 
            // If we're not done and we have a parameter delimiter, then we have a list of parameters.
            if ((current < input.Length) && (input[current] == ';'))
            {
                transferCodingHeader = transferCodingCreator();
                transferCodingHeader._value = value;
 
                current++; // skip delimiter.
                int parameterLength = NameValueHeaderValue.GetNameValueListLength(input, current, ';',
                    (UnvalidatedObjectCollection<NameValueHeaderValue>)transferCodingHeader.Parameters);
 
                if (parameterLength == 0)
                {
                    return 0;
                }
 
                parsedValue = transferCodingHeader;
                return current + parameterLength - startIndex;
            }
 
            // We have a transfer coding without parameters.
            transferCodingHeader = transferCodingCreator();
            transferCodingHeader._value = value;
            parsedValue = transferCodingHeader;
            return current - startIndex;
        }
 
        public override string ToString()
        {
            StringBuilder sb = StringBuilderCache.Acquire();
            sb.Append(_value);
            NameValueHeaderValue.ToString(_parameters, ';', true, sb);
            return StringBuilderCache.GetStringAndRelease(sb);
        }
 
        public override bool Equals([NotNullWhen(true)] object? obj)
        {
            TransferCodingHeaderValue? other = obj as TransferCodingHeaderValue;
 
            if (other == null)
            {
                return false;
            }
 
            return string.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase) &&
                HeaderUtilities.AreEqualCollections(_parameters, other._parameters);
        }
 
        public override int GetHashCode()
        {
            // The value string is case-insensitive.
            return StringComparer.OrdinalIgnoreCase.GetHashCode(_value) ^ NameValueHeaderValue.GetHashCode(_parameters);
        }
 
        // Implement ICloneable explicitly to allow derived types to "override" the implementation.
        object ICloneable.Clone()
        {
            return new TransferCodingHeaderValue(this);
        }
    }
}