< Summary

Line coverage
41%
Covered lines: 444
Uncovered lines: 617
Coverable lines: 1061
Total lines: 1669
Line coverage: 41.8%
Branch coverage
36%
Covered branches: 149
Total branches: 406
Branch coverage: 36.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%110%
.ctor(...)100%11100%
Add(...)100%11100%
Add(...)100%66100%
Add(...)100%110%
Add(...)0%16160%
TryAddWithoutValidation(...)100%22100%
TryAddWithoutValidation(...)66.66%66100%
TryAddWithoutValidation(...)0%220%
TryAddWithoutValidation(...)0%24240%
GetValues(...)100%110%
GetValues(...)0%220%
TryGetValues(...)0%220%
TryGetValues(...)0%660%
Contains(...)0%220%
ToString()100%110%
Dump(...)0%10100%
GetHeaderString(...)0%440%
GetEnumerator()100%22100%
GetEnumeratorCore()80%1010100%
System.Collections.IEnumerable.GetEnumerator()100%110%
AddParsedValue(...)0%220%
SetParsedValue(...)100%110%
SetOrRemoveParsedValue(...)0%220%
Remove(...)0%220%
RemoveParsedValue(...)0%28280%
ContainsParsedValue(...)0%14140%
AddHeaders(...)0%20200%
CloneHeaderInfo(...)0%880%
CloneAndAddValue(...)0%220%
CloneStringHeaderInfoValues(...)0%440%
GetOrCreateHeaderInfo(...)0%220%
CreateAndAddHeaderToStore(...)100%110%
TryGetHeaderValue(...)0%220%
TryGetAndParseHeaderInfo(...)75%44100%
ReplaceWithHeaderStoreItemInfo(...)50%2288.88%
ParseRawHeaderValues(...)100%66100%
ParseSingleRawHeaderValue(...)60%101080%
TryParseAndAddValue(...)0%440%
TryParseAndAddRawHeaderValue(...)60%404085.48%
AddParsedValue(...)100%11100%
AddInvalidValue(...)100%11100%
AddRawValue(...)100%11100%
AddValueToStoreValue(...)100%44100%
GetSingleParsedValue(...)0%220%
GetParsedAndInvalidValues(...)0%220%
IsAllowedHeaderName(...)100%11100%
CheckIsAllowedHeaderName(...)50%2260%
PrepareHeaderInfoForAdd(...)100%22100%
ParseAndAddValue(...)81.25%1616100%
GetHeaderDescriptor(...)66.66%6676.92%
TryGetHeaderDescriptor(...)75%8883.33%
CheckContainsNewLineOrNull(...)100%44100%
GetStoreValuesAsStringArray(...)100%22100%
GetStoreValuesAsStringOrStringArray(...)75%4481.48%
GetStoreValuesIntoStringArray(...)0%880%
GetValueCount(...)100%11100%
Count(System.Object)100%44100%
ReadStoreValues(...)100%1414100%
AreEqual(...)0%220%
.ctor(...)100%11100%
ToString()100%11100%
.ctor()100%11100%
CanAddParsedValue(...)100%22100%
AssertContainsNoInvalidValues()83.33%66100%
GetSingleParsedValue()0%10100%
AssertContainsSingleParsedValue(...)0%440%
GetEntriesArray()50%4463.63%
GetEntriesFromDictionary()0%220%
GetEntries()100%110%
GetValueRefOrNullRef(...)60%101073.68%
GetValueRefOrAddDefault(...)75%121285.18%
GrowEntriesAndAddDefault(System.Net.Http.Headers.HeaderDescriptor)0%220%
ConvertToDictionaryAndAddDefault(System.Net.Http.Headers.HeaderDescriptor)0%220%
DictionaryGetValueRefOrAddDefault(System.Net.Http.Headers.HeaderDescriptor)0%220%
AddEntryToStore(...)50%4484.61%
Contains(...)100%11100%
Clear()100%22100%
Remove(...)0%16160%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpHeaders.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Diagnostics.CodeAnalysis;
 8using System.Runtime.CompilerServices;
 9using System.Runtime.InteropServices;
 10using System.Text;
 11using System.Threading;
 12
 13namespace System.Net.Http.Headers
 14{
 15    /// <summary>
 16    /// Key/value pairs of headers. The value is either a raw <see cref="string"/> or a <see cref="HttpHeaders.HeaderSto
 17    /// We're using a custom type instead of <see cref="KeyValuePair{TKey, TValue}"/> because we need ref access to fiel
 18    /// </summary>
 19    internal struct HeaderEntry
 20    {
 21        public HeaderDescriptor Key;
 22        public object Value;
 23
 24        public HeaderEntry(HeaderDescriptor key, object value)
 25        {
 26            Key = key;
 27            Value = value;
 28        }
 29    }
 30
 31    public abstract class HttpHeaders : IEnumerable<KeyValuePair<string, IEnumerable<string>>>
 32    {
 33        // This type is used to store a collection of headers in 'headerStore':
 34        // - A header can have multiple values.
 35        // - A header can have an associated parser which is able to parse the raw string value into a strongly typed ob
 36        // - If a header has an associated parser and the provided raw value can't be parsed, the value is considered
 37        //   invalid. Invalid values are stored if added using TryAddWithoutValidation(). If the value was added using A
 38        //   Add() will throw FormatException.
 39        // - Since parsing header values is expensive and users usually only care about a few headers, header values are
 40        //   lazily initialized.
 41        //
 42        // Given the properties above, a header value can have three states:
 43        // - 'raw': The header value was added using TryAddWithoutValidation() and it wasn't parsed yet.
 44        // - 'parsed': The header value was successfully parsed. It was either added using Add() where the value was par
 45        //   immediately, or if added using TryAddWithoutValidation() a user already accessed a property/method triggeri
 46        //   value to be parsed.
 47        // - 'invalid': The header value was parsed, but parsing failed because the value is invalid. Storing invalid va
 48        //   allows users to still retrieve the value (by calling GetValues()), but it will not be exposed as strongly t
 49        //   object. E.g. the client receives a response with the following header: 'Via: 1.1 proxy, invalid'
 50        //   - HttpHeaders.GetValues() will return "1.1 proxy", "invalid"
 51        //   - HttpResponseHeaders.Via collection will only contain one ViaHeaderValue object with value "1.1 proxy"
 52
 53        /// <summary>Either a <see cref="HeaderEntry"/> array or a Dictionary&lt;<see cref="HeaderDescriptor"/>, <see cr
 54        private object? _headerStore;
 55        private int _count;
 56
 57        private readonly HttpHeaderType _allowedHeaderTypes;
 58        private readonly HttpHeaderType _treatAsCustomHeaderTypes;
 59
 60        protected HttpHeaders()
 061            : this(HttpHeaderType.All, HttpHeaderType.None)
 062        {
 063        }
 64
 365        internal HttpHeaders(HttpHeaderType allowedHeaderTypes, HttpHeaderType treatAsCustomHeaderTypes)
 366        {
 67            // Should be no overlap
 368            Debug.Assert((allowedHeaderTypes & treatAsCustomHeaderTypes) == 0);
 69
 370            _allowedHeaderTypes = allowedHeaderTypes & ~HttpHeaderType.NonTrailing;
 371            _treatAsCustomHeaderTypes = treatAsCustomHeaderTypes & ~HttpHeaderType.NonTrailing;
 372        }
 73
 74        /// <summary>Gets a view of the contents of this headers collection that does not parse nor validate the data up
 961075        public HttpHeadersNonValidated NonValidated => new HttpHeadersNonValidated(this);
 76
 1527477        public void Add(string name, string? value) => Add(GetHeaderDescriptor(name), value);
 78
 79        internal void Add(HeaderDescriptor descriptor, string? value)
 1527480        {
 1527481            if (descriptor.Parser is null)
 737582            {
 83                // If the header has no parser, we only have to check for new lines or null.
 737584                CheckIsAllowedHeaderName(descriptor);
 737585                CheckContainsNewLineOrNull(value);
 662886                TryAddWithoutValidation(descriptor, value);
 662887                return;
 88            }
 89
 90            // We don't use GetOrCreateHeaderInfo() here, since this would create a new header in the store. If parsing
 91            // the value then throws, we would have to remove the header from the store again. So just get a
 92            // HeaderStoreItemInfo object and try to parse the value. If it works, we'll add the header.
 789993            PrepareHeaderInfoForAdd(descriptor, out HeaderStoreItemInfo info, out bool addToStore);
 789994            ParseAndAddValue(descriptor, info, value);
 95
 96            // If we get here, then the value could be parsed correctly. If we created a new HeaderStoreItemInfo, add
 97            // it to the store if we added at least one value.
 462998            if (addToStore && (info.ParsedAndInvalidValues != null))
 225199            {
 2251100                info.AssertContainsNoInvalidValues();
 2251101                Debug.Assert(!Contains(descriptor));
 2251102                AddEntryToStore(new HeaderEntry(descriptor, info));
 2251103            }
 11257104        }
 105
 0106        public void Add(string name, IEnumerable<string?> values) => Add(GetHeaderDescriptor(name), values);
 107
 108        internal void Add(HeaderDescriptor descriptor, IEnumerable<string?> values)
 0109        {
 0110            ArgumentNullException.ThrowIfNull(values);
 111
 112            // It's relatively common to only add a single value with this overload, especially when copying
 113            // between HttpHeaders collections. Avoid boxing the enumerator and possibly a HeaderStoreItemInfo
 114            // allocation by deferring to the overload for a single value instead.
 0115            if (values is IList<string?> { Count: 1 } valuesList)
 0116            {
 0117                Add(descriptor, valuesList[0]);
 0118                return;
 119            }
 120
 0121            PrepareHeaderInfoForAdd(descriptor, out HeaderStoreItemInfo info, out bool addToStore);
 122
 123            try
 0124            {
 125                // Note that if the first couple of values are valid followed by an invalid value, the valid values
 126                // will be added to the store before the exception for the invalid value is thrown.
 0127                if (descriptor.Parser is null)
 0128                {
 0129                    foreach (string? value in values)
 0130                    {
 131                        // If the header has no parser, we only have to check for new lines or null.
 0132                        CheckContainsNewLineOrNull(value);
 0133                        AddParsedValue(info, value ?? string.Empty);
 0134                    }
 0135                }
 136                else
 0137                {
 0138                    foreach (string? value in values)
 0139                    {
 0140                        ParseAndAddValue(descriptor, info, value);
 0141                    }
 0142                }
 0143            }
 144            finally
 0145            {
 146                // Even if one of the values was invalid, make sure we add the header for the valid ones. We need to be
 147                // consistent here: If values get added to an _existing_ header, then all values until the invalid one
 148                // get added. Same here: If multiple values get added to a _new_ header, make sure the header gets added
 149                // with the valid values.
 150                // However, if all values for a _new_ header were invalid, then don't add the header.
 0151                if (addToStore && (info.ParsedAndInvalidValues != null))
 0152                {
 0153                    info.AssertContainsNoInvalidValues();
 0154                    Debug.Assert(!Contains(descriptor));
 0155                    AddEntryToStore(new HeaderEntry(descriptor, info));
 0156                }
 0157            }
 0158        }
 159
 160        public bool TryAddWithoutValidation(string name, string? value) =>
 14238161            TryGetHeaderDescriptor(name, out HeaderDescriptor descriptor) &&
 14238162            TryAddWithoutValidation(descriptor, value);
 163
 164        internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, string? value)
 16238165        {
 166            // Normalize null values to be empty values, which are allowed. If the user adds multiple
 167            // null/empty values, all of them are added to the collection. This will result in delimiter-only
 168            // values, e.g. adding two null-strings (or empty, or whitespace-only) results in "My-Header: ,".
 16238169            value ??= string.Empty;
 170
 16238171            ref object? storeValueRef = ref GetValueRefOrAddDefault(descriptor);
 16238172            object? currentValue = storeValueRef;
 173
 16238174            if (currentValue is null)
 12924175            {
 12924176                storeValueRef = value;
 12924177            }
 178            else
 3314179            {
 3314180                if (currentValue is not HeaderStoreItemInfo info)
 3314181                {
 182                    // The header store contained a single raw string value, so promote it
 183                    // to being a HeaderStoreItemInfo and add to it.
 3314184                    Debug.Assert(currentValue is string);
 3314185                    storeValueRef = info = new HeaderStoreItemInfo() { RawValue = currentValue };
 3314186                }
 187
 3314188                AddRawValue(info, value);
 3314189            }
 190
 16238191            return true;
 16238192        }
 193
 194        public bool TryAddWithoutValidation(string name, IEnumerable<string?> values) =>
 0195            TryGetHeaderDescriptor(name, out HeaderDescriptor descriptor) &&
 0196            TryAddWithoutValidation(descriptor, values);
 197
 198        internal bool TryAddWithoutValidation(HeaderDescriptor descriptor, IEnumerable<string?> values)
 0199        {
 0200            ArgumentNullException.ThrowIfNull(values);
 201
 0202            if (values is IList<string?> valuesList)
 0203            {
 0204                int count = valuesList.Count;
 205
 0206                if (count > 0)
 0207                {
 208                    // The store value is either a string (a single unparsed value) or a HeaderStoreItemInfo.
 209                    // The RawValue on HeaderStoreItemInfo can likewise be either a single string or a List<string>.
 210
 0211                    ref object? storeValueRef = ref GetValueRefOrAddDefault(descriptor);
 0212                    object? storeValue = storeValueRef;
 213
 214                    // If the storeValue was already set or we're adding more than 1 value,
 215                    // we'll have to store the values in a List<string> on HeaderStoreItemInfo.
 0216                    if (storeValue is not null || count > 1)
 0217                    {
 0218                        if (storeValue is not HeaderStoreItemInfo info)
 0219                        {
 0220                            storeValueRef = info = new HeaderStoreItemInfo { RawValue = storeValue };
 0221                        }
 222
 0223                        object? rawValue = info.RawValue;
 0224                        if (rawValue is not List<string> rawValues)
 0225                        {
 0226                            info.RawValue = rawValues = new List<string>();
 227
 0228                            if (rawValue != null)
 0229                            {
 0230                                rawValues.EnsureCapacity(count + 1);
 0231                                rawValues.Add((string)rawValue);
 0232                            }
 0233                        }
 234
 0235                        rawValues.EnsureCapacity(rawValues.Count + count);
 236
 0237                        for (int i = 0; i < count; i++)
 0238                        {
 0239                            rawValues.Add(valuesList[i] ?? string.Empty);
 0240                        }
 0241                    }
 242                    else
 0243                    {
 244                        // We're adding a single value to a new header entry. We can store the unparsed value as-is.
 0245                        storeValueRef = valuesList[0] ?? string.Empty;
 0246                    }
 0247                }
 0248            }
 249            else
 0250            {
 0251                foreach (string? value in values)
 0252                {
 0253                    TryAddWithoutValidation(descriptor, value ?? string.Empty);
 0254                }
 0255            }
 256
 0257            return true;
 0258        }
 259
 0260        public IEnumerable<string> GetValues(string name) => GetValues(GetHeaderDescriptor(name));
 261
 262        internal IEnumerable<string> GetValues(HeaderDescriptor descriptor)
 0263        {
 0264            if (TryGetValues(descriptor, out IEnumerable<string>? values))
 0265            {
 0266                return values;
 267            }
 268
 0269            throw new InvalidOperationException(SR.net_http_headers_not_found);
 0270        }
 271
 272        public bool TryGetValues(string name, [NotNullWhen(true)] out IEnumerable<string>? values)
 0273        {
 0274            if (TryGetHeaderDescriptor(name, out HeaderDescriptor descriptor))
 0275            {
 0276                return TryGetValues(descriptor, out values);
 277            }
 278
 0279            values = null;
 0280            return false;
 0281        }
 282
 283        internal bool TryGetValues(HeaderDescriptor descriptor, [NotNullWhen(true)] out IEnumerable<string>? values)
 0284        {
 0285            ref object storeValueRef = ref GetValueRefOrNullRef(descriptor);
 0286            if (!Unsafe.IsNullRef(ref storeValueRef))
 0287            {
 0288                object value = storeValueRef;
 289
 0290                if (value is not HeaderStoreItemInfo info)
 0291                {
 0292                    if (descriptor.Parser is null)
 0293                    {
 294                        // This is a custom header without a known parser, so unparsed values won't change.
 295                        // Avoid allocating the HeaderStoreItemInfo and just return the raw value as-is.
 0296                        values = new string[] { (string)value };
 0297                        return true;
 298                    }
 299
 0300                    info = ReplaceWithHeaderStoreItemInfo(ref storeValueRef, value);
 0301                }
 302
 0303                ParseRawHeaderValues(descriptor, info);
 0304                values = GetStoreValuesAsStringArray(descriptor, info);
 0305                return true;
 306            }
 307
 0308            values = null;
 0309            return false;
 0310        }
 311
 312        public bool Contains(string name) =>
 0313            TryGetHeaderDescriptor(name, out HeaderDescriptor descriptor) &&
 0314            Contains(descriptor);
 315
 316        public override string ToString()
 0317        {
 0318            var vsb = new ValueStringBuilder(stackalloc char[512]);
 0319            Dump(ref vsb, indentLines: false);
 0320            return vsb.ToString();
 0321        }
 322
 323        internal void Dump(ref ValueStringBuilder builder, bool indentLines)
 0324        {
 325            // Return all headers as string similar to:
 326            // HeaderName1: Value1, Value2
 327            // HeaderName2: Value1
 328            // ...
 329
 0330            foreach (HeaderEntry entry in GetEntries())
 0331            {
 0332                if (indentLines)
 0333                {
 0334                    builder.Append("  ");
 0335                }
 336
 0337                builder.Append(entry.Key.Name);
 0338                builder.Append(": ");
 339
 0340                GetStoreValuesAsStringOrStringArray(entry.Key, entry.Value, out string? singleValue, out string[]? multi
 0341                Debug.Assert(singleValue is not null ^ multiValue is not null);
 342
 0343                if (singleValue is not null)
 0344                {
 0345                    builder.Append(singleValue);
 0346                }
 347                else
 0348                {
 349                    // Note that if we get multiple values for a header that doesn't support multiple values, we'll
 350                    // just separate the values using a comma (default separator).
 0351                    string separator = entry.Key.Separator;
 352
 0353                    Debug.Assert(multiValue is not null && multiValue.Length > 0);
 0354                    builder.Append(multiValue[0]);
 0355                    for (int i = 1; i < multiValue.Length; i++)
 0356                    {
 0357                        builder.Append(separator);
 0358                        builder.Append(multiValue[i]);
 0359                    }
 0360                }
 361
 0362                builder.Append(Environment.NewLine);
 0363            }
 0364        }
 365
 366        internal string GetHeaderString(HeaderDescriptor descriptor)
 0367        {
 0368            if (TryGetHeaderValue(descriptor, out object? info))
 0369            {
 0370                GetStoreValuesAsStringOrStringArray(descriptor, info, out string? singleValue, out string[]? multiValue)
 0371                Debug.Assert(singleValue is not null ^ multiValue is not null);
 372
 0373                if (singleValue is not null)
 0374                {
 0375                    return singleValue;
 376                }
 377
 378                // Note that if we get multiple values for a header that doesn't support multiple values, we'll
 379                // just separate the values using a comma (default separator).
 0380                return string.Join(descriptor.Separator, multiValue!);
 381            }
 382
 0383            return string.Empty;
 0384        }
 385
 386        #region IEnumerable<KeyValuePair<string, IEnumerable<string>>> Members
 387
 19220388        public IEnumerator<KeyValuePair<string, IEnumerable<string>>> GetEnumerator() => _count == 0 ?
 19220389                ((IEnumerable<KeyValuePair<string, IEnumerable<string>>>)Array.Empty<KeyValuePair<string, IEnumerable<st
 19220390                GetEnumeratorCore();
 391
 392        private IEnumerator<KeyValuePair<string, IEnumerable<string>>> GetEnumeratorCore()
 15175393        {
 15175394            Debug.Assert(_headerStore is not null);
 395
 15175396            HeaderEntry[]? entries = GetEntriesArray();
 15175397            Debug.Assert(_count != 0 && entries is not null, "Caller should have validated the collection is not empty")
 398
 60700399            for (int i = 0; i < _count; i++)
 15175400            {
 15175401                HeaderEntry entry = entries[i];
 402
 15175403                if (entry.Value is not HeaderStoreItemInfo info)
 9610404                {
 9610405                    if (entry.Key.Parser is null)
 4061406                    {
 407                        // This is a custom header without a known parser, so unparsed values won't change.
 408                        // Avoid allocating the HeaderStoreItemInfo and just return the raw value as-is.
 4061409                        yield return new KeyValuePair<string, IEnumerable<string>>(entry.Key.Name, new string[] { (strin
 4061410                        continue;
 411                    }
 412
 413                    // To retain consistent semantics, we need to upgrade a raw string to a HeaderStoreItemInfo
 414                    // during enumeration so that we can parse the raw value in order to a) return
 415                    // the correct set of parsed values, and b) update the instance for subsequent enumerations
 416                    // to reflect that parsing.
 5549417                    ref object storeValueRef = ref EntriesAreLiveView
 5549418                        ? ref entries[i].Value
 5549419                        : ref CollectionsMarshal.GetValueRefOrNullRef((Dictionary<HeaderDescriptor, object>)_headerStore
 420
 5549421                    info = ReplaceWithHeaderStoreItemInfo(ref storeValueRef, entry.Value);
 5549422                }
 423
 424                // Make sure we parse all raw values before returning the result. Note that this has to be
 425                // done before we calculate the array length (next line): A raw value may contain a list of
 426                // values.
 11114427                ParseRawHeaderValues(entry.Key, info);
 428
 11114429                string[] values = GetStoreValuesAsStringArray(entry.Key, info);
 11114430                yield return new KeyValuePair<string, IEnumerable<string>>(entry.Key.Name, values);
 11114431            }
 15175432        }
 433
 434        #endregion
 435
 436        #region IEnumerable Members
 437
 0438        Collections.IEnumerator Collections.IEnumerable.GetEnumerator() => GetEnumerator();
 439
 440        #endregion
 441
 442        internal void AddParsedValue(HeaderDescriptor descriptor, object value)
 0443        {
 0444            Debug.Assert(value != null);
 0445            Debug.Assert(descriptor.Parser != null, "Can't add parsed value if there is no parser available.");
 446
 0447            HeaderStoreItemInfo info = GetOrCreateHeaderInfo(descriptor);
 448
 449            // If the current header has only one value, we can't add another value. The strongly typed property
 450            // must not call AddParsedValue(), but SetParsedValue(). E.g. for headers like 'Date', 'Host'.
 0451            Debug.Assert(descriptor.Parser.SupportsMultipleValues, $"Header '{descriptor.Name}' doesn't support multiple
 452
 0453            AddParsedValue(info, value);
 0454        }
 455
 456        internal void SetParsedValue(HeaderDescriptor descriptor, object value)
 0457        {
 0458            Debug.Assert(value != null);
 0459            Debug.Assert(descriptor.Parser != null, "Can't add parsed value if there is no parser available.");
 460
 461            // This method will first clear all values. This is used e.g. when setting the 'Date' or 'Host' header.
 462            // i.e. headers not supporting collections.
 0463            HeaderStoreItemInfo info = GetOrCreateHeaderInfo(descriptor);
 464
 0465            info.ParsedAndInvalidValues = null;
 0466            info.RawValue = null;
 467
 0468            AddParsedValue(info, value);
 0469        }
 470
 471        internal void SetOrRemoveParsedValue(HeaderDescriptor descriptor, object? value)
 0472        {
 0473            if (value == null)
 0474            {
 0475                Remove(descriptor);
 0476            }
 477            else
 0478            {
 0479                SetParsedValue(descriptor, value);
 0480            }
 0481        }
 482
 483        public bool Remove(string name) =>
 0484            TryGetHeaderDescriptor(name, out HeaderDescriptor descriptor) &&
 0485            Remove(descriptor);
 486
 487        internal bool RemoveParsedValue(HeaderDescriptor descriptor, object value, bool removeAll = false)
 0488        {
 0489            Debug.Assert(value != null);
 490
 491            // If we have a value for this header, then verify if we have a single value. If so, compare that
 492            // value with 'item'. If we have a list of values, then remove 'item' from the list.
 0493            if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info))
 0494            {
 0495                Debug.Assert(descriptor.Parser != null, "Can't add parsed value if there is no parser available.");
 0496                Debug.Assert(descriptor.Parser.SupportsMultipleValues,
 0497                    "This method should not be used for single-value headers. Use Remove(string) instead.");
 498
 499                // If there is no entry, just return.
 0500                var parsedValue = info.ParsedAndInvalidValues;
 0501                if (parsedValue == null)
 0502                {
 0503                    return false;
 504                }
 505
 0506                bool result = false;
 0507                IEqualityComparer? comparer = descriptor.Parser.Comparer;
 508
 0509                List<object>? parsedValues = parsedValue as List<object>;
 0510                if (parsedValues == null)
 0511                {
 0512                    if (parsedValue is not InvalidValue)
 0513                    {
 0514                        Debug.Assert(parsedValue.GetType() == value.GetType(),
 0515                            "Stored value does not have the same type as 'value'.");
 516
 0517                        if (AreEqual(value, parsedValue, comparer))
 0518                        {
 0519                            info.ParsedAndInvalidValues = null;
 0520                            result = true;
 0521                        }
 0522                    }
 0523                }
 524                else
 0525                {
 0526                    for (int i = 0; i < parsedValues.Count; i++)
 0527                    {
 0528                        object item = parsedValues[i];
 0529                        if (item is not InvalidValue)
 0530                        {
 0531                            Debug.Assert(item.GetType() == value.GetType(),
 0532                                "One of the stored values does not have the same type as 'value'.");
 533
 0534                            if (AreEqual(value, item, comparer))
 0535                            {
 0536                                parsedValues.RemoveAt(i);
 0537                                i--;
 538
 0539                                if (!result)
 0540                                {
 0541                                    result = true;
 542
 0543                                    if (!removeAll)
 0544                                    {
 0545                                        break;
 546                                    }
 0547                                }
 548                                else
 0549                                {
 550                                    // We've removed a second item. Fallback to RemoveAll in case there are more to main
 551                                    // Create a copy of the locals to avoid the capture allocation in the common case.
 0552                                    object valueLocal = value;
 0553                                    IEqualityComparer? comparerLocal = comparer;
 0554                                    parsedValues.RemoveAll(item => item is not InvalidValue && AreEqual(valueLocal, item
 0555                                    break;
 556                                }
 0557                            }
 0558                        }
 0559                    }
 560
 561                    // If we removed the last item in a list, remove the list.
 0562                    if (parsedValues.Count == 0)
 0563                    {
 0564                        info.AssertContainsNoInvalidValues();
 0565                        info.ParsedAndInvalidValues = null;
 0566                    }
 0567                }
 568
 569                // If there is no value for the header left, remove the header.
 0570                if (info.IsEmpty)
 0571                {
 0572                    bool headerRemoved = Remove(descriptor);
 0573                    Debug.Assert(headerRemoved, $"Existing header '{descriptor.Name}' couldn't be removed.");
 0574                }
 575
 0576                return result;
 577            }
 578
 0579            return false;
 0580        }
 581
 582        internal bool ContainsParsedValue(HeaderDescriptor descriptor, object value)
 0583        {
 0584            Debug.Assert(value != null);
 585
 586            // If we have a value for this header, then verify if we have a single value. If so, compare that
 587            // value with 'item'. If we have a list of values, then compare each item in the list with 'item'.
 0588            if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info))
 0589            {
 0590                Debug.Assert(descriptor.Parser != null, "Can't add parsed value if there is no parser available.");
 0591                Debug.Assert(descriptor.Parser.SupportsMultipleValues,
 0592                    "This method should not be used for single-value headers. Use equality comparer instead.");
 593
 594                // If there is no entry, just return.
 0595                var parsedValue = info.ParsedAndInvalidValues;
 0596                if (parsedValue == null)
 0597                {
 0598                    return false;
 599                }
 600
 0601                List<object>? parsedValues = parsedValue as List<object>;
 602
 0603                IEqualityComparer? comparer = descriptor.Parser.Comparer;
 604
 0605                if (parsedValues == null)
 0606                {
 0607                    if (parsedValue is not InvalidValue)
 0608                    {
 0609                        Debug.Assert(parsedValue.GetType() == value.GetType(),
 0610                            "Stored value does not have the same type as 'value'.");
 611
 0612                        return AreEqual(value, parsedValue, comparer);
 613                    }
 0614                }
 615                else
 0616                {
 0617                    foreach (object item in parsedValues)
 0618                    {
 0619                        if (item is not InvalidValue)
 0620                        {
 0621                            Debug.Assert(item.GetType() == value.GetType(),
 0622                                "One of the stored values does not have the same type as 'value'.");
 623
 0624                            if (AreEqual(value, item, comparer))
 0625                            {
 0626                                return true;
 627                            }
 0628                        }
 0629                    }
 630
 0631                    return false;
 632                }
 0633            }
 634
 0635            return false;
 0636        }
 637
 638        internal virtual void AddHeaders(HttpHeaders sourceHeaders)
 0639        {
 0640            Debug.Assert(sourceHeaders != null);
 0641            Debug.Assert(GetType() == sourceHeaders.GetType(), "Can only copy headers from an instance of the same type.
 642
 643            // Only add header values if they're not already set on the message. Note that we don't merge
 644            // collections: If both the default headers and the message have set some values for a certain
 645            // header, then we don't try to merge the values.
 0646            if (_count == 0 && sourceHeaders._headerStore is HeaderEntry[] sourceEntries)
 0647            {
 648                // If the target collection is empty, we don't have to search for existing values
 0649                _count = sourceHeaders._count;
 0650                if (_headerStore is not HeaderEntry[] entries || entries.Length < _count)
 0651                {
 0652                    entries = new HeaderEntry[sourceEntries.Length];
 0653                    _headerStore = entries;
 0654                }
 655
 0656                for (int i = 0; i < _count && i < sourceEntries.Length; i++)
 0657                {
 0658                    HeaderEntry entry = sourceEntries[i];
 0659                    if (entry.Value is HeaderStoreItemInfo info)
 0660                    {
 0661                        entry.Value = CloneHeaderInfo(entry.Key, info);
 0662                    }
 0663                    entries[i] = entry;
 0664                }
 0665            }
 666            else
 0667            {
 0668                foreach (HeaderEntry entry in sourceHeaders.GetEntries())
 0669                {
 0670                    ref object? storeValueRef = ref GetValueRefOrAddDefault(entry.Key);
 0671                    if (storeValueRef is null)
 0672                    {
 0673                        object sourceValue = entry.Value;
 0674                        if (sourceValue is HeaderStoreItemInfo info)
 0675                        {
 0676                            storeValueRef = CloneHeaderInfo(entry.Key, info);
 0677                        }
 678                        else
 0679                        {
 0680                            Debug.Assert(sourceValue is string);
 0681                            storeValueRef = sourceValue;
 0682                        }
 0683                    }
 0684                }
 0685            }
 0686        }
 687
 688        private static HeaderStoreItemInfo CloneHeaderInfo(HeaderDescriptor descriptor, HeaderStoreItemInfo sourceInfo)
 0689        {
 0690            lock (sourceInfo)
 0691            {
 0692                var destinationInfo = new HeaderStoreItemInfo
 0693                {
 0694                    // Always copy raw values
 0695                    RawValue = CloneStringHeaderInfoValues(sourceInfo.RawValue)
 0696                };
 697
 0698                if (descriptor.Parser == null)
 0699                {
 0700                    sourceInfo.AssertContainsNoInvalidValues();
 0701                    destinationInfo.ParsedAndInvalidValues = CloneStringHeaderInfoValues(sourceInfo.ParsedAndInvalidValu
 0702                }
 703                else
 0704                {
 705                    // We have a parser, so we also have to clone invalid values and parsed values.
 0706                    if (sourceInfo.ParsedAndInvalidValues != null)
 0707                    {
 0708                        List<object>? sourceValues = sourceInfo.ParsedAndInvalidValues as List<object>;
 0709                        if (sourceValues == null)
 0710                        {
 0711                            CloneAndAddValue(destinationInfo, sourceInfo.ParsedAndInvalidValues);
 0712                        }
 713                        else
 0714                        {
 0715                            foreach (object item in sourceValues)
 0716                            {
 0717                                CloneAndAddValue(destinationInfo, item);
 0718                            }
 0719                        }
 0720                    }
 0721                }
 722
 0723                return destinationInfo;
 724            }
 0725        }
 726
 727        private static void CloneAndAddValue(HeaderStoreItemInfo destinationInfo, object source)
 0728        {
 729            // We only have one value. Clone it and assign it to the store.
 0730            if (source is ICloneable cloneableValue)
 0731            {
 0732                Debug.Assert(source is not InvalidValue);
 0733                AddParsedValue(destinationInfo, cloneableValue.Clone());
 0734            }
 735            else
 0736            {
 737                // If it doesn't implement ICloneable, it's a value type or an immutable type like String/Uri.
 0738                AddParsedValue(destinationInfo, source);
 0739            }
 0740        }
 741
 742        [return: NotNullIfNotNull(nameof(source))]
 743        private static object? CloneStringHeaderInfoValues(object? source)
 0744        {
 0745            if (source == null)
 0746            {
 0747                return null;
 748            }
 749
 0750            List<object>? sourceValues = source as List<object>;
 0751            if (sourceValues == null)
 0752            {
 753                // If we just have one value, return the reference to the string (strings are immutable so it's OK
 754                // to use the reference).
 0755                return source;
 756            }
 757            else
 0758            {
 759                // If we have a list of strings, create a new list and copy all strings to the new list.
 0760                return new List<object>(sourceValues);
 761            }
 0762        }
 763
 764        private HeaderStoreItemInfo GetOrCreateHeaderInfo(HeaderDescriptor descriptor)
 0765        {
 0766            if (TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info))
 0767            {
 0768                return info;
 769            }
 770            else
 0771            {
 0772                return CreateAndAddHeaderToStore(descriptor);
 773            }
 0774        }
 775
 776        private HeaderStoreItemInfo CreateAndAddHeaderToStore(HeaderDescriptor descriptor)
 0777        {
 0778            Debug.Assert(!Contains(descriptor));
 779
 780            // If we don't have the header in the store yet, add it now.
 0781            HeaderStoreItemInfo result = new HeaderStoreItemInfo();
 782
 783            // If the descriptor header type is in _treatAsCustomHeaderTypes, it must be converted to a custom header be
 0784            Debug.Assert((descriptor.HeaderType & _treatAsCustomHeaderTypes) == 0);
 785
 0786            AddEntryToStore(new HeaderEntry(descriptor, result));
 787
 0788            return result;
 0789        }
 790
 791        internal bool TryGetHeaderValue(HeaderDescriptor descriptor, [NotNullWhen(true)] out object? value)
 0792        {
 0793            ref object storeValueRef = ref GetValueRefOrNullRef(descriptor);
 0794            if (Unsafe.IsNullRef(ref storeValueRef))
 0795            {
 0796                value = null;
 0797                return false;
 798            }
 799            else
 0800            {
 0801                value = storeValueRef;
 0802                return true;
 803            }
 0804        }
 805
 806        private bool TryGetAndParseHeaderInfo(HeaderDescriptor key, [NotNullWhen(true)] out HeaderStoreItemInfo? info)
 7899807        {
 7899808            ref object storeValueRef = ref GetValueRefOrNullRef(key);
 7899809            if (!Unsafe.IsNullRef(ref storeValueRef))
 2251810            {
 2251811                object value = storeValueRef;
 812
 2251813                info = value is HeaderStoreItemInfo hsi
 2251814                    ? hsi
 2251815                    : ReplaceWithHeaderStoreItemInfo(ref storeValueRef, value);
 816
 2251817                ParseRawHeaderValues(key, info);
 2251818                return true;
 819            }
 820
 5648821            info = null;
 5648822            return false;
 7899823        }
 824
 825        /// <summary>
 826        /// Replaces <paramref name="storeValueRef"/> with a new <see cref="HeaderStoreItemInfo"/>,
 827        /// or returns the existing <see cref="HeaderStoreItemInfo"/> if a different thread beat us to it.
 828        /// </summary>
 829        /// <remarks>
 830        /// This helper should be used any time we're upgrading a storage slot from an unparsed string to a HeaderStoreI
 831        /// Concurrent writes to the header collection are UB, so we don't need to worry about race conditions when doin
 832        /// </remarks>
 833        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 834        private static HeaderStoreItemInfo ReplaceWithHeaderStoreItemInfo(ref object storeValueRef, object value)
 5549835        {
 5549836            Debug.Assert(value is string);
 837
 5549838            var info = new HeaderStoreItemInfo() { RawValue = value };
 5549839            object previousValue = Interlocked.CompareExchange(ref storeValueRef, info, value);
 840
 5549841            if (ReferenceEquals(previousValue, value))
 5549842            {
 5549843                return info;
 844            }
 845
 846            // Rare race condition: Another thread replaced the value with a HeaderStoreItemInfo.
 0847            return (HeaderStoreItemInfo)previousValue;
 5549848        }
 849
 850        private static void ParseRawHeaderValues(HeaderDescriptor descriptor, HeaderStoreItemInfo info)
 13365851        {
 852            // Unlike TryGetHeaderInfo() this method tries to parse all non-validated header values (if any)
 853            // before returning to the caller.
 13365854            lock (info)
 13365855            {
 13365856                Debug.Assert(!info.IsEmpty);
 13365857                if (info.RawValue != null)
 8863858                {
 8863859                    if (info.RawValue is List<string> rawValues)
 3314860                    {
 23198861                        foreach (string rawValue in rawValues)
 6628862                        {
 6628863                            ParseSingleRawHeaderValue(info, descriptor, rawValue);
 6628864                        }
 3314865                    }
 866                    else
 5549867                    {
 5549868                        string? rawValue = info.RawValue as string;
 5549869                        Debug.Assert(rawValue is not null);
 5549870                        ParseSingleRawHeaderValue(info, descriptor, rawValue);
 5549871                    }
 872
 873                    // At this point all values are either in info.ParsedValue, info.InvalidValue. Reset RawValue.
 8863874                    Debug.Assert(info.ParsedAndInvalidValues is not null);
 8863875                    info.RawValue = null;
 8863876                }
 13365877            }
 13365878        }
 879
 880        private static void ParseSingleRawHeaderValue(HeaderStoreItemInfo info, HeaderDescriptor descriptor, string rawV
 12177881        {
 12177882            Debug.Assert(Monitor.IsEntered(info));
 12177883            if (descriptor.Parser == null)
 6628884            {
 6628885                if (HttpRuleParser.ContainsNewLineOrNull(rawValue))
 0886                {
 0887                    if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(null, SR.Format(SR.net_http_log_headers_no_
 0888                    AddInvalidValue(info, rawValue);
 0889                }
 890                else
 6628891                {
 6628892                    AddParsedValue(info, rawValue);
 6628893                }
 6628894            }
 895            else
 5549896            {
 5549897                if (!TryParseAndAddRawHeaderValue(descriptor, info, rawValue, true))
 3199898                {
 3199899                    if (NetEventSource.Log.IsEnabled()) NetEventSource.Log.HeadersInvalidValue(descriptor.Name, rawValue
 3199900                }
 5549901            }
 12177902        }
 903
 904        // See Add(name, string)
 905        internal bool TryParseAndAddValue(HeaderDescriptor descriptor, string? value)
 0906        {
 907            // We don't use GetOrCreateHeaderInfo() here, since this would create a new header in the store. If parsing
 908            // the value then throws, we would have to remove the header from the store again. So just get a
 909            // HeaderStoreItemInfo object and try to parse the value. If it works, we'll add the header.
 910            HeaderStoreItemInfo info;
 911            bool addToStore;
 0912            PrepareHeaderInfoForAdd(descriptor, out info, out addToStore);
 913
 0914            bool result = TryParseAndAddRawHeaderValue(descriptor, info, value, false);
 915
 0916            if (result && addToStore && (info.ParsedAndInvalidValues != null))
 0917            {
 0918                info.AssertContainsNoInvalidValues();
 919                // If we get here, then the value could be parsed correctly. If we created a new HeaderStoreItemInfo, ad
 920                // it to the store if we added at least one value.
 0921                Debug.Assert(!Contains(descriptor));
 0922                AddEntryToStore(new HeaderEntry(descriptor, info));
 0923            }
 924
 0925            return result;
 0926        }
 927
 928        // See ParseAndAddValue
 929        private static bool TryParseAndAddRawHeaderValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, string? 
 5549930        {
 5549931            Debug.Assert(info != null);
 5549932            Debug.Assert(descriptor.Parser != null);
 933
 934            // Values are added as 'invalid' if we either can't parse the value OR if we already have a value
 935            // and the current header doesn't support multiple values: e.g. trying to add a date/time value
 936            // to the 'Date' header if we already have a date/time value will result in the second value being
 937            // added to the 'invalid' header values.
 5549938            if (!info.CanAddParsedValue(descriptor.Parser))
 0939            {
 0940                if (addWhenInvalid)
 0941                {
 0942                    AddInvalidValue(info, value ?? string.Empty);
 0943                }
 0944                return false;
 945            }
 946
 5549947            int index = 0;
 948
 5549949            if (descriptor.Parser.TryParseValue(value, info.ParsedAndInvalidValues, ref index, out object? parsedValue))
 3264950            {
 951                // The raw string only represented one value (which was successfully parsed). Add the value and return.
 3264952                if ((value == null) || (index == value.Length))
 1114953                {
 1114954                    if (parsedValue != null)
 1015955                    {
 1015956                        AddParsedValue(info, parsedValue);
 1015957                    }
 99958                    else if (addWhenInvalid && info.ParsedAndInvalidValues is null)
 99959                    {
 99960                        AddInvalidValue(info, value ?? string.Empty);
 99961                    }
 1114962                    return true;
 963                }
 2150964                Debug.Assert(index < value.Length, "Parser must return an index value within the string length.");
 965
 966                // If we successfully parsed a value, but there are more left to read, store the results in a temp
 967                // list. Only when all values are parsed successfully write the list to the store.
 2150968                List<object> parsedValues = new List<object>();
 2150969                if (parsedValue != null)
 2150970                {
 2150971                    parsedValues.Add(parsedValue);
 2150972                }
 973
 46977974                while (index < value.Length)
 45741975                {
 45741976                    if (descriptor.Parser.TryParseValue(value, info.ParsedAndInvalidValues, ref index, out parsedValue))
 44827977                    {
 44827978                        if (parsedValue != null)
 44827979                        {
 44827980                            parsedValues.Add(parsedValue);
 44827981                        }
 44827982                    }
 983                    else
 914984                    {
 914985                        if (addWhenInvalid)
 914986                        {
 914987                            AddInvalidValue(info, value);
 914988                        }
 914989                        return false;
 990                    }
 44827991                }
 992
 993                // All values were parsed correctly. Copy results to the store.
 74292994                foreach (object item in parsedValues)
 35292995                {
 35292996                    AddParsedValue(info, item);
 35292997                }
 998
 1236999                if (parsedValues.Count == 0 && addWhenInvalid && info.ParsedAndInvalidValues is null)
 01000                {
 01001                    AddInvalidValue(info, value);
 01002                }
 1003
 12361004                return true;
 1005            }
 1006
 22851007            Debug.Assert(value != null);
 22851008            if (addWhenInvalid)
 22851009            {
 22851010                AddInvalidValue(info, value ?? string.Empty);
 22851011            }
 22851012            return false;
 55491013        }
 1014
 1015        private static void AddParsedValue(HeaderStoreItemInfo info, object value)
 1151021016        {
 1151021017            Debug.Assert(!(value is List<object>),
 1151021018                "Header value types must not derive from List<object> since this type is used internally to store " +
 1151021019                "lists of values. So we would not be able to distinguish between a single value and a list of values.");
 1020
 1151021021            AddValueToStoreValue<object>(value, ref info.ParsedAndInvalidValues);
 1151021022        }
 1023
 1024        private static void AddInvalidValue(HeaderStoreItemInfo info, string value)
 32981025        {
 32981026            AddValueToStoreValue<object>(new InvalidValue(value), ref info.ParsedAndInvalidValues);
 32981027        }
 1028
 1029        private static void AddRawValue(HeaderStoreItemInfo info, string value)
 33141030        {
 33141031            AddValueToStoreValue<string>(value, ref info.RawValue);
 33141032        }
 1033
 1034        private static void AddValueToStoreValue<T>(T value, ref object? currentStoreValue) where T : class
 1217141035        {
 1036            // If there is no value set yet, then add current item as value (we don't create a list
 1037            // if not required). If 'info.Value' is already assigned then make sure 'info.Value' is a
 1038            // List<T> and append 'item' to the list.
 1217141039            if (currentStoreValue == null)
 111141040            {
 111141041                currentStoreValue = value;
 111141042            }
 1043            else
 1106001044            {
 1106001045                List<T>? storeValues = currentStoreValue as List<T>;
 1046
 1106001047                if (storeValues == null)
 96681048                {
 96681049                    storeValues = new List<T>(2);
 96681050                    Debug.Assert(currentStoreValue is T);
 96681051                    storeValues.Add((T)currentStoreValue);
 96681052                    currentStoreValue = storeValues;
 96681053                }
 1106001054                Debug.Assert(value is T);
 1106001055                storeValues.Add((T)value);
 1106001056            }
 1217141057        }
 1058
 1059        internal object? GetSingleParsedValue(HeaderDescriptor descriptor)
 01060        {
 01061            if (!TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info))
 01062            {
 01063                return null;
 1064            }
 1065
 01066            return info.GetSingleParsedValue();
 01067        }
 1068
 1069        internal object? GetParsedAndInvalidValues(HeaderDescriptor descriptor)
 01070        {
 01071            if (!TryGetAndParseHeaderInfo(descriptor, out HeaderStoreItemInfo? info))
 01072            {
 01073                return null;
 1074            }
 1075
 01076            return info.ParsedAndInvalidValues;
 01077        }
 1078
 77251079        internal virtual bool IsAllowedHeaderName(HeaderDescriptor descriptor) => true;
 1080
 1081        private void CheckIsAllowedHeaderName(HeaderDescriptor descriptor)
 152741082        {
 152741083            if (!IsAllowedHeaderName(descriptor))
 01084            {
 01085                throw new InvalidOperationException(SR.Format(SR.net_http_headers_not_allowed_header_name, descriptor.Na
 1086            }
 152741087        }
 1088
 1089        private void PrepareHeaderInfoForAdd(HeaderDescriptor descriptor, out HeaderStoreItemInfo info, out bool addToSt
 78991090        {
 78991091            CheckIsAllowedHeaderName(descriptor);
 1092
 78991093            addToStore = false;
 78991094            if (!TryGetAndParseHeaderInfo(descriptor, out info!))
 56481095            {
 56481096                info = new HeaderStoreItemInfo();
 56481097                addToStore = true;
 56481098            }
 78991099        }
 1100
 1101        private static void ParseAndAddValue(HeaderDescriptor descriptor, HeaderStoreItemInfo info, string? value)
 78991102        {
 78991103            Debug.Assert(info != null);
 78991104            Debug.Assert(descriptor.Parser != null);
 1105
 1106            // If the header only supports 1 value, we can add the current value only if there is no
 1107            // value already set.
 78991108            if (!info.CanAddParsedValue(descriptor.Parser))
 711109            {
 711110                throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_heade
 1111            }
 1112
 78281113            int index = 0;
 78281114            object parsedValue = descriptor.Parser.ParseValue(value, info.ParsedAndInvalidValues, ref index);
 1115
 1116            // The raw string only represented one value (which was successfully parsed). Add the value and return.
 1117            // If value is null we still have to first call ParseValue() to allow the parser to decide whether null is
 1118            // a valid value. If it is (i.e. no exception thrown), we set the parsed value (if any) and return.
 55431119            if ((value == null) || (index == value.Length))
 21571120            {
 1121                // If the returned value is null, then it means the header accepts empty values. i.e. we don't throw
 1122                // but we don't add 'null' to the store either.
 21571123                if (parsedValue != null)
 15831124                {
 15831125                    AddParsedValue(info, parsedValue);
 15831126                }
 21571127                return;
 1128            }
 33861129            Debug.Assert(index < value.Length, "Parser must return an index value within the string length.");
 1130
 1131            // If we successfully parsed a value, but there are more left to read, store the results in a temp
 1132            // list. Only when all values are parsed successfully write the list to the store.
 33861133            List<object> parsedValues = new List<object>();
 33861134            if (parsedValue != null)
 33861135            {
 33861136                parsedValues.Add(parsedValue);
 33861137            }
 1138
 822691139            while (index < value.Length)
 797971140            {
 797971141                parsedValue = descriptor.Parser.ParseValue(value, info.ParsedAndInvalidValues, ref index);
 788831142                if (parsedValue != null)
 788831143                {
 788831144                    parsedValues.Add(parsedValue);
 788831145                }
 788831146            }
 1147
 1148            // All values were parsed correctly. Copy results to the store.
 1485841149            foreach (object item in parsedValues)
 705841150            {
 705841151                AddParsedValue(info, item);
 705841152            }
 46291153        }
 1154
 1155        internal HeaderDescriptor GetHeaderDescriptor(string name)
 152741156        {
 152741157            ArgumentException.ThrowIfNullOrEmpty(name);
 1158
 152741159            if (!HeaderDescriptor.TryGet(name, out HeaderDescriptor descriptor))
 01160            {
 01161                throw new FormatException(SR.Format(SR.net_http_headers_invalid_header_name, name));
 1162            }
 1163
 152741164            if ((descriptor.HeaderType & _allowedHeaderTypes) != 0)
 89291165            {
 89291166                return descriptor;
 1167            }
 63451168            else if ((descriptor.HeaderType & _treatAsCustomHeaderTypes) != 0)
 63451169            {
 63451170                return descriptor.AsCustomHeader();
 1171            }
 1172
 01173            throw new InvalidOperationException(SR.Format(SR.net_http_headers_not_allowed_header_name, name));
 152741174        }
 1175
 1176        internal bool TryGetHeaderDescriptor(string name, out HeaderDescriptor descriptor)
 142381177        {
 142381178            if (string.IsNullOrEmpty(name))
 01179            {
 01180                descriptor = default;
 01181                return false;
 1182            }
 1183
 142381184            if (HeaderDescriptor.TryGet(name, out descriptor))
 142381185            {
 142381186                HttpHeaderType headerType = descriptor.HeaderType;
 1187
 142381188                if ((headerType & _allowedHeaderTypes) != 0)
 62381189                {
 62381190                    return true;
 1191                }
 1192
 80001193                if ((headerType & _treatAsCustomHeaderTypes) != 0)
 33721194                {
 33721195                    descriptor = descriptor.AsCustomHeader();
 33721196                    return true;
 1197                }
 46281198            }
 1199
 46281200            return false;
 142381201        }
 1202
 1203        internal static void CheckContainsNewLineOrNull(string? value)
 711541204        {
 711541205            if (value == null)
 562861206            {
 562861207                return;
 1208            }
 1209
 148681210            if (HttpRuleParser.ContainsNewLineOrNull(value))
 7471211            {
 7471212                throw new FormatException(SR.net_http_headers_no_newlines_no_nul);
 1213            }
 704071214        }
 1215
 1216        internal static string[] GetStoreValuesAsStringArray(HeaderDescriptor descriptor, HeaderStoreItemInfo info)
 111141217        {
 111141218            GetStoreValuesAsStringOrStringArray(descriptor, info, out string? singleValue, out string[]? multiValue);
 111141219            Debug.Assert(singleValue is not null ^ multiValue is not null);
 111141220            return multiValue ?? new[] { singleValue! };
 111141221        }
 1222
 1223        internal static void GetStoreValuesAsStringOrStringArray(HeaderDescriptor descriptor, object sourceValues, out s
 166791224        {
 166791225            HeaderStoreItemInfo? info = sourceValues as HeaderStoreItemInfo;
 166791226            if (info is null)
 01227            {
 01228                Debug.Assert(sourceValues is string);
 01229                singleValue = (string)sourceValues;
 01230                multiValue = null;
 01231                return;
 1232            }
 1233
 166791234            lock (info)
 166791235            {
 166791236                int length = GetValueCount(info);
 1237
 1238                scoped Span<string?> values;
 166791239                singleValue = null;
 166791240                if (length == 1)
 52071241                {
 52071242                    multiValue = null;
 52071243                    values = new Span<string?>(ref singleValue);
 52071244                }
 1245                else
 114721246                {
 114721247                    Debug.Assert(length > 1, "The header should have been removed when it became empty");
 114721248                    values = (multiValue = new string[length])!;
 114721249                }
 1250
 166791251                int currentIndex = 0;
 166791252                ReadStoreValues<object?>(values, info.ParsedAndInvalidValues, descriptor.Parser, ref currentIndex);
 166791253                ReadStoreValues<string?>(values, info.RawValue, null, ref currentIndex);
 1254
 166791255                Debug.Assert(currentIndex == length);
 166791256            }
 166791257        }
 1258
 1259        internal static int GetStoreValuesIntoStringArray(HeaderDescriptor descriptor, object sourceValues, [NotNull] re
 01260        {
 01261            values ??= Array.Empty<string>();
 1262
 01263            HeaderStoreItemInfo? info = sourceValues as HeaderStoreItemInfo;
 01264            if (info is null)
 01265            {
 01266                Debug.Assert(sourceValues is string);
 1267
 01268                if (values.Length == 0)
 01269                {
 01270                    values = new string[1];
 01271                }
 1272
 01273                values[0] = (string)sourceValues;
 01274                return 1;
 1275            }
 1276
 01277            lock (info)
 01278            {
 01279                int length = GetValueCount(info);
 01280                Debug.Assert(length > 0);
 1281
 01282                if (values.Length < length)
 01283                {
 01284                    values = new string[length];
 01285                }
 1286
 01287                int currentIndex = 0;
 01288                ReadStoreValues<object?>(values!, info.ParsedAndInvalidValues, descriptor.Parser, ref currentIndex);
 01289                ReadStoreValues<string?>(values!, info.RawValue, null, ref currentIndex);
 01290                Debug.Assert(currentIndex == length);
 1291
 01292                return length;
 1293            }
 01294        }
 1295
 1296        private static int GetValueCount(HeaderStoreItemInfo info)
 166791297        {
 166791298            Debug.Assert(info != null);
 166791299            Debug.Assert(Monitor.IsEntered(info));
 1300
 166791301            return Count<object>(info.ParsedAndInvalidValues) + Count<string>(info.RawValue);
 1302
 1303            static int Count<T>(object? valueStore) =>
 333581304                valueStore is null ? 0 :
 333581305                valueStore is List<T> list ? list.Count :
 333581306                1;
 166791307        }
 1308
 1309        private static void ReadStoreValues<T>(Span<string?> values, object? storeValue, HttpHeaderParser? parser, ref i
 333581310        {
 333581311            if (storeValue != null)
 166791312            {
 166791313                List<T>? storeValues = storeValue as List<T>;
 1314
 166791315                if (storeValues == null)
 52071316                {
 52071317                    values[currentIndex] = parser == null || storeValue is InvalidValue ? storeValue.ToString() : parser
 52071318                    currentIndex++;
 52071319                }
 1320                else
 114721321                {
 4183921322                    foreach (object? item in storeValues)
 1919881323                    {
 1919881324                        Debug.Assert(item != null);
 1919881325                        values[currentIndex] = parser == null || item is InvalidValue ? item.ToString() : parser.ToStrin
 1919881326                        currentIndex++;
 1919881327                    }
 114721328                }
 166791329            }
 333581330        }
 1331
 1332        private static bool AreEqual(object value, object? storeValue, IEqualityComparer? comparer)
 01333        {
 01334            Debug.Assert(value != null);
 1335
 01336            if (comparer != null)
 01337            {
 01338                return comparer.Equals(value, storeValue);
 1339            }
 1340
 1341            // We don't have a comparer, so use the Equals() method.
 01342            return value.Equals(storeValue);
 01343        }
 1344
 1345        internal sealed class InvalidValue
 1346        {
 1347            private readonly string _value;
 1348
 32981349            public InvalidValue(string value)
 32981350            {
 32981351                Debug.Assert(value is not null);
 32981352                _value = value;
 32981353            }
 1354
 32981355            public override string ToString() => _value;
 1356        }
 1357
 1358        internal sealed class HeaderStoreItemInfo
 1359        {
 435331360            internal HeaderStoreItemInfo() { }
 1361
 1362            internal object? RawValue;
 1363            internal object? ParsedAndInvalidValues;
 1364
 1365            public bool CanAddParsedValue(HttpHeaderParser parser)
 134481366            {
 134481367                Debug.Assert(parser != null, "There should be no reason to call CanAddValue if there is no parser for th
 1368
 1369                // If the header only supports one value, and we have already a value set, then we can't add
 1370                // another value. E.g. the 'Date' header only supports one value. We can't add multiple timestamps
 1371                // to 'Date'.
 1372                // So if this is a known header, ask the parser if it supports multiple values and check whether
 1373                // we already have a (valid or invalid) value.
 1374                // Note that we ignore the rawValue by purpose: E.g. we are parsing 2 raw values for a header only
 1375                // supporting 1 value. When the first value gets parsed, CanAddValue returns true and we add the
 1376                // parsed value to ParsedValue. When the second value is parsed, CanAddValue returns false, because
 1377                // we have already a parsed value.
 134481378                return parser.SupportsMultipleValues || ParsedAndInvalidValues is null;
 134481379            }
 1380
 1381            [Conditional("DEBUG")]
 1382            public void AssertContainsNoInvalidValues()
 22511383            {
 22511384                if (ParsedAndInvalidValues is not null)
 22511385                {
 22511386                    if (ParsedAndInvalidValues is List<object> list)
 12361387                    {
 742921388                        foreach (object item in list)
 352921389                        {
 352921390                            Debug.Assert(item is not InvalidValue);
 352921391                        }
 12361392                    }
 1393                    else
 10151394                    {
 10151395                        Debug.Assert(ParsedAndInvalidValues is not InvalidValue);
 10151396                    }
 22511397                }
 22511398            }
 1399
 1400            public object? GetSingleParsedValue()
 01401            {
 01402                if (ParsedAndInvalidValues is not null)
 01403                {
 01404                    if (ParsedAndInvalidValues is List<object> list)
 01405                    {
 01406                        AssertContainsSingleParsedValue(list);
 01407                        foreach (object item in list)
 01408                        {
 01409                            if (item is not InvalidValue)
 01410                            {
 01411                                return item;
 1412                            }
 01413                        }
 01414                    }
 1415                    else
 01416                    {
 01417                        if (ParsedAndInvalidValues is not InvalidValue)
 01418                        {
 01419                            return ParsedAndInvalidValues;
 1420                        }
 01421                    }
 01422                }
 1423
 01424                return null;
 01425            }
 1426
 1427            [Conditional("DEBUG")]
 1428            private static void AssertContainsSingleParsedValue(List<object> list)
 01429            {
 01430                int count = 0;
 01431                foreach (object item in list)
 01432                {
 01433                    if (item is not InvalidValue)
 01434                    {
 01435                        count++;
 01436                    }
 01437                }
 1438
 01439                Debug.Assert(count == 1, "Only a single parsed value should be stored for this parser");
 01440            }
 1441
 133651442            public bool IsEmpty => RawValue == null && ParsedAndInvalidValues == null;
 1443        }
 1444
 1445
 1446        #region Low-level implementation details that work with _headerStore directly
 1447
 1448        private const int InitialCapacity = 4;
 1449        internal const int ArrayThreshold = 64; // Above this threshold, header ordering will not be preserved
 1450
 1451        internal HeaderEntry[]? GetEntriesArray()
 247851452        {
 247851453            object? store = _headerStore;
 247851454            if (store is null)
 01455            {
 01456                return null;
 1457            }
 247851458            else if (store is HeaderEntry[] entries)
 247851459            {
 247851460                return entries;
 1461            }
 1462            else
 01463            {
 01464                return GetEntriesFromDictionary();
 1465            }
 1466
 1467            HeaderEntry[] GetEntriesFromDictionary()
 01468            {
 01469                var dictionary = (Dictionary<HeaderDescriptor, object>)_headerStore!;
 01470                var entries = new HeaderEntry[dictionary.Count];
 01471                int i = 0;
 01472                foreach (KeyValuePair<HeaderDescriptor, object> entry in dictionary)
 01473                {
 01474                    entries[i++] = new HeaderEntry
 01475                    {
 01476                        Key = entry.Key,
 01477                        Value = entry.Value
 01478                    };
 01479                }
 01480                return entries;
 01481            }
 247851482        }
 1483
 1484        internal ReadOnlySpan<HeaderEntry> GetEntries()
 01485        {
 01486            return new ReadOnlySpan<HeaderEntry>(GetEntriesArray(), 0, _count);
 01487        }
 1488
 96101489        internal int Count => _count;
 1490
 55491491        private bool EntriesAreLiveView => _headerStore is HeaderEntry[];
 1492
 1493        private ref object GetValueRefOrNullRef(HeaderDescriptor key)
 124011494        {
 124011495            ref object valueRef = ref Unsafe.NullRef<object>();
 1496
 124011497            object? store = _headerStore;
 124011498            if (store is HeaderEntry[] entries)
 124011499            {
 248021500                for (int i = 0; i < _count && i < entries.Length; i++)
 22511501                {
 22511502                    if (key.Equals(entries[i].Key))
 22511503                    {
 22511504                        valueRef = ref entries[i].Value;
 22511505                        break;
 1506                    }
 01507                }
 124011508            }
 01509            else if (store is not null)
 01510            {
 01511                valueRef = ref CollectionsMarshal.GetValueRefOrNullRef((Dictionary<HeaderDescriptor, object>)store, key)
 01512            }
 1513
 124011514            return ref valueRef;
 124011515        }
 1516
 1517        private ref object? GetValueRefOrAddDefault(HeaderDescriptor key)
 162381518        {
 162381519            object? store = _headerStore;
 162381520            if (store is HeaderEntry[] entries)
 162351521            {
 324701522                for (int i = 0; i < _count && i < entries.Length; i++)
 33141523                {
 33141524                    if (key.Equals(entries[i].Key))
 33141525                    {
 33141526                        return ref entries[i].Value!;
 1527                    }
 01528                }
 1529
 129211530                int count = _count;
 129211531                _count++;
 129211532                if ((uint)count < (uint)entries.Length)
 129211533                {
 129211534                    entries[count].Key = key;
 129211535                    return ref entries[count].Value!;
 1536                }
 1537
 01538                return ref GrowEntriesAndAddDefault(key);
 1539            }
 31540            else if (store is null)
 31541            {
 31542                _count++;
 31543                entries = new HeaderEntry[InitialCapacity];
 31544                _headerStore = entries;
 31545                entries[0].Key = key;
 31546                return ref entries[0].Value!;
 1547            }
 1548            else
 01549            {
 01550                return ref DictionaryGetValueRefOrAddDefault(key);
 1551            }
 1552
 1553            ref object? GrowEntriesAndAddDefault(HeaderDescriptor key)
 01554            {
 01555                var entries = (HeaderEntry[])_headerStore!;
 01556                if (entries.Length == ArrayThreshold)
 01557                {
 01558                    return ref ConvertToDictionaryAndAddDefault(key);
 1559                }
 1560                else
 01561                {
 01562                    Array.Resize(ref entries, entries.Length << 1);
 01563                    _headerStore = entries;
 01564                    ref HeaderEntry firstNewEntry = ref entries[entries.Length >> 1];
 01565                    firstNewEntry.Key = key;
 01566                    return ref firstNewEntry.Value!;
 1567                }
 01568            }
 1569
 1570            ref object? ConvertToDictionaryAndAddDefault(HeaderDescriptor key)
 01571            {
 01572                var entries = (HeaderEntry[])_headerStore!;
 01573                var dictionary = new Dictionary<HeaderDescriptor, object>(ArrayThreshold);
 01574                _headerStore = dictionary;
 01575                foreach (HeaderEntry entry in entries)
 01576                {
 01577                    dictionary.Add(entry.Key, entry.Value);
 01578                }
 01579                Debug.Assert(dictionary.Count == _count - 1);
 01580                return ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out _);
 01581            }
 1582
 1583            ref object? DictionaryGetValueRefOrAddDefault(HeaderDescriptor key)
 01584            {
 01585                var dictionary = (Dictionary<HeaderDescriptor, object>)_headerStore!;
 01586                ref object? value = ref CollectionsMarshal.GetValueRefOrAddDefault(dictionary, key, out _);
 01587                if (value is null)
 01588                {
 01589                    _count++;
 01590                }
 01591                return ref value;
 01592            }
 162381593        }
 1594
 1595        private void AddEntryToStore(HeaderEntry entry)
 22511596        {
 22511597            Debug.Assert(!Contains(entry.Key));
 1598
 22511599            if (_headerStore is HeaderEntry[] entries)
 22511600            {
 22511601                int count = _count;
 22511602                if ((uint)count < (uint)entries.Length)
 22511603                {
 22511604                    entries[count] = entry;
 22511605                    _count++;
 22511606                    return;
 1607                }
 01608            }
 1609
 01610            GetValueRefOrAddDefault(entry.Key) = entry.Value;
 22511611        }
 1612
 1613        internal bool Contains(HeaderDescriptor key)
 45021614        {
 45021615            return !Unsafe.IsNullRef(ref GetValueRefOrNullRef(key));
 45021616        }
 1617
 1618        public void Clear()
 238481619        {
 238481620            if (_headerStore is HeaderEntry[] entries)
 238391621            {
 238391622                Array.Clear(entries, 0, _count);
 238391623            }
 1624            else
 91625            {
 91626                _headerStore = null;
 91627            }
 238481628            _count = 0;
 238481629        }
 1630
 1631        internal bool Remove(HeaderDescriptor key)
 01632        {
 01633            bool removed = false;
 1634
 01635            object? store = _headerStore;
 01636            if (store is HeaderEntry[] entries)
 01637            {
 01638                for (int i = 0; i < _count && i < entries.Length; i++)
 01639                {
 01640                    if (key.Equals(entries[i].Key))
 01641                    {
 01642                        while (i + 1 < _count && (uint)(i + 1) < (uint)entries.Length)
 01643                        {
 01644                            entries[i] = entries[i + 1];
 01645                            i++;
 01646                        }
 01647                        entries[i] = default;
 01648                        removed = true;
 01649                        break;
 1650                    }
 01651                }
 01652            }
 01653            else if (store is not null)
 01654            {
 01655                removed = ((Dictionary<HeaderDescriptor, object>)store).Remove(key);
 01656            }
 1657
 01658            if (removed)
 01659            {
 01660                _count--;
 01661            }
 1662
 01663            return removed;
 01664        }
 1665
 1666        #endregion // _headerStore implementation
 1667    }
 1668}
 1669

Methods/Properties

.ctor()
.ctor(System.Net.Http.Headers.HttpHeaderType,System.Net.Http.Headers.HttpHeaderType)
NonValidated()
Add(System.String,System.String)
Add(System.Net.Http.Headers.HeaderDescriptor,System.String)
Add(System.String,System.Collections.Generic.IEnumerable`1<System.String>)
Add(System.Net.Http.Headers.HeaderDescriptor,System.Collections.Generic.IEnumerable`1<System.String>)
TryAddWithoutValidation(System.String,System.String)
TryAddWithoutValidation(System.Net.Http.Headers.HeaderDescriptor,System.String)
TryAddWithoutValidation(System.String,System.Collections.Generic.IEnumerable`1<System.String>)
TryAddWithoutValidation(System.Net.Http.Headers.HeaderDescriptor,System.Collections.Generic.IEnumerable`1<System.String>)
GetValues(System.String)
GetValues(System.Net.Http.Headers.HeaderDescriptor)
TryGetValues(System.String,System.Collections.Generic.IEnumerable`1<System.String>&)
TryGetValues(System.Net.Http.Headers.HeaderDescriptor,System.Collections.Generic.IEnumerable`1<System.String>&)
Contains(System.String)
ToString()
Dump(System.Text.ValueStringBuilder&,System.Boolean)
GetHeaderString(System.Net.Http.Headers.HeaderDescriptor)
GetEnumerator()
GetEnumeratorCore()
System.Collections.IEnumerable.GetEnumerator()
AddParsedValue(System.Net.Http.Headers.HeaderDescriptor,System.Object)
SetParsedValue(System.Net.Http.Headers.HeaderDescriptor,System.Object)
SetOrRemoveParsedValue(System.Net.Http.Headers.HeaderDescriptor,System.Object)
Remove(System.String)
RemoveParsedValue(System.Net.Http.Headers.HeaderDescriptor,System.Object,System.Boolean)
ContainsParsedValue(System.Net.Http.Headers.HeaderDescriptor,System.Object)
AddHeaders(System.Net.Http.Headers.HttpHeaders)
CloneHeaderInfo(System.Net.Http.Headers.HeaderDescriptor,System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo)
CloneAndAddValue(System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo,System.Object)
CloneStringHeaderInfoValues(System.Object)
GetOrCreateHeaderInfo(System.Net.Http.Headers.HeaderDescriptor)
CreateAndAddHeaderToStore(System.Net.Http.Headers.HeaderDescriptor)
TryGetHeaderValue(System.Net.Http.Headers.HeaderDescriptor,System.Object&)
TryGetAndParseHeaderInfo(System.Net.Http.Headers.HeaderDescriptor,System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo&)
ReplaceWithHeaderStoreItemInfo(System.Object&,System.Object)
ParseRawHeaderValues(System.Net.Http.Headers.HeaderDescriptor,System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo)
ParseSingleRawHeaderValue(System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo,System.Net.Http.Headers.HeaderDescriptor,System.String)
TryParseAndAddValue(System.Net.Http.Headers.HeaderDescriptor,System.String)
TryParseAndAddRawHeaderValue(System.Net.Http.Headers.HeaderDescriptor,System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo,System.String,System.Boolean)
AddParsedValue(System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo,System.Object)
AddInvalidValue(System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo,System.String)
AddRawValue(System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo,System.String)
AddValueToStoreValue(T,System.Object&)
GetSingleParsedValue(System.Net.Http.Headers.HeaderDescriptor)
GetParsedAndInvalidValues(System.Net.Http.Headers.HeaderDescriptor)
IsAllowedHeaderName(System.Net.Http.Headers.HeaderDescriptor)
CheckIsAllowedHeaderName(System.Net.Http.Headers.HeaderDescriptor)
PrepareHeaderInfoForAdd(System.Net.Http.Headers.HeaderDescriptor,System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo&,System.Boolean&)
ParseAndAddValue(System.Net.Http.Headers.HeaderDescriptor,System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo,System.String)
GetHeaderDescriptor(System.String)
TryGetHeaderDescriptor(System.String,System.Net.Http.Headers.HeaderDescriptor&)
CheckContainsNewLineOrNull(System.String)
GetStoreValuesAsStringArray(System.Net.Http.Headers.HeaderDescriptor,System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo)
GetStoreValuesAsStringOrStringArray(System.Net.Http.Headers.HeaderDescriptor,System.Object,System.String&,System.String[]&)
GetStoreValuesIntoStringArray(System.Net.Http.Headers.HeaderDescriptor,System.Object,System.String[]&)
GetValueCount(System.Net.Http.Headers.HttpHeaders/HeaderStoreItemInfo)
Count(System.Object)
ReadStoreValues(System.Span`1<System.String>,System.Object,System.Net.Http.Headers.HttpHeaderParser,System.Int32&)
AreEqual(System.Object,System.Object,System.Collections.IEqualityComparer)
.ctor(System.String)
ToString()
.ctor()
CanAddParsedValue(System.Net.Http.Headers.HttpHeaderParser)
AssertContainsNoInvalidValues()
GetSingleParsedValue()
AssertContainsSingleParsedValue(System.Collections.Generic.List`1<System.Object>)
IsEmpty()
GetEntriesArray()
GetEntriesFromDictionary()
GetEntries()
Count()
EntriesAreLiveView()
GetValueRefOrNullRef(System.Net.Http.Headers.HeaderDescriptor)
GetValueRefOrAddDefault(System.Net.Http.Headers.HeaderDescriptor)
GrowEntriesAndAddDefault(System.Net.Http.Headers.HeaderDescriptor)
ConvertToDictionaryAndAddDefault(System.Net.Http.Headers.HeaderDescriptor)
DictionaryGetValueRefOrAddDefault(System.Net.Http.Headers.HeaderDescriptor)
AddEntryToStore(System.Net.Http.Headers.HeaderEntry)
Contains(System.Net.Http.Headers.HeaderDescriptor)
Clear()
Remove(System.Net.Http.Headers.HeaderDescriptor)