< Summary

Information
Class: System.Net.Http.Headers.WarningHeaderValue
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\WarningHeaderValue.cs
Line coverage
61%
Covered lines: 110
Uncovered lines: 70
Coverable lines: 180
Total lines: 303
Line coverage: 61.1%
Branch coverage
64%
Covered branches: 36
Total branches: 56
Branch coverage: 64.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%110%
.ctor(...)100%110%
ToString()50%2266.66%
Equals(...)0%10100%
GetHashCode()100%110%
Parse(...)100%110%
TryParse(...)0%220%
GetWarningLength(...)83.33%121292%
TryReadAgent(...)100%66100%
TryReadCode(...)90%101083.33%
TryReadDate(...)90%101084%
System.ICloneable.Clone()100%110%
CheckCode(...)100%11100%
CheckAgent(...)50%2266.66%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\WarningHeaderValue.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.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6using System.Globalization;
 7using System.Text;
 8
 9namespace System.Net.Http.Headers
 10{
 11    public class WarningHeaderValue : ICloneable
 12    {
 13        private readonly int _code;
 14        private readonly string _agent;
 15        private readonly string _text;
 16        private readonly DateTimeOffset _date;
 17        private readonly bool _dateHasValue;
 18
 019        public int Code => _code;
 20
 021        public string Agent => _agent;
 22
 023        public string Text => _text;
 24
 025        public DateTimeOffset? Date => _dateHasValue ? _date : null;
 26
 2593027        private WarningHeaderValue(int code, string agent, string text, DateTimeOffset? date)
 2593028        {
 29#if DEBUG
 30            // This constructor should only be used with already validated values.
 2593031            new WarningHeaderValue(code, agent, text);
 32#endif
 33
 2593034            _code = code;
 2593035            _agent = agent;
 2593036            _text = text;
 2593037            _date = date.GetValueOrDefault();
 2593038            _dateHasValue = date.HasValue;
 2593039        }
 40
 2593041        public WarningHeaderValue(int code, string agent, string text)
 2593042        {
 2593043            CheckCode(code);
 2593044            CheckAgent(agent);
 2593045            HeaderUtilities.CheckValidQuotedString(text);
 46
 2593047            _code = code;
 2593048            _agent = agent;
 2593049            _text = text;
 2593050        }
 51
 052        public WarningHeaderValue(int code, string agent, string text, DateTimeOffset date)
 053        {
 054            CheckCode(code);
 055            CheckAgent(agent);
 056            HeaderUtilities.CheckValidQuotedString(text);
 57
 058            _code = code;
 059            _agent = agent;
 060            _text = text;
 061            _date = date;
 062            _dateHasValue = true;
 063        }
 64
 065        private WarningHeaderValue(WarningHeaderValue source)
 066        {
 067            Debug.Assert(source != null);
 68
 069            _code = source._code;
 070            _agent = source._agent;
 071            _text = source._text;
 072            _date = source._date;
 073            _dateHasValue = source._dateHasValue;
 074        }
 75
 76        public override string ToString()
 3819077        {
 3819078            var sb = new ValueStringBuilder(stackalloc char[256]);
 79
 80            // Warning codes are always 3 digits according to RFC2616
 3819081            sb.AppendSpanFormattable(_code, "000", NumberFormatInfo.InvariantInfo);
 82
 3819083            sb.Append(' ');
 3819084            sb.Append(_agent);
 3819085            sb.Append(' ');
 3819086            sb.Append(_text);
 87
 3819088            if (_dateHasValue)
 089            {
 090                sb.Append(" \"");
 091                sb.AppendSpanFormattable(_date, "r");
 092                sb.Append('\"');
 093            }
 94
 3819095            return sb.ToString();
 3819096        }
 97
 98        public override bool Equals([NotNullWhen(true)] object? obj) =>
 099            obj is WarningHeaderValue other &&
 0100            _code == other._code &&
 0101            // 'agent' is a host/token, i.e. use case-insensitive comparison. Use case-sensitive comparison for 'text'
 0102            // since it is a quoted string.
 0103            string.Equals(_agent, other._agent, StringComparison.OrdinalIgnoreCase) &&
 0104            string.Equals(_text, other._text, StringComparison.Ordinal) &&
 0105            _dateHasValue == other._dateHasValue &&
 0106            _date == other._date;
 107
 108        public override int GetHashCode() =>
 0109            HashCode.Combine(
 0110                _code,
 0111                StringComparer.OrdinalIgnoreCase.GetHashCode(_agent),
 0112                _text,
 0113                _dateHasValue,
 0114                _date);
 115
 116        public static WarningHeaderValue Parse(string input)
 0117        {
 0118            int index = 0;
 0119            return (WarningHeaderValue)GenericHeaderParser.SingleValueWarningParser.ParseValue(input, null, ref index);
 0120        }
 121
 122        public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out WarningHeaderValue? parse
 0123        {
 0124            int index = 0;
 0125            parsedValue = null;
 126
 0127            if (GenericHeaderParser.SingleValueWarningParser.TryParseValue(input, null, ref index, out object? output))
 0128            {
 0129                parsedValue = (WarningHeaderValue)output!;
 0130                return true;
 131            }
 0132            return false;
 0133        }
 134
 135        internal static int GetWarningLength(string? input, int startIndex, out object? parsedValue)
 27342136        {
 27342137            Debug.Assert(startIndex >= 0);
 138
 27342139            parsedValue = null;
 140
 27342141            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
 0142            {
 0143                return 0;
 144            }
 145
 146            // Read <code> in '<code> <agent> <text> ["<date>"]'
 27342147            int current = startIndex;
 148
 27342149            if (!TryReadCode(input, ref current, out int code))
 216150            {
 216151                return 0;
 152            }
 153
 154            // Read <agent> in '<code> <agent> <text> ["<date>"]'
 27126155            if (!TryReadAgent(input, ref current, out string? agent))
 640156            {
 640157                return 0;
 158            }
 159
 160            // Read <text> in '<code> <agent> <text> ["<date>"]'
 26486161            int textStartIndex = current;
 26486162            if (HttpRuleParser.GetQuotedStringLength(input, current, out int textLength) != HttpParseResult.Parsed)
 336163            {
 336164                return 0;
 165            }
 166
 26150167            string text = input.Substring(textStartIndex, textLength);
 168
 26150169            current += textLength;
 170
 171            // Read <date> in '<code> <agent> <text> ["<date>"]'
 26150172            if (!TryReadDate(input, ref current, out DateTimeOffset? date))
 220173            {
 220174                return 0;
 175            }
 176
 25930177            parsedValue = new WarningHeaderValue(code, agent, text, date);
 178
 25930179            return current - startIndex;
 27342180        }
 181
 182        private static bool TryReadAgent(string input, ref int current, [NotNullWhen(true)] out string? agent)
 27126183        {
 27126184            agent = null;
 185
 27126186            int agentLength = HttpRuleParser.GetHostLength(input, current, true);
 27126187            if (agentLength == 0)
 264188            {
 264189                return false;
 190            }
 191
 26862192            agent = input.Substring(current, agentLength);
 26862193            current += agentLength;
 194
 26862195            int whitespaceLength = HttpRuleParser.GetWhitespaceLength(input, current);
 26862196            current += whitespaceLength;
 197
 198            // At least one whitespace required after <agent>. Also make sure we have characters left for <text>
 26862199            if ((whitespaceLength == 0) || (current == input.Length))
 376200            {
 376201                return false;
 202            }
 203
 26486204            return true;
 27126205        }
 206
 207        private static bool TryReadCode(string input, ref int current, out int code)
 27342208        {
 27342209            code = 0;
 27342210            int codeLength = HttpRuleParser.GetNumberLength(input, current, false);
 211
 212            // code must be a 3 digit value. We accept less digits, but we don't accept more.
 27342213            if ((codeLength == 0) || (codeLength > 3))
 176214            {
 176215                return false;
 216            }
 217
 27166218            if (!HeaderUtilities.TryParseInt32(input, current, codeLength, out code))
 0219            {
 0220                Debug.Fail("Unable to parse value even though it was parsed as <=3 digits string. Input: '" +
 0221                    input + "', Current: " + current + ", CodeLength: " + codeLength);
 222                return false;
 223            }
 224
 27166225            current += codeLength;
 226
 27166227            int whitespaceLength = HttpRuleParser.GetWhitespaceLength(input, current);
 27166228            current += whitespaceLength;
 229
 230            // Make sure the number is followed by at least one whitespace and that we have characters left to parse.
 27166231            if ((whitespaceLength == 0) || (current == input.Length))
 40232            {
 40233                return false;
 234            }
 235
 27126236            return true;
 27342237        }
 238
 239        private static bool TryReadDate(string input, ref int current, out DateTimeOffset? date)
 26150240        {
 26150241            date = null;
 242
 243            // Make sure we have at least one whitespace between <text> and <date> (if we have <date>)
 26150244            int whitespaceLength = HttpRuleParser.GetWhitespaceLength(input, current);
 26150245            current += whitespaceLength;
 246
 247            // Read <date> in '<code> <agent> <text> ["<date>"]'
 26150248            if ((current < input.Length) && (input[current] == '"'))
 220249            {
 220250                if (whitespaceLength == 0)
 116251                {
 116252                    return false; // we have characters after <text> but they were not separated by a whitespace
 253                }
 254
 104255                current++; // skip opening '"'
 256
 257                // Find the closing '"'
 104258                int dateStartIndex = current;
 104259                int quote = input.AsSpan(current).IndexOf('"');
 104260                if (quote <= 0) // no quote was found or it was the first character (meaning an empty quoted string)
 44261                {
 44262                    return false;
 263                }
 60264                current += quote;
 265
 60266                if (!HttpDateParser.TryParse(input.AsSpan(dateStartIndex, current - dateStartIndex), out DateTimeOffset 
 60267                {
 60268                    return false;
 269                }
 270
 0271                date = temp;
 272
 0273                current++; // skip closing '"'
 0274                current += HttpRuleParser.GetWhitespaceLength(input, current);
 0275            }
 276
 25930277            return true;
 26150278        }
 279
 280        object ICloneable.Clone()
 0281        {
 0282            return new WarningHeaderValue(this);
 0283        }
 284
 285        private static void CheckCode(int code)
 25930286        {
 25930287            ArgumentOutOfRangeException.ThrowIfNegative(code);
 25930288            ArgumentOutOfRangeException.ThrowIfGreaterThan(code, 999);
 25930289        }
 290
 291        private static void CheckAgent(string agent)
 25930292        {
 25930293            ArgumentException.ThrowIfNullOrEmpty(agent);
 294
 295            // 'Agent' can either be a host or a token. Since a token is a valid host, we only verify if the value
 296            // is a valid host.
 25930297            if (HttpRuleParser.GetHostLength(agent, 0, true) != agent.Length)
 0298            {
 0299                throw new FormatException(SR.Format(SR.net_http_headers_invalid_value, agent));
 300            }
 25930301        }
 302    }
 303}