< Summary

Line coverage
61%
Covered lines: 99
Uncovered lines: 62
Coverable lines: 161
Total lines: 269
Line coverage: 61.4%
Branch coverage
62%
Covered branches: 30
Total branches: 48
Branch coverage: 62.5%
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%110%
.ctor(...)100%110%
.ctor(...)75%4476.47%
.ctor(...)100%110%
ToString()75%4476.47%
Equals(...)0%880%
GetHashCode()0%220%
Parse(...)100%110%
TryParse(...)0%220%
GetViaLength(...)81.25%161680.64%
GetProtocolEndIndex(...)100%1010100%
System.ICloneable.Clone()100%110%
CheckReceivedBy(...)50%2266.66%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Net.Http/src/System/Net/Http/Headers/ViaHeaderValue.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.Text;
 7
 8namespace System.Net.Http.Headers
 9{
 10    public class ViaHeaderValue : ICloneable
 11    {
 12        private readonly string? _protocolName;
 13        private readonly string _protocolVersion;
 14        private readonly string _receivedBy;
 15        private readonly string? _comment;
 16
 017        public string? ProtocolName => _protocolName;
 18
 019        public string ProtocolVersion => _protocolVersion;
 20
 021        public string ReceivedBy => _receivedBy;
 22
 023        public string? Comment => _comment;
 24
 123225        private ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName, string? comment, bool _)
 123226        {
 27#if DEBUG
 28            // This constructor should only be used with already validated values.
 123229            new ViaHeaderValue(protocolVersion, receivedBy, protocolName, comment);
 30#endif
 31
 123232            _protocolVersion = protocolVersion;
 123233            _receivedBy = receivedBy;
 123234            _protocolName = protocolName;
 123235            _comment = comment;
 123236        }
 37
 38        public ViaHeaderValue(string protocolVersion, string receivedBy)
 039            : this(protocolVersion, receivedBy, null, null)
 040        {
 041        }
 42
 43        public ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName)
 044            : this(protocolVersion, receivedBy, protocolName, null)
 045        {
 046        }
 47
 123248        public ViaHeaderValue(string protocolVersion, string receivedBy, string? protocolName, string? comment)
 123249        {
 123250            HeaderUtilities.CheckValidToken(protocolVersion);
 123251            CheckReceivedBy(receivedBy);
 52
 123253            if (!string.IsNullOrEmpty(protocolName))
 2254            {
 2255                HeaderUtilities.CheckValidToken(protocolName);
 2256                _protocolName = protocolName;
 2257            }
 58
 123259            if (!string.IsNullOrEmpty(comment))
 060            {
 061                HeaderUtilities.CheckValidComment(comment);
 062                _comment = comment;
 063            }
 64
 123265            _protocolVersion = protocolVersion;
 123266            _receivedBy = receivedBy;
 123267        }
 68
 069        private ViaHeaderValue(ViaHeaderValue source)
 070        {
 071            Debug.Assert(source != null);
 72
 073            _protocolName = source._protocolName;
 074            _protocolVersion = source._protocolVersion;
 075            _receivedBy = source._receivedBy;
 076            _comment = source._comment;
 077        }
 78
 79        public override string ToString()
 128080        {
 128081            var sb = new ValueStringBuilder(stackalloc char[256]);
 82
 128083            if (!string.IsNullOrEmpty(_protocolName))
 3084            {
 3085                sb.Append(_protocolName);
 3086                sb.Append('/');
 3087            }
 88
 128089            sb.Append(_protocolVersion);
 128090            sb.Append(' ');
 128091            sb.Append(_receivedBy);
 92
 128093            if (!string.IsNullOrEmpty(_comment))
 094            {
 095                sb.Append(' ');
 096                sb.Append(_comment);
 097            }
 98
 128099            return sb.ToString();
 1280100        }
 101
 102        public override bool Equals([NotNullWhen(true)] object? obj) =>
 0103            obj is ViaHeaderValue other &&
 0104            // Note that for token and host case-insensitive comparison is used. Comments are compared using case-
 0105            // sensitive comparison.
 0106            string.Equals(_protocolVersion, other._protocolVersion, StringComparison.OrdinalIgnoreCase) &&
 0107            string.Equals(_receivedBy, other._receivedBy, StringComparison.OrdinalIgnoreCase) &&
 0108            string.Equals(_protocolName, other._protocolName, StringComparison.OrdinalIgnoreCase) &&
 0109            string.Equals(_comment, other._comment, StringComparison.Ordinal);
 110
 111        public override int GetHashCode() =>
 0112            HashCode.Combine(
 0113                StringComparer.OrdinalIgnoreCase.GetHashCode(_protocolVersion),
 0114                StringComparer.OrdinalIgnoreCase.GetHashCode(_receivedBy),
 0115                _protocolName is null ? 0 : StringComparer.OrdinalIgnoreCase.GetHashCode(_protocolName),
 0116                _comment);
 117
 118        public static ViaHeaderValue Parse(string input)
 0119        {
 0120            int index = 0;
 0121            return (ViaHeaderValue)GenericHeaderParser.SingleValueViaParser.ParseValue(input, null, ref index);
 0122        }
 123
 124        public static bool TryParse([NotNullWhen(true)] string? input, [NotNullWhen(true)] out ViaHeaderValue? parsedVal
 0125        {
 0126            int index = 0;
 0127            parsedValue = null;
 128
 0129            if (GenericHeaderParser.SingleValueViaParser.TryParseValue(input, null, ref index, out object? output))
 0130            {
 0131                parsedValue = (ViaHeaderValue)output!;
 0132                return true;
 133            }
 0134            return false;
 0135        }
 136
 137        internal static int GetViaLength(string? input, int startIndex, out object? parsedValue)
 1540138        {
 1540139            Debug.Assert(startIndex >= 0);
 140
 1540141            parsedValue = null;
 142
 1540143            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
 0144            {
 0145                return 0;
 146            }
 147
 148            // Read <protocolName> and <protocolVersion> in '[<protocolName>/]<protocolVersion> <receivedBy> [<comment>]
 1540149            int current = GetProtocolEndIndex(input, startIndex, out string? protocolName, out string? protocolVersion);
 150
 151            // If we reached the end of the string after reading protocolName/Version we return (we expect at least
 152            // <receivedBy> to follow). If reading protocolName/Version read 0 bytes, we return.
 1540153            if ((current == 0) || (current == input.Length))
 116154            {
 116155                return 0;
 156            }
 1424157            Debug.Assert(protocolVersion != null);
 158
 159            // Read <receivedBy> in '[<protocolName>/]<protocolVersion> <receivedBy> [<comment>]'
 1424160            int receivedByLength = HttpRuleParser.GetHostLength(input, current, true);
 1424161            if (receivedByLength == 0)
 108162            {
 108163                return 0;
 164            }
 165
 1316166            string receivedBy = input.Substring(current, receivedByLength);
 1316167            current += receivedByLength;
 168
 1316169            current += HttpRuleParser.GetWhitespaceLength(input, current);
 170
 1316171            string? comment = null;
 1316172            if ((current < input.Length) && (input[current] == '('))
 84173            {
 174                // We have a <comment> in '[<protocolName>/]<protocolVersion> <receivedBy> [<comment>]'
 84175                if (HttpRuleParser.GetCommentLength(input, current, out int commentLength) != HttpParseResult.Parsed)
 84176                {
 84177                    return 0; // We found a '(' character but it wasn't a valid comment. Abort.
 178                }
 179
 0180                comment = input.Substring(current, commentLength);
 181
 0182                current += commentLength;
 0183                current += HttpRuleParser.GetWhitespaceLength(input, current);
 0184            }
 185
 1232186            parsedValue = new ViaHeaderValue(protocolVersion, receivedBy, protocolName, comment, false);
 1232187            return current - startIndex;
 1540188        }
 189
 190        private static int GetProtocolEndIndex(string input, int startIndex, out string? protocolName,
 191            out string? protocolVersion)
 1540192        {
 193            // We have a string of the form '[<protocolName>/]<protocolVersion> <receivedBy> [<comment>]'. The first
 194            // token may either be the protocol name or protocol version. We'll only find out after reading the token
 195            // and by looking at the following character: If it is a '/' we just parsed the protocol name, otherwise
 196            // the protocol version.
 1540197            protocolName = null;
 1540198            protocolVersion = null;
 199
 1540200            int current = startIndex;
 1540201            int protocolVersionOrNameLength = HttpRuleParser.GetTokenLength(input, current);
 202
 1540203            if (protocolVersionOrNameLength == 0)
 12204            {
 12205                return 0;
 206            }
 207
 1528208            current = startIndex + protocolVersionOrNameLength;
 1528209            int whitespaceLength = HttpRuleParser.GetWhitespaceLength(input, current);
 1528210            current += whitespaceLength;
 211
 1528212            if (current == input.Length)
 4213            {
 4214                return 0;
 215            }
 216
 1524217            if (input[current] == '/')
 42218            {
 219                // We parsed the protocol name
 42220                protocolName = input.Substring(startIndex, protocolVersionOrNameLength);
 221
 42222                current++; // skip the '/' delimiter
 42223                current += HttpRuleParser.GetWhitespaceLength(input, current);
 224
 42225                protocolVersionOrNameLength = HttpRuleParser.GetTokenLength(input, current);
 226
 42227                if (protocolVersionOrNameLength == 0)
 8228                {
 8229                    return 0; // We have a string "<token>/" followed by non-token chars. This is invalid.
 230                }
 231
 34232                protocolVersion = input.Substring(current, protocolVersionOrNameLength);
 233
 34234                current += protocolVersionOrNameLength;
 34235                whitespaceLength = HttpRuleParser.GetWhitespaceLength(input, current);
 34236                current += whitespaceLength;
 34237            }
 238            else
 1482239            {
 1482240                protocolVersion = input.Substring(startIndex, protocolVersionOrNameLength);
 1482241            }
 242
 1516243            if (whitespaceLength == 0)
 92244            {
 92245                return 0; // We were able to parse [<protocolName>/]<protocolVersion> but it wasn't followed by a WS
 246            }
 247
 1424248            return current;
 1540249        }
 250
 251        object ICloneable.Clone()
 0252        {
 0253            return new ViaHeaderValue(this);
 0254        }
 255
 256        private static void CheckReceivedBy(string receivedBy)
 1232257        {
 1232258            ArgumentException.ThrowIfNullOrEmpty(receivedBy);
 259
 260            // 'receivedBy' can either be a host or a token. Since a token is a valid host, we only verify if the value
 261            // is a valid host.;
 1232262            if (HttpRuleParser.GetHostLength(receivedBy, 0, true) != receivedBy.Length)
 0263            {
 0264                throw new FormatException(SR.Format(System.Globalization.CultureInfo.InvariantCulture, SR.net_http_heade
 265            }
 1232266        }
 267    }
 268}
 269