Example #1
0
    [InlineData("9223372036854775807", 9223372036854775807)] // long.MaxValue
    public void TryParseNonNegativeInt64_Succeeds(string valueString, long expected)
    {
        long value = 1;

        Assert.True(HeaderUtilities.TryParseNonNegativeInt64(valueString, out value));
        Assert.Equal(expected, value);
    }
Example #2
0
    [InlineData("9223372036854775808")] // long.MaxValue + 1
    public void TryParseNonNegativeInt64_Fails(string valueString)
    {
        long value = 1;

        Assert.False(HeaderUtilities.TryParseNonNegativeInt64(valueString, out value));
        Assert.Equal(0, value);
    }
Example #3
0
        private static bool TryParseInt64(string input, out long value)
        {
#if NETSTANDARD2_0
            return(HeaderUtilities.TryParseNonNegativeInt64(input, out value));
#else
            return(HeaderUtilities.TryParseInt64(input, out value));
#endif
        }
        private static long ParseContentLength(string value)
        {
            if (!HeaderUtilities.TryParseNonNegativeInt64(value, out var parsed))
            {
                ThrowInvalidContentLengthException(value);
            }

            return(parsed);
        }
        private static long ParseContentLength(string value)
        {
            if (!HeaderUtilities.TryParseNonNegativeInt64(value, out var parsed))
            {
                KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value);
            }

            return(parsed);
        }
Example #6
0
    internal static int GetRangeItemLength(StringSegment input, int startIndex, out RangeItemHeaderValue?parsedValue)
    {
        Contract.Requires(startIndex >= 0);

        // This parser parses number ranges: e.g. '1-2', '1-', '-2'.

        parsedValue = null;

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

        // Caller must remove leading whitespaces. If not, we'll return 0.
        var current = startIndex;

        // Try parse the first value of a value pair.
        var fromStartIndex = current;
        var fromLength     = HttpRuleParser.GetNumberLength(input, current, false);

        if (fromLength > HttpRuleParser.MaxInt64Digits)
        {
            return(0);
        }

        current = current + fromLength;
        current = current + HttpRuleParser.GetWhitespaceLength(input, current);

        // After the first value, the '-' character must follow.
        if ((current == input.Length) || (input[current] != '-'))
        {
            // We need a '-' character otherwise this can't be a valid range.
            return(0);
        }

        current++; // skip the '-' character
        current = current + HttpRuleParser.GetWhitespaceLength(input, current);

        var toStartIndex = current;
        var toLength     = 0;

        // If we didn't reach the end of the string, try parse the second value of the range.
        if (current < input.Length)
        {
            toLength = HttpRuleParser.GetNumberLength(input, current, false);

            if (toLength > HttpRuleParser.MaxInt64Digits)
            {
                return(0);
            }

            current = current + toLength;
            current = current + HttpRuleParser.GetWhitespaceLength(input, current);
        }

        if ((fromLength == 0) && (toLength == 0))
        {
            return(0); // At least one value must be provided in order to be a valid range.
        }

        // Try convert first value to int64
        long from = 0;

        if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(fromStartIndex, fromLength), out from))
        {
            return(0);
        }

        // Try convert second value to int64
        long to = 0;

        if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(toStartIndex, toLength), out to))
        {
            return(0);
        }

        // 'from' must not be greater than 'to'
        if ((fromLength > 0) && (toLength > 0) && (from > to))
        {
            return(0);
        }

        parsedValue = new RangeItemHeaderValue((fromLength == 0 ? (long?)null : (long?)from),
                                               (toLength == 0 ? (long?)null : (long?)to));
        return(current - startIndex);
    }
Example #7
0
 private static bool TryParseInt64(string input, out long value)
 {
     return(HeaderUtilities.TryParseNonNegativeInt64(input, out value));
 }
Example #8
0
    // name=value; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; samesite={Strict|Lax|None}; httponly
    private static int GetSetCookieLength(StringSegment input, int startIndex, out SetCookieHeaderValue?parsedValue)
    {
        Contract.Requires(startIndex >= 0);
        var offset = startIndex;

        parsedValue = null;

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

        var result = new SetCookieHeaderValue();

        // The caller should have already consumed any leading whitespace, commas, etc..

        // Name=value;

        // Name
        var itemLength = HttpRuleParser.GetTokenLength(input, offset);

        if (itemLength == 0)
        {
            return(0);
        }
        result._name = input.Subsegment(offset, itemLength);
        offset      += itemLength;

        // = (no spaces)
        if (!ReadEqualsSign(input, ref offset))
        {
            return(0);
        }

        // value or "quoted value"
        // The value may be empty
        result._value = CookieHeaderParserShared.GetCookieValue(input, ref offset);

        // *(';' SP cookie-av)
        while (offset < input.Length)
        {
            if (input[offset] == ',')
            {
                // Divider between headers
                break;
            }
            if (input[offset] != ';')
            {
                // Expecting a ';' between parameters
                return(0);
            }
            offset++;

            offset += HttpRuleParser.GetWhitespaceLength(input, offset);

            //  cookie-av = expires-av / max-age-av / domain-av / path-av / secure-av / samesite-av / httponly-av / extension-av
            itemLength = HttpRuleParser.GetTokenLength(input, offset);
            if (itemLength == 0)
            {
                // Trailing ';' or leading into garbage. Let the next parser fail.
                break;
            }
            var token = input.Subsegment(offset, itemLength);
            offset += itemLength;

            //  expires-av = "Expires=" sane-cookie-date
            if (StringSegment.Equals(token, ExpiresToken, StringComparison.OrdinalIgnoreCase))
            {
                // = (no spaces)
                if (!ReadEqualsSign(input, ref offset))
                {
                    return(0);
                }
                // We don't want to include comma, becouse date may contain it (eg. Sun, 06 Nov...)
                var            dateString = ReadToSemicolonOrEnd(input, ref offset, includeComma: false);
                DateTimeOffset expirationDate;
                if (!HttpRuleParser.TryStringToDate(dateString, out expirationDate))
                {
                    // Invalid expiration date, abort
                    return(0);
                }
                result.Expires = expirationDate;
            }
            // max-age-av = "Max-Age=" non-zero-digit *DIGIT
            else if (StringSegment.Equals(token, MaxAgeToken, StringComparison.OrdinalIgnoreCase))
            {
                // = (no spaces)
                if (!ReadEqualsSign(input, ref offset))
                {
                    return(0);
                }

                itemLength = HttpRuleParser.GetNumberLength(input, offset, allowDecimal: false);
                if (itemLength == 0)
                {
                    return(0);
                }
                var  numberString = input.Subsegment(offset, itemLength);
                long maxAge;
                if (!HeaderUtilities.TryParseNonNegativeInt64(numberString, out maxAge))
                {
                    // Invalid expiration date, abort
                    return(0);
                }
                result.MaxAge = TimeSpan.FromSeconds(maxAge);
                offset       += itemLength;
            }
            // domain-av = "Domain=" domain-value
            // domain-value = <subdomain> ; defined in [RFC1034], Section 3.5, as enhanced by [RFC1123], Section 2.1
            else if (StringSegment.Equals(token, DomainToken, StringComparison.OrdinalIgnoreCase))
            {
                // = (no spaces)
                if (!ReadEqualsSign(input, ref offset))
                {
                    return(0);
                }
                // We don't do any detailed validation on the domain.
                result.Domain = ReadToSemicolonOrEnd(input, ref offset);
            }
            // path-av = "Path=" path-value
            // path-value = <any CHAR except CTLs or ";">
            else if (StringSegment.Equals(token, PathToken, StringComparison.OrdinalIgnoreCase))
            {
                // = (no spaces)
                if (!ReadEqualsSign(input, ref offset))
                {
                    return(0);
                }
                // We don't do any detailed validation on the path.
                result.Path = ReadToSemicolonOrEnd(input, ref offset);
            }
            // secure-av = "Secure"
            else if (StringSegment.Equals(token, SecureToken, StringComparison.OrdinalIgnoreCase))
            {
                result.Secure = true;
            }
            // samesite-av = "SameSite=" samesite-value
            // samesite-value = "Strict" / "Lax" / "None"
            else if (StringSegment.Equals(token, SameSiteToken, StringComparison.OrdinalIgnoreCase))
            {
                if (!ReadEqualsSign(input, ref offset))
                {
                    result.SameSite = SameSiteMode.Unspecified;
                }
                else
                {
                    var enforcementMode = ReadToSemicolonOrEnd(input, ref offset);

                    if (StringSegment.Equals(enforcementMode, SameSiteStrictToken, StringComparison.OrdinalIgnoreCase))
                    {
                        result.SameSite = SameSiteMode.Strict;
                    }
                    else if (StringSegment.Equals(enforcementMode, SameSiteLaxToken, StringComparison.OrdinalIgnoreCase))
                    {
                        result.SameSite = SameSiteMode.Lax;
                    }
                    else if (StringSegment.Equals(enforcementMode, SameSiteNoneToken, StringComparison.OrdinalIgnoreCase))
                    {
                        result.SameSite = SameSiteMode.None;
                    }
                    else
                    {
                        result.SameSite = SameSiteMode.Unspecified;
                    }
                }
            }
            // httponly-av = "HttpOnly"
            else if (StringSegment.Equals(token, HttpOnlyToken, StringComparison.OrdinalIgnoreCase))
            {
                result.HttpOnly = true;
            }
            // extension-av = <any CHAR except CTLs or ";">
            else
            {
                var tokenStart = offset - itemLength;
                ReadToSemicolonOrEnd(input, ref offset, includeComma: true);
                result.Extensions.Add(input.Subsegment(tokenStart, offset - tokenStart));
            }
        }

        parsedValue = result;
        return(offset - startIndex);
    }
    private static bool TryCreateContentRange(
        StringSegment input,
        StringSegment unit,
        int fromStartIndex,
        int fromLength,
        int toStartIndex,
        int toLength,
        int lengthStartIndex,
        int lengthLength,
        [NotNullWhen(true)] out ContentRangeHeaderValue?parsedValue)
    {
        parsedValue = null;

        long from = 0;

        if ((fromLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(fromStartIndex, fromLength), out from))
        {
            return(false);
        }

        long to = 0;

        if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(toStartIndex, toLength), out to))
        {
            return(false);
        }

        // 'from' must not be greater than 'to'
        if ((fromLength > 0) && (toLength > 0) && (from > to))
        {
            return(false);
        }

        long length = 0;

        if ((lengthLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(lengthStartIndex, lengthLength),
                                                                            out length))
        {
            return(false);
        }

        // 'from' and 'to' must be less than 'length'
        if ((toLength > 0) && (lengthLength > 0) && (to >= length))
        {
            return(false);
        }

        var result = new ContentRangeHeaderValue();

        result._unit = unit;

        if (fromLength > 0)
        {
            result.From = from;
            result.To   = to;
        }

        if (lengthLength > 0)
        {
            result.Length = length;
        }

        parsedValue = result;
        return(true);
    }