< Summary

Information
Class: System.Net.Http.Headers.RangeItemHeaderValue
Assembly: System.Net.Http
File(s): D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\RangeItemHeaderValue.cs
Line coverage
70%
Covered lines: 84
Uncovered lines: 35
Coverable lines: 119
Total lines: 216
Line coverage: 70.5%
Branch coverage
78%
Covered branches: 58
Total branches: 74
Branch coverage: 78.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)91.66%121290%
.ctor(...)100%110%
ToString()0%440%
Equals(...)0%440%
GetHashCode()100%110%
GetRangeItemListLength(...)92.85%1414100%
GetRangeItemLength(...)83.33%363678.72%
System.ICloneable.Clone()100%110%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\Headers\RangeItemHeaderValue.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;
 8
 9namespace System.Net.Http.Headers
 10{
 11    public class RangeItemHeaderValue : ICloneable
 12    {
 13        // Set to -1 if not set.
 14        private readonly long _from;
 15        private readonly long _to;
 16
 10207217        public long? From => _from >= 0 ? _from : null;
 18
 7061419        public long? To => _to >= 0 ? _to : null;
 20
 4470821        public RangeItemHeaderValue(long? from, long? to)
 4470822        {
 4470823            if (!from.HasValue && !to.HasValue)
 024            {
 025                throw new ArgumentException(SR.net_http_headers_invalid_range);
 26            }
 4470827            if (from.HasValue)
 3950628            {
 3950629                ArgumentOutOfRangeException.ThrowIfNegative(from.GetValueOrDefault(), nameof(from));
 3950630            }
 4470831            if (to.HasValue)
 1565632            {
 1565633                ArgumentOutOfRangeException.ThrowIfNegative(to.GetValueOrDefault(), nameof(to));
 1565634            }
 4470835            if (from.HasValue && to.HasValue)
 1045436            {
 1045437                ArgumentOutOfRangeException.ThrowIfGreaterThan(from.GetValueOrDefault(), to.GetValueOrDefault(), nameof(
 1045438            }
 39
 4470840            _from = from ?? -1;
 4470841            _to = to ?? -1;
 4470842        }
 43
 044        internal RangeItemHeaderValue(RangeItemHeaderValue source)
 045        {
 046            Debug.Assert(source != null);
 47
 048            _from = source._from;
 049            _to = source._to;
 050        }
 51
 52        public override string ToString()
 053        {
 054            Span<char> stackBuffer = stackalloc char[128];
 55
 056            if (_from < 0)
 057            {
 058                return string.Create(CultureInfo.InvariantCulture, stackBuffer, $"-{_to}");
 59            }
 60
 061            if (_to < 0)
 062            {
 063                return string.Create(CultureInfo.InvariantCulture, stackBuffer, $"{_from}-"); ;
 64            }
 65
 066            return string.Create(CultureInfo.InvariantCulture, stackBuffer, $"{_from}-{_to}");
 067        }
 68
 69        public override bool Equals([NotNullWhen(true)] object? obj) =>
 070            obj is RangeItemHeaderValue other &&
 071            _from == other._from &&
 072            _to == other._to;
 73
 74        public override int GetHashCode() =>
 075            HashCode.Combine(_from, _to);
 76
 77        // Returns the length of a range list. E.g. "1-2, 3-4, 5-6" adds 3 ranges to 'rangeCollection'. Note that empty
 78        // list segments are allowed, e.g. ",1-2, , 3-4,,".
 79        internal static int GetRangeItemListLength(string? input, int startIndex,
 80            ICollection<RangeItemHeaderValue> rangeCollection)
 106481        {
 106482            Debug.Assert(rangeCollection != null);
 106483            Debug.Assert(startIndex >= 0);
 84
 106485            if ((string.IsNullOrEmpty(input)) || (startIndex >= input.Length))
 1486            {
 1487                return 0;
 88            }
 89
 90            // Empty segments are allowed, so skip all delimiter-only segments (e.g. ", ,").
 105091            int current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, startIndex, true, out _);
 92            // It's OK if we didn't find leading separator characters. Ignore 'separatorFound'.
 93
 105094            if (current == input.Length)
 495            {
 496                return 0;
 97            }
 98
 4510899            while (true)
 45108100            {
 45108101                int rangeLength = GetRangeItemLength(input, current, out RangeItemHeaderValue? range);
 102
 45108103                if (rangeLength == 0)
 400104                {
 400105                    return 0;
 106                }
 107
 44708108                rangeCollection.Add(range!);
 109
 44708110                current += rangeLength;
 44708111                current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, current, true, out bool separatorFound
 112
 113                // If the string is not consumed, we must have a delimiter, otherwise the string is not a valid
 114                // range list.
 44708115                if ((current < input.Length) && !separatorFound)
 160116                {
 160117                    return 0;
 118                }
 119
 44548120                if (current == input.Length)
 486121                {
 486122                    return current - startIndex;
 123                }
 44062124            }
 1064125        }
 126
 127        internal static int GetRangeItemLength(string? input, int startIndex, out RangeItemHeaderValue? parsedValue)
 45108128        {
 45108129            Debug.Assert(startIndex >= 0);
 130
 131            // This parser parses number ranges: e.g. '1-2', '1-', '-2'.
 132
 45108133            parsedValue = null;
 134
 45108135            if (string.IsNullOrEmpty(input) || (startIndex >= input.Length))
 0136            {
 0137                return 0;
 138            }
 139
 140            // Caller must remove leading whitespace. If not, we'll return 0.
 45108141            int current = startIndex;
 142
 143            // Try parse the first value of a value pair.
 45108144            int fromStartIndex = current;
 45108145            int fromLength = HttpRuleParser.GetNumberLength(input, current, false);
 146
 45108147            if (fromLength > HttpRuleParser.MaxInt64Digits)
 0148            {
 0149                return 0;
 150            }
 151
 45108152            current += fromLength;
 45108153            current += HttpRuleParser.GetWhitespaceLength(input, current);
 154
 155            // After the first value, the '-' character must follow.
 45108156            if ((current == input.Length) || (input[current] != '-'))
 254157            {
 158                // We need a '-' character otherwise this can't be a valid range.
 254159                return 0;
 160            }
 161
 44854162            current++; // skip the '-' character
 44854163            current += HttpRuleParser.GetWhitespaceLength(input, current);
 164
 44854165            int toStartIndex = current;
 44854166            int toLength = 0;
 167
 168            // If we didn't reach the end of the string, try parse the second value of the range.
 44854169            if (current < input.Length)
 44772170            {
 44772171                toLength = HttpRuleParser.GetNumberLength(input, current, false);
 172
 44772173                if (toLength > HttpRuleParser.MaxInt64Digits)
 0174                {
 0175                    return 0;
 176                }
 177
 44772178                current += toLength;
 44772179                current += HttpRuleParser.GetWhitespaceLength(input, current);
 44772180            }
 181
 44854182            if ((fromLength == 0) && (toLength == 0))
 144183            {
 144184                return 0; // At least one value must be provided in order to be a valid range.
 185            }
 186
 187            // Try convert first value to int64
 44710188            long from = 0;
 44710189            if ((fromLength > 0) && !HeaderUtilities.TryParseInt64(input, fromStartIndex, fromLength, out from))
 0190            {
 0191                return 0;
 192            }
 193
 194            // Try convert second value to int64
 44710195            long to = 0;
 44710196            if ((toLength > 0) && !HeaderUtilities.TryParseInt64(input, toStartIndex, toLength, out to))
 0197            {
 0198                return 0;
 199            }
 200
 201            // 'from' must not be greater than 'to'
 44710202            if ((fromLength > 0) && (toLength > 0) && (from > to))
 2203            {
 2204                return 0;
 205            }
 206
 44708207            parsedValue = new RangeItemHeaderValue((fromLength == 0 ? null : from), (toLength == 0 ? null : to));
 44708208            return current - startIndex;
 45108209        }
 210
 211        object ICloneable.Clone()
 0212        {
 0213            return new RangeItemHeaderValue(this);
 0214        }
 215    }
 216}