File: ParserTests.cs
Web Access
Project: src\test\Libraries\Microsoft.AspNetCore.HeaderParsing.Tests\Microsoft.AspNetCore.HeaderParsing.Tests.csproj (Microsoft.AspNetCore.HeaderParsing.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using Microsoft.AspNetCore.HeaderParsing.Parsers;
using Microsoft.Extensions.Primitives;
using Xunit;
using UriParser = Microsoft.AspNetCore.HeaderParsing.Parsers.UriParser;
 
namespace Microsoft.AspNetCore.HeaderParsing.Test;
 
public class ParserTests
{
    [Fact]
    public void Host_ReturnsParsedValue()
    {
        var sv = new StringValues("web.vortex.data.microsoft.com");
        Assert.True(HostHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal("web.vortex.data.microsoft.com", result.Host);
        Assert.Null(result.Port);
        Assert.Null(error);
    }
 
    [Fact]
    public void Host_Multi()
    {
        var sv = new StringValues(new[] { "Hello", "World" });
        Assert.False(HostHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Date_ReturnsParsedValue()
    {
        var sv = new StringValues("Wed, 21 Oct 2015 07:28:14 GMT");
        Assert.True(DateTimeOffsetParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal(DayOfWeek.Wednesday, result.DayOfWeek);
        Assert.Equal(21, result.Day);
        Assert.Equal(10, result.Month);
        Assert.Equal(2015, result.Year);
        Assert.Equal(7, result.Hour);
        Assert.Equal(28, result.Minute);
        Assert.Equal(14, result.Second);
        Assert.Null(error);
    }
 
    [Fact]
    public void Date_ReturnsNullForEmptyValue()
    {
        var sv = new StringValues(string.Empty);
        Assert.False(DateTimeOffsetParser.Instance.TryParse(sv, out var result, out var error));
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Date_ReturnsNullForInvalidValue()
    {
        var sv = new StringValues("Hello World");
        Assert.False(DateTimeOffsetParser.Instance.TryParse(sv, out var result, out var error));
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Date_Multi()
    {
        var sv = new StringValues(new[] { "Hello", "World" });
        Assert.False(DateTimeOffsetParser.Instance.TryParse(sv, out var result, out var error));
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Cookkie_ReturnsParsedValue()
    {
        var sv = new StringValues("csrftoken=u32t4o3tb3gg43");
        Assert.True(CookieHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Single(result);
        Assert.Equal("csrftoken", result[0].Name.Value);
        Assert.Equal("u32t4o3tb3gg43", result[0].Value.Value);
        Assert.Null(error);
    }
 
    [Fact]
    public void Cookie_ReturnsMultipleCookiesForMultipleCookies()
    {
        var sv = new StringValues("csrftoken=u32t4o3tb3gg43; _gat=1");
        Assert.True(CookieHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal(2, result.Count);
        Assert.Equal("csrftoken", result[0].Name.Value);
        Assert.Equal("u32t4o3tb3gg43", result[0].Value.Value);
        Assert.Equal("_gat", result[1].Name.Value);
        Assert.Equal("1", result[1].Value.Value);
        Assert.Null(error);
    }
 
    [Fact]
    public void Cookie_ReturnsNullForEmptyValue()
    {
        var sv = new StringValues(string.Empty);
        Assert.False(CookieHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Cookie_ReturnsNullForInvalidValue()
    {
        var sv = new StringValues("HelloWorld");
        Assert.False(CookieHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void CacheControl_ReturnsParsedValue()
    {
        var sv = new StringValues("public, max-age=604800");
        Assert.True(CacheControlHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.True(result.Public);
        Assert.Equal(TimeSpan.FromSeconds(604800), result.MaxAge);
        Assert.Null(error);
    }
 
    [Fact]
    public void CacheControl_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues("ZZZ=ZZZ=ZZZ=ZZZ");
        Assert.False(CacheControlHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void CacheControl_Multi()
    {
        var sv = new StringValues(new[] { "Hello", "World" });
        Assert.False(CacheControlHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void ContentDisposition_ReturnsParsedValue()
    {
        var sv = new StringValues("attachment; filename=\"cool.html\"");
        Assert.True(ContentDispositionHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal("cool.html", result.FileName);
        Assert.Equal("attachment", result.DispositionType);
        Assert.Null(error);
    }
 
    [Fact]
    public void ContentDisposition_Multi()
    {
        var sv = new StringValues(new[] { "attachment; filename=\"cool.html\"", "attachment; filename=\"cool.html\"" });
        Assert.False(ContentDispositionHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void ContentDisposition_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues("zz=zz=zz");
        Assert.False(ContentDispositionHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void MediaType_ReturnsParsedValue()
    {
        var sv = new StringValues("text/html; charset=UTF-8");
        Assert.True(MediaTypeHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal("text/html", result.MediaType);
        Assert.Equal("UTF-8", result.Charset);
        Assert.Null(error);
    }
 
    [Fact]
    public void MediaType_Multi()
    {
        var sv = new StringValues(new[] { "text/html; charset=UTF-8", "text/html; charset=UTF-8" });
        Assert.False(MediaTypeHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void MediaType_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues(string.Empty);
        Assert.False(MediaTypeHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void MediaTypes_ReturnsParsedValue()
    {
        var sv = new StringValues("text/html; charset=UTF-8");
        Assert.True(MediaTypeHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Single(result);
        Assert.Equal("text/html", result[0].MediaType);
        Assert.Equal("UTF-8", result[0].Charset);
        Assert.Null(error);
    }
 
    [Fact]
    public void MediaTypes_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues(string.Empty);
        Assert.False(MediaTypeHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void EntityTag_ReturnsParsedValue()
    {
        var sv = new StringValues("\"HelloWorld\"");
        Assert.True(EntityTagHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Single(result!);
        Assert.Equal("\"HelloWorld\"", result[0].Tag);
        Assert.Null(error);
    }
 
    [Fact]
    public void EntityTag_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues(string.Empty);
        Assert.False(EntityTagHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void StringQuality_ReturnsParsedValue()
    {
        var sv = new StringValues("en-US");
        Assert.True(StringWithQualityHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Single(result!);
        Assert.Equal("en-US", result[0].Value);
        Assert.Null(error);
    }
 
    [Fact]
    public void StringQuality_Multi()
    {
        var sv = new StringValues("en-US,en;q=0.5");
        Assert.True(StringWithQualityHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal(2, result.Count);
        Assert.Equal("en-US", result[0].Value);
        Assert.Equal("en", result[1].Value);
        Assert.Equal(0.5, result[1].Quality);
        Assert.Null(error);
    }
 
    [Fact]
    public void StringQuality_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues(string.Empty);
        Assert.False(StringWithQualityHeaderValueListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Uri_ReturnsParsedValue()
    {
        var sv = new StringValues("https://foo.com:81");
        Assert.True(UriParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal("foo.com", result!.Host);
        Assert.Equal(81, result.Port);
        Assert.Null(error);
    }
 
    [Fact]
    public void Uri_Multi()
    {
        var sv = new StringValues(new[] { "http://foo.com", "http://bar.com" });
        Assert.False(UriParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Uri_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues("http://localhost:XXX");
        Assert.False(UriParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Range_ReturnsParsedValue()
    {
        var sv = new StringValues("bytes=200-1000");
        Assert.True(RangeHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal("bytes", result!.Unit);
        Assert.Single(result.Ranges);
        Assert.Equal(200, result.Ranges.Single().From);
        Assert.Equal(1000, result.Ranges.Single().To);
        Assert.Null(error);
    }
 
    [Fact]
    public void Range_Multi()
    {
        var sv = new StringValues(new[] { "bytes=200-1000", "bytes=3000-4000" });
        Assert.False(RangeHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void Range_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues("Hello World");
        Assert.False(RangeHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void RangeCondition_ReturnsParsedValue()
    {
        var sv = new StringValues("Wed, 21 Oct 2015 07:28:14 GMT");
        Assert.True(RangeConditionHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Equal(DayOfWeek.Wednesday, result!.LastModified!.Value.DayOfWeek);
        Assert.Equal(21, result!.LastModified.Value.Day);
        Assert.Equal(10, result!.LastModified.Value.Month);
        Assert.Equal(2015, result!.LastModified.Value.Year);
        Assert.Equal(7, result!.LastModified.Value.Hour);
        Assert.Equal(28, result!.LastModified!.Value.Minute);
        Assert.Equal(14, result!.LastModified.Value.Second);
        Assert.Null(error);
 
        sv = new StringValues("\"67ab43\"");
        Assert.True(RangeConditionHeaderValueParser.Instance.TryParse(sv, out result, out error));
        Assert.Equal("\"67ab43\"", result!.EntityTag!.Tag);
        Assert.Null(error);
    }
 
    [Fact]
    public void RangeCondition_Multi()
    {
        var sv = new StringValues(new[] { "\"67ab43\"", "\"67ab43\"" });
        Assert.False(RangeConditionHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void RangeCondition_ReturnsNullWhenInvalid()
    {
        var sv = new StringValues("Hello World");
        Assert.False(RangeConditionHeaderValueParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void IpAddressesList_WithSpaces_ReturnsParsedValue()
    {
        var sv = new StringValues(new[] { "    1.1.1.1    ,    192.168.1.100    ", "    3.3.3.3    " });
        Assert.True(IPAddressListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.NotNull(result);
        Assert.Equal(new List<IPAddress> { IPAddress.Parse("1.1.1.1"), IPAddress.Parse("192.168.1.100"), IPAddress.Parse("3.3.3.3") }, result);
        Assert.Null(error);
    }
 
    [Fact]
    public void IpAddressesList_NoSpaces_ReturnsParsedValue()
    {
        var sv = new StringValues(new[] { "1.1.1.1,192.168.1.100", "3.3.3.3" });
        Assert.True(IPAddressListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.NotNull(result);
        Assert.Equal(new List<IPAddress> { IPAddress.Parse("1.1.1.1"), IPAddress.Parse("192.168.1.100"), IPAddress.Parse("3.3.3.3") }, result);
        Assert.Null(error);
    }
 
    [Theory]
    [InlineData("      1.1.1.1")]
    [InlineData("1.1.1.1")]
    public void IpAddressesList_SingleIpV4_ReturnsParsedValue(string testValue)
    {
        var sv = new StringValues(new[] { testValue });
        Assert.True(IPAddressListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.NotNull(result);
        Assert.Equal(new List<IPAddress> { IPAddress.Parse("1.1.1.1") }, result);
        Assert.Null(error);
    }
 
    [Theory]
    [InlineData("      1::ffff")]
    [InlineData("1::ffff")]
    public void IpAddressesList_SingleIpV6_ReturnsParsedValue(string testValue)
    {
        var sv = new StringValues(new[] { testValue });
        Assert.True(IPAddressListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.NotNull(result);
        Assert.Equal(new List<IPAddress> { IPAddress.Parse("1::ffff") }, result);
        Assert.Null(error);
    }
 
    [Theory]
    [InlineData("1.1.1.1, 2.2.2.2", "a.b.c.d")]
    [InlineData("1.1.1.1,,2.2.2.2")]
    [InlineData("1.1.1.1,")]
    public void IpAddressesList_Malformed_ReturnsNull(params string[] values)
    {
        var sv = new StringValues(values);
        Assert.False(IPAddressListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.False(string.IsNullOrEmpty(error));
    }
 
    [Fact]
    public void IpAddressesList_FirstEmptyIp_ReturnsErrorAboutEmptyIp()
    {
        var sv = new StringValues(",1.1.1.1");
        Assert.False(IPAddressListParser.Instance.TryParse(sv, out var result, out var error));
        Assert.Null(result);
        Assert.Equal("IP address cannot be empty.", error);
    }
}