private static void CheckGetNextNonEmptyOrWhitespaceIndex(string input, int startIndex,
                                                                  bool supportsEmptyValues, int expectedIndex, bool expectedSeparatorFound)
        {
            bool separatorFound = false;

            Assert.Equal(expectedIndex, HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, startIndex,
                                                                                         supportsEmptyValues, out separatorFound));
            Assert.Equal(expectedSeparatorFound, separatorFound);
        }
Example #2
0
        public sealed override bool TryParseValue(string value, object storeValue, ref int index,
                                                  out object parsedValue)
        {
            parsedValue = null;

            // If multiple values are supported (i.e. list of values), then accept an empty string: The header may
            // be added multiple times to the request/response message. E.g.
            //  Accept: text/xml; q=1
            //  Accept:
            //  Accept: text/plain; q=0.2
            if (string.IsNullOrEmpty(value) || (index == value.Length))
            {
                return(SupportsMultipleValues);
            }

            bool separatorFound = false;
            int  current        = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(value, index, SupportsMultipleValues,
                                                                                   out separatorFound);

            if (separatorFound && !SupportsMultipleValues)
            {
                return(false); // leading separators not allowed if we don't support multiple values.
            }

            if (current == value.Length)
            {
                if (SupportsMultipleValues)
                {
                    index = current;
                }
                return(SupportsMultipleValues);
            }

            object result = null;
            int    length = GetParsedValueLength(value, current, storeValue, out result);

            if (length == 0)
            {
                return(false);
            }

            current = current + length;
            current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(value, current, SupportsMultipleValues,
                                                                       out separatorFound);

            // If we support multiple values and we've not reached the end of the string, then we must have a separator.
            if ((separatorFound && !SupportsMultipleValues) || (!separatorFound && (current < value.Length)))
            {
                return(false);
            }

            index       = current;
            parsedValue = result;
            return(true);
        }
Example #3
0
    // Returns the length of a range list. E.g. "1-2, 3-4, 5-6" adds 3 ranges to 'rangeCollection'. Note that empty
    // list segments are allowed, e.g. ",1-2, , 3-4,,".
    internal static int GetRangeItemListLength(
        StringSegment input,
        int startIndex,
        ICollection <RangeItemHeaderValue> rangeCollection)
    {
        Contract.Requires(startIndex >= 0);
        Contract.Ensures((Contract.Result <int>() == 0) || (rangeCollection.Count > 0),
                         "If we can parse the string, then we expect to have at least one range item.");

        if ((StringSegment.IsNullOrEmpty(input)) || (startIndex >= input.Length))
        {
            return(0);
        }

        // Empty segments are allowed, so skip all delimiter-only segments (e.g. ", ,").
        var current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, startIndex, true, separatorFound: out _);

        // It's OK if we didn't find leading separator characters. Ignore 'separatorFound'.

        if (current == input.Length)
        {
            return(0);
        }

        while (true)
        {
            var rangeLength = GetRangeItemLength(input, current, out var range);

            if (rangeLength == 0)
            {
                return(0);
            }

            rangeCollection !.Add(range !);

            current = current + rangeLength;
            current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, current, true, out var separatorFound);

            // If the string is not consumed, we must have a delimiter, otherwise the string is not a valid
            // range list.
            if ((current < input.Length) && !separatorFound)
            {
                return(0);
            }

            if (current == input.Length)
            {
                return(current - startIndex);
            }
        }
    }
Example #4
0
    private static bool TrySetOptionalTokenList(
        NameValueHeaderValue nameValue,
        ref bool boolField,
        ref ICollection <StringSegment>?destination)
    {
        if (nameValue.Value == null)
        {
            boolField = true;
            return(true);
        }

        // We need the string to be at least 3 chars long: 2x quotes and at least 1 character. Also make sure we
        // have a quoted string. Note that NameValueHeaderValue will never have leading/trailing whitespaces.
        var valueString = nameValue.Value;

        if ((valueString.Length < 3) || (valueString[0] != '\"') || (valueString[valueString.Length - 1] != '\"'))
        {
            return(false);
        }

        // We have a quoted string. Now verify that the string contains a list of valid tokens separated by ','.
        var current            = 1;                      // skip the initial '"' character.
        var maxLength          = valueString.Length - 1; // -1 because we don't want to parse the final '"'.
        var originalValueCount = destination == null ? 0 : destination.Count;

        while (current < maxLength)
        {
            current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(valueString, current, true,
                                                                       out var separatorFound);

            if (current == maxLength)
            {
                break;
            }

            var tokenLength = HttpRuleParser.GetTokenLength(valueString, current);

            if (tokenLength == 0)
            {
                // We already skipped whitespaces and separators. If we don't have a token it must be an invalid
                // character.
                return(false);
            }

            if (destination == null)
            {
                destination = new ObjectCollection <StringSegment>(CheckIsValidTokenAction);
            }

            destination.Add(valueString.Subsegment(current, tokenLength));

            current = current + tokenLength;
        }

        // After parsing a valid token list, we expect to have at least one value
        if ((destination != null) && (destination.Count > originalValueCount))
        {
            boolField = true;
            return(true);
        }

        return(false);
    }