< Summary

Information
Class: System.Net.Http.Headers.CacheControlHeaderValue
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\CacheControlHeaderValue.cs
Line coverage
21%
Covered lines: 74
Uncovered lines: 272
Coverable lines: 346
Total lines: 612
Line coverage: 21.3%
Branch coverage
28%
Covered branches: 54
Total branches: 190
Branch coverage: 28.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%11100%
SetTimeSpan(...)100%110%
SetFlag(...)0%220%
.ctor()100%11100%
.ctor(...)0%880%
ToString()20%303019.76%
Equals(...)0%16160%
GetHashCode()0%440%
Parse(...)0%220%
TryParse(...)0%440%
GetCacheControlLength(...)78.57%141484.61%
TrySetCacheControlValues(...)56.66%606033.33%
TrySetOptionalTokenList(...)0%22220%
TrySetTimeSpan(...)0%440%
AppendValueIfRequired(...)50%2250%
AppendValueWithSeparatorIfRequired(...)0%220%
AppendValues(...)0%440%
System.ICloneable.Clone()100%110%
Validate(...)100%110%
GetHashCode(...)0%220%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\CacheControlHeaderValue.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.Generic;
 5using System.Diagnostics;
 6using System.Diagnostics.CodeAnalysis;
 7using System.Globalization;
 8using System.Runtime.CompilerServices;
 9using System.Text;
 10using System.Threading;
 11
 12namespace System.Net.Http.Headers
 13{
 14    public class CacheControlHeaderValue : ICloneable
 15    {
 16        private const string maxAgeString = "max-age";
 17        private const string maxStaleString = "max-stale";
 18        private const string minFreshString = "min-fresh";
 19        private const string mustRevalidateString = "must-revalidate";
 20        private const string noCacheString = "no-cache";
 21        private const string noStoreString = "no-store";
 22        private const string noTransformString = "no-transform";
 23        private const string onlyIfCachedString = "only-if-cached";
 24        private const string privateString = "private";
 25        private const string proxyRevalidateString = "proxy-revalidate";
 26        private const string publicString = "public";
 27        private const string sharedMaxAgeString = "s-maxage";
 28
 129        private static readonly GenericHeaderParser s_nameValueListParser = GenericHeaderParser.MultipleValueNameValuePa
 30
 31        [Flags]
 32        private enum Flags : int
 33        {
 34            None = 0,
 35            MaxAgeHasValue = 1 << 0,
 36            SharedMaxAgeHasValue = 1 << 1,
 37            MaxStaleLimitHasValue = 1 << 2,
 38            MinFreshHasValue = 1 << 3,
 39            NoCache = 1 << 4,
 40            NoStore = 1 << 5,
 41            MaxStale = 1 << 6,
 42            NoTransform = 1 << 7,
 43            OnlyIfCached = 1 << 8,
 44            Public = 1 << 9,
 45            Private = 1 << 10,
 46            MustRevalidate = 1 << 11,
 47            ProxyRevalidate = 1 << 12,
 48        }
 49
 50        private Flags _flags;
 51        private TokenObjectCollection? _noCacheHeaders;
 52        private TimeSpan _maxAge;
 53        private TimeSpan _sharedMaxAge;
 54        private TimeSpan _maxStaleLimit;
 55        private TimeSpan _minFresh;
 56        private TokenObjectCollection? _privateHeaders;
 57        private UnvalidatedObjectCollection<NameValueHeaderValue>? _extensions;
 58
 59        private void SetTimeSpan(ref TimeSpan fieldRef, Flags flag, TimeSpan? value)
 060        {
 061            fieldRef = value.GetValueOrDefault();
 062            SetFlag(flag, value.HasValue);
 063        }
 64
 65        private void SetFlag(Flags flag, bool value)
 066        {
 067            Debug.Assert(sizeof(Flags) == sizeof(int));
 68
 69            // This type is not thread-safe, but we do a minimal amount of synchronization to ensure
 70            // that concurrent modifications of different properties don't interfere with each other.
 071            if (value)
 072            {
 073                Interlocked.Or(ref _flags, flag);
 074            }
 75            else
 076            {
 077                Interlocked.And(ref _flags, ~flag);
 078            }
 079        }
 80
 81        public bool NoCache
 82        {
 499883            get => (_flags & Flags.NoCache) != 0;
 084            set => SetFlag(Flags.NoCache, value);
 85        }
 86
 087        public ICollection<string> NoCacheHeaders => _noCacheHeaders ??= new TokenObjectCollection();
 88
 89        public bool NoStore
 90        {
 499891            get => (_flags & Flags.NoStore) != 0;
 092            set => SetFlag(Flags.NoStore, value);
 93        }
 94
 95        public TimeSpan? MaxAge
 96        {
 097            get => (_flags & Flags.MaxAgeHasValue) == 0 ? null : _maxAge;
 098            set => SetTimeSpan(ref _maxAge, Flags.MaxAgeHasValue, value);
 99        }
 100
 101        public TimeSpan? SharedMaxAge
 102        {
 0103            get => (_flags & Flags.SharedMaxAgeHasValue) == 0 ? null : _sharedMaxAge;
 0104            set => SetTimeSpan(ref _sharedMaxAge, Flags.SharedMaxAgeHasValue, value);
 105        }
 106
 107        public bool MaxStale
 108        {
 4998109            get => (_flags & Flags.MaxStale) != 0;
 0110            set => SetFlag(Flags.MaxStale, value);
 111        }
 112
 113        public TimeSpan? MaxStaleLimit
 114        {
 0115            get => (_flags & Flags.MaxStaleLimitHasValue) == 0 ? null : _maxStaleLimit;
 0116            set => SetTimeSpan(ref _maxStaleLimit, Flags.MaxStaleLimitHasValue, value);
 117        }
 118
 119        public TimeSpan? MinFresh
 120        {
 0121            get => (_flags & Flags.MinFreshHasValue) == 0 ? null : _minFresh;
 0122            set => SetTimeSpan(ref _minFresh, Flags.MinFreshHasValue, value);
 123        }
 124
 125        public bool NoTransform
 126        {
 4998127            get => (_flags & Flags.NoTransform) != 0;
 0128            set => SetFlag(Flags.NoTransform, value);
 129        }
 130
 131        public bool OnlyIfCached
 132        {
 4998133            get => (_flags & Flags.OnlyIfCached) != 0;
 0134            set => SetFlag(Flags.OnlyIfCached, value);
 135        }
 136
 137        public bool Public
 138        {
 4998139            get => (_flags & Flags.Public) != 0;
 0140            set => SetFlag(Flags.Public, value);
 141        }
 142
 143        public bool Private
 144        {
 4998145            get => (_flags & Flags.Private) != 0;
 0146            set => SetFlag(Flags.Private, value);
 147        }
 148
 0149        public ICollection<string> PrivateHeaders => _privateHeaders ??= new TokenObjectCollection();
 150
 151        public bool MustRevalidate
 152        {
 4998153            get => (_flags & Flags.MustRevalidate) != 0;
 0154            set => SetFlag(Flags.MustRevalidate, value);
 155        }
 156
 157        public bool ProxyRevalidate
 158        {
 4998159            get => (_flags & Flags.ProxyRevalidate) != 0;
 0160            set => SetFlag(Flags.ProxyRevalidate, value);
 161        }
 162
 232494163        public ICollection<NameValueHeaderValue> Extensions => _extensions ??= new UnvalidatedObjectCollection<NameValue
 164
 3332165        public CacheControlHeaderValue()
 3332166        {
 3332167        }
 168
 0169        private CacheControlHeaderValue(CacheControlHeaderValue source)
 0170        {
 0171            Debug.Assert(source != null);
 172
 0173            _flags = source._flags;
 0174            _maxAge = source._maxAge;
 0175            _sharedMaxAge = source._sharedMaxAge;
 0176            _maxStaleLimit = source._maxStaleLimit;
 0177            _minFresh = source._minFresh;
 178
 0179            if (source._noCacheHeaders != null)
 0180            {
 0181                foreach (string noCacheHeader in source._noCacheHeaders)
 0182                {
 0183                    NoCacheHeaders.Add(noCacheHeader);
 0184                }
 0185            }
 186
 0187            if (source._privateHeaders != null)
 0188            {
 0189                foreach (string privateHeader in source._privateHeaders)
 0190                {
 0191                    PrivateHeaders.Add(privateHeader);
 0192                }
 0193            }
 194
 0195            _extensions = source._extensions.Clone();
 0196        }
 197
 198        public override string ToString()
 4998199        {
 4998200            StringBuilder sb = StringBuilderCache.Acquire();
 201
 4998202            AppendValueIfRequired(sb, NoStore, noStoreString);
 4998203            AppendValueIfRequired(sb, NoTransform, noTransformString);
 4998204            AppendValueIfRequired(sb, OnlyIfCached, onlyIfCachedString);
 4998205            AppendValueIfRequired(sb, Public, publicString);
 4998206            AppendValueIfRequired(sb, MustRevalidate, mustRevalidateString);
 4998207            AppendValueIfRequired(sb, ProxyRevalidate, proxyRevalidateString);
 208
 4998209            if (NoCache)
 0210            {
 0211                AppendValueWithSeparatorIfRequired(sb, noCacheString);
 0212                if ((_noCacheHeaders != null) && (_noCacheHeaders.Count > 0))
 0213                {
 0214                    sb.Append("=\"");
 0215                    AppendValues(sb, _noCacheHeaders);
 0216                    sb.Append('\"');
 0217                }
 0218            }
 219
 4998220            if ((_flags & Flags.MaxAgeHasValue) != 0)
 0221            {
 0222                AppendValueWithSeparatorIfRequired(sb, maxAgeString);
 0223                sb.Append('=');
 0224                int maxAge = (int)_maxAge.TotalSeconds;
 0225                if (maxAge >= 0)
 0226                {
 0227                    sb.Append(maxAge);
 0228                }
 229                else
 0230                {
 231                    // In the corner case where the value is negative, ensure it uses
 232                    // the invariant's negative sign rather than the current culture's.
 0233                    sb.Append(NumberFormatInfo.InvariantInfo, $"{maxAge}");
 0234                }
 0235            }
 236
 4998237            if ((_flags & Flags.SharedMaxAgeHasValue) != 0)
 0238            {
 0239                AppendValueWithSeparatorIfRequired(sb, sharedMaxAgeString);
 0240                sb.Append('=');
 0241                int sharedMaxAge = (int)_sharedMaxAge.TotalSeconds;
 0242                if (sharedMaxAge >= 0)
 0243                {
 0244                    sb.Append(sharedMaxAge);
 0245                }
 246                else
 0247                {
 248                    // In the corner case where the value is negative, ensure it uses
 249                    // the invariant's negative sign rather than the current culture's.
 0250                    sb.Append(NumberFormatInfo.InvariantInfo, $"{sharedMaxAge}");
 0251                }
 0252            }
 253
 4998254            if (MaxStale)
 0255            {
 0256                AppendValueWithSeparatorIfRequired(sb, maxStaleString);
 0257                if ((_flags & Flags.MaxStaleLimitHasValue) != 0)
 0258                {
 0259                    sb.Append('=');
 0260                    int maxStaleLimit = (int)_maxStaleLimit.TotalSeconds;
 0261                    if (maxStaleLimit >= 0)
 0262                    {
 0263                        sb.Append(maxStaleLimit);
 0264                    }
 265                    else
 0266                    {
 267                        // In the corner case where the value is negative, ensure it uses
 268                        // the invariant's negative sign rather than the current culture's.
 0269                        sb.Append(NumberFormatInfo.InvariantInfo, $"{maxStaleLimit}");
 0270                    }
 0271                }
 0272            }
 273
 4998274            if ((_flags & Flags.MinFreshHasValue) != 0)
 0275            {
 0276                AppendValueWithSeparatorIfRequired(sb, minFreshString);
 0277                sb.Append('=');
 0278                int minFresh = (int)_minFresh.TotalSeconds;
 0279                if (minFresh >= 0)
 0280                {
 0281                    sb.Append(minFresh);
 0282                }
 283                else
 0284                {
 285                    // In the corner case where the value is negative, ensure it uses
 286                    // the invariant's negative sign rather than the current culture's.
 0287                    sb.Append(NumberFormatInfo.InvariantInfo, $"{minFresh}");
 0288                }
 0289            }
 290
 4998291            if (Private)
 0292            {
 0293                AppendValueWithSeparatorIfRequired(sb, privateString);
 0294                if ((_privateHeaders != null) && (_privateHeaders.Count > 0))
 0295                {
 0296                    sb.Append("=\"");
 0297                    AppendValues(sb, _privateHeaders);
 0298                    sb.Append('\"');
 0299                }
 0300            }
 301
 4998302            NameValueHeaderValue.ToString(_extensions, ',', false, sb);
 303
 4998304            return StringBuilderCache.GetStringAndRelease(sb);
 4998305        }
 306
 307        public override bool Equals([NotNullWhen(true)] object? obj) =>
 0308            obj is CacheControlHeaderValue other &&
 0309            _flags == other._flags &&
 0310            _maxAge == other._maxAge &&
 0311            _sharedMaxAge == other._sharedMaxAge &&
 0312            _maxStaleLimit == other._maxStaleLimit &&
 0313            _minFresh == other._minFresh &&
 0314            HeaderUtilities.AreEqualCollections(_noCacheHeaders, other._noCacheHeaders, StringComparer.OrdinalIgnoreCase
 0315            HeaderUtilities.AreEqualCollections(_privateHeaders, other._privateHeaders, StringComparer.OrdinalIgnoreCase
 0316            HeaderUtilities.AreEqualCollections(_extensions, other._extensions);
 317
 318        public override int GetHashCode() =>
 0319            HashCode.Combine(
 0320                _flags,
 0321                _maxAge,
 0322                _sharedMaxAge,
 0323                _maxStaleLimit,
 0324                _minFresh,
 0325                (_noCacheHeaders is null ? 0 : _noCacheHeaders.GetHashCode(StringComparer.OrdinalIgnoreCase)),
 0326                (_privateHeaders is null ? 0 : _privateHeaders.GetHashCode(StringComparer.OrdinalIgnoreCase)),
 0327                NameValueHeaderValue.GetHashCode(_extensions));
 328
 329        public static CacheControlHeaderValue Parse(string? input)
 0330        {
 0331            int index = 0;
 0332            return (CacheControlHeaderValue)CacheControlHeaderParser.Parser.ParseValue(input, null, ref index) ?? new Ca
 0333        }
 334
 335        public static bool TryParse(string? input, [NotNullWhen(true)] out CacheControlHeaderValue? parsedValue)
 0336        {
 0337            int index = 0;
 0338            parsedValue = null;
 339
 0340            if (CacheControlHeaderParser.Parser.TryParseValue(input, null, ref index, out object? output))
 0341            {
 0342                parsedValue = (CacheControlHeaderValue?)output ?? new CacheControlHeaderValue();
 0343                return true;
 344            }
 0345            return false;
 0346        }
 347
 348        internal static int GetCacheControlLength(string? input, int startIndex, CacheControlHeaderValue? storeValue,
 349            out CacheControlHeaderValue? parsedValue)
 5134350        {
 5134351            Debug.Assert(startIndex >= 0);
 352
 5134353            parsedValue = null;
 354
 5134355            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
 0356            {
 0357                return 0;
 358            }
 359
 360            // Cache-Control header consists of a list of name/value pairs, where the value is optional. So use an
 361            // instance of NameValueHeaderParser to parse the string.
 5134362            int current = startIndex;
 5134363            List<NameValueHeaderValue> nameValueList = new List<NameValueHeaderValue>();
 237756364            while (current < input.Length)
 232758365            {
 232758366                if (!s_nameValueListParser.TryParseValue(input, null, ref current, out object? nameValue))
 136367                {
 136368                    return 0;
 369                }
 370
 232622371                Debug.Assert(nameValue is not null);
 232622372                nameValueList.Add((NameValueHeaderValue)nameValue);
 232622373            }
 374
 375            // If we get here, we were able to successfully parse the string as list of name/value pairs. Now analyze
 376            // the name/value pairs.
 377
 378            // Cache-Control is a header supporting lists of values. However, expose the header as an instance of
 379            // CacheControlHeaderValue. So if we already have an instance of CacheControlHeaderValue, add the values
 380            // from this string to the existing instances.
 4998381            CacheControlHeaderValue? result = storeValue ?? new CacheControlHeaderValue();
 382
 4998383            if (!TrySetCacheControlValues(result, nameValueList))
 0384            {
 0385                return 0;
 386            }
 387
 388            // If we had an existing store value and we just updated that instance, return 'null' to indicate that
 389            // we don't have a new instance of CacheControlHeaderValue, but just updated an existing one. This is the
 390            // case if we have multiple 'Cache-Control' headers set in a request/response message.
 4998391            if (storeValue == null)
 3332392            {
 3332393                parsedValue = result;
 3332394            }
 395
 396            // If we get here we successfully parsed the whole string.
 4998397            return input.Length - startIndex;
 5134398        }
 399
 400        private static bool TrySetCacheControlValues(CacheControlHeaderValue cc, List<NameValueHeaderValue> nameValueLis
 4998401        {
 479982402            foreach (NameValueHeaderValue nameValue in nameValueList)
 232494403            {
 232494404                string name = nameValue.Name.ToLowerInvariant();
 232494405                string? value = nameValue.Value;
 406
 232494407                Flags flagsToSet = Flags.None;
 232494408                bool success = value is null;
 409
 232494410                switch (name)
 411                {
 412                    case noCacheString:
 0413                        flagsToSet = Flags.NoCache;
 0414                        success = TrySetOptionalTokenList(nameValue, ref cc._noCacheHeaders);
 0415                        break;
 416
 417                    case noStoreString:
 0418                        flagsToSet = Flags.NoStore;
 0419                        break;
 420
 421                    case maxAgeString:
 0422                        flagsToSet = Flags.MaxAgeHasValue;
 0423                        success = TrySetTimeSpan(value, ref cc._maxAge);
 0424                        break;
 425
 426                    case maxStaleString:
 0427                        flagsToSet = Flags.MaxStale;
 0428                        if (TrySetTimeSpan(value, ref cc._maxStaleLimit))
 0429                        {
 0430                            success = true;
 0431                            flagsToSet = Flags.MaxStale | Flags.MaxStaleLimitHasValue;
 0432                        }
 0433                        break;
 434
 435                    case minFreshString:
 0436                        flagsToSet = Flags.MinFreshHasValue;
 0437                        success = TrySetTimeSpan(value, ref cc._minFresh);
 0438                        break;
 439
 440                    case noTransformString:
 0441                        flagsToSet = Flags.NoTransform;
 0442                        break;
 443
 444                    case onlyIfCachedString:
 0445                        flagsToSet = Flags.OnlyIfCached;
 0446                        break;
 447
 448                    case publicString:
 0449                        flagsToSet = Flags.Public;
 0450                        break;
 451
 452                    case privateString:
 0453                        flagsToSet = Flags.Private;
 0454                        success = TrySetOptionalTokenList(nameValue, ref cc._privateHeaders);
 0455                        break;
 456
 457                    case mustRevalidateString:
 0458                        flagsToSet = Flags.MustRevalidate;
 0459                        break;
 460
 461                    case proxyRevalidateString:
 0462                        flagsToSet = Flags.ProxyRevalidate;
 0463                        break;
 464
 465                    case sharedMaxAgeString:
 0466                        flagsToSet = Flags.SharedMaxAgeHasValue;
 0467                        success = TrySetTimeSpan(value, ref cc._sharedMaxAge);
 0468                        break;
 469
 470                    default:
 232494471                        success = true;
 232494472                        cc.Extensions.Add(nameValue);
 232494473                        break;
 474                }
 475
 232494476                if (success)
 232494477                {
 232494478                    cc._flags |= flagsToSet;
 232494479                }
 480                else
 0481                {
 0482                    return false;
 483                }
 232494484            }
 485
 4998486            return true;
 4998487        }
 488
 489        private static bool TrySetOptionalTokenList(NameValueHeaderValue nameValue, ref TokenObjectCollection? destinati
 0490        {
 0491            Debug.Assert(nameValue != null);
 492
 0493            if (nameValue.Value == null)
 0494            {
 0495                return true;
 496            }
 497
 498            // We need the string to be at least 3 chars long: 2x quotes and at least 1 character. Also make sure we
 499            // have a quoted string. Note that NameValueHeaderValue will never have leading/trailing whitespace.
 0500            string valueString = nameValue.Value;
 0501            if ((valueString.Length < 3) || !valueString.StartsWith('\"') || !valueString.EndsWith('\"'))
 0502            {
 0503                return false;
 504            }
 505
 506            // We have a quoted string. Now verify that the string contains a list of valid tokens separated by ','.
 0507            int current = 1; // skip the initial '"' character.
 0508            int maxLength = valueString.Length - 1; // -1 because we don't want to parse the final '"'.
 0509            int originalValueCount = destination == null ? 0 : destination.Count;
 0510            while (current < maxLength)
 0511            {
 0512                current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(valueString, current, true,
 0513                    out _);
 514
 0515                if (current == maxLength)
 0516                {
 0517                    break;
 518                }
 519
 0520                int tokenLength = HttpRuleParser.GetTokenLength(valueString, current);
 521
 0522                if (tokenLength == 0)
 0523                {
 524                    // We already skipped whitespace and separators. If we don't have a token it must be an invalid
 525                    // character.
 0526                    return false;
 527                }
 528
 0529                destination ??= new TokenObjectCollection();
 0530                destination.Add(valueString.Substring(current, tokenLength));
 531
 0532                current += tokenLength;
 0533            }
 534
 535            // After parsing a valid token list, we expect to have at least one value
 0536            if ((destination != null) && (destination.Count > originalValueCount))
 0537            {
 0538                return true;
 539            }
 540
 0541            return false;
 0542        }
 543
 544        private static bool TrySetTimeSpan(string? value, ref TimeSpan timeSpan)
 0545        {
 0546            if (value is null || !HeaderUtilities.TryParseInt32(value, out int seconds))
 0547            {
 0548                return false;
 549            }
 550
 0551            timeSpan = new TimeSpan(0, 0, seconds);
 0552            return true;
 0553        }
 554
 555        private static void AppendValueIfRequired(StringBuilder sb, bool appendValue, string value)
 29988556        {
 29988557            if (appendValue)
 0558            {
 0559                AppendValueWithSeparatorIfRequired(sb, value);
 0560            }
 29988561        }
 562
 563        private static void AppendValueWithSeparatorIfRequired(StringBuilder sb, string value)
 0564        {
 0565            if (sb.Length > 0)
 0566            {
 0567                sb.Append(", ");
 0568            }
 0569            sb.Append(value);
 0570        }
 571
 572        private static void AppendValues(StringBuilder sb, TokenObjectCollection values)
 0573        {
 0574            bool first = true;
 0575            foreach (string value in values)
 0576            {
 0577                if (first)
 0578                {
 0579                    first = false;
 0580                }
 581                else
 0582                {
 0583                    sb.Append(", ");
 0584                }
 585
 0586                sb.Append(value);
 0587            }
 0588        }
 589
 590        object ICloneable.Clone()
 0591        {
 0592            return new CacheControlHeaderValue(this);
 0593        }
 594
 595        private sealed class TokenObjectCollection : ObjectCollection<string>
 596        {
 0597            public override void Validate(string item) => HeaderUtilities.CheckValidToken(item);
 598
 599            public int GetHashCode(StringComparer comparer)
 0600            {
 0601                int hashcode = 0;
 602
 0603                foreach (string value in this)
 0604                {
 0605                    hashcode ^= comparer.GetHashCode(value);
 0606                }
 607
 0608                return hashcode;
 0609            }
 610        }
 611    }
 612}

Methods/Properties

.cctor()
SetTimeSpan(System.TimeSpan&,System.Net.Http.Headers.CacheControlHeaderValue/Flags,System.Nullable`1<System.TimeSpan>)
SetFlag(System.Net.Http.Headers.CacheControlHeaderValue/Flags,System.Boolean)
NoCache()
NoCache(System.Boolean)
NoCacheHeaders()
NoStore()
NoStore(System.Boolean)
MaxAge()
MaxAge(System.Nullable`1<System.TimeSpan>)
SharedMaxAge()
SharedMaxAge(System.Nullable`1<System.TimeSpan>)
MaxStale()
MaxStale(System.Boolean)
MaxStaleLimit()
MaxStaleLimit(System.Nullable`1<System.TimeSpan>)
MinFresh()
MinFresh(System.Nullable`1<System.TimeSpan>)
NoTransform()
NoTransform(System.Boolean)
OnlyIfCached()
OnlyIfCached(System.Boolean)
Public()
Public(System.Boolean)
Private()
Private(System.Boolean)
PrivateHeaders()
MustRevalidate()
MustRevalidate(System.Boolean)
ProxyRevalidate()
ProxyRevalidate(System.Boolean)
Extensions()
.ctor()
.ctor(System.Net.Http.Headers.CacheControlHeaderValue)
ToString()
Equals(System.Object)
GetHashCode()
Parse(System.String)
TryParse(System.String,System.Net.Http.Headers.CacheControlHeaderValue&)
GetCacheControlLength(System.String,System.Int32,System.Net.Http.Headers.CacheControlHeaderValue,System.Net.Http.Headers.CacheControlHeaderValue&)
TrySetCacheControlValues(System.Net.Http.Headers.CacheControlHeaderValue,System.Collections.Generic.List`1<System.Net.Http.Headers.NameValueHeaderValue>)
TrySetOptionalTokenList(System.Net.Http.Headers.NameValueHeaderValue,System.Net.Http.Headers.CacheControlHeaderValue/TokenObjectCollection&)
TrySetTimeSpan(System.String,System.TimeSpan&)
AppendValueIfRequired(System.Text.StringBuilder,System.Boolean,System.String)
AppendValueWithSeparatorIfRequired(System.Text.StringBuilder,System.String)
AppendValues(System.Text.StringBuilder,System.Net.Http.Headers.CacheControlHeaderValue/TokenObjectCollection)
System.ICloneable.Clone()
Validate(System.String)
GetHashCode(System.StringComparer)