Merge pull request #23427 from dotnet-maestro-bot/merge/release/5.0-preview7-to-master

[automated] Merge branch 'release/5.0-preview7' => 'master'
This commit is contained in:
Pranav K 2020-07-01 07:27:53 -07:00 committed by GitHub
commit dc4670e8d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 450 additions and 243 deletions

View File

@ -1,15 +1,9 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.Components.Authorization.netstandard2.0.cs" />
<Reference Include="Microsoft.AspNetCore.Authorization" />
<Reference Include="Microsoft.AspNetCore.Components" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.AspNetCore.Components.Authorization.netcoreapp.cs" />
<Reference Include="Microsoft.AspNetCore.Authorization" />
<Reference Include="Microsoft.AspNetCore.Components" />

View File

@ -1,12 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<Description>Authentication and authorization support for Blazor applications.</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RazorLangVersion>3.0</RazorLangVersion>
</PropertyGroup>
<ItemGroup>

View File

@ -1,19 +1,10 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.Components.netstandard2.0.cs" />
<Compile Include="Microsoft.AspNetCore.Components.Manual.cs" />
<Compile Include="../src/Properties/AssemblyInfo.cs" />
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<Reference Include="System.Buffers" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.AspNetCore.Components.netcoreapp.cs" />
<Compile Include="Microsoft.AspNetCore.Components.Manual.cs" />
<Compile Include="../src/Properties/AssemblyInfo.cs" />

View File

@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Description>Components feature for ASP.NET Core.</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
@ -17,19 +16,12 @@
<ItemGroup>
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<Compile Include="$(SharedSourceRoot)HashCodeCombiner\*.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
<Reference Include="System.Buffers" />
</ItemGroup>
<!-- These references were removed in 3.0 -->
<ItemGroup>
<SuppressBaselineReference Include="Microsoft.AspNetCore.Components.Analyzers" />
<SuppressBaselineReference Include="Microsoft.AspNetCore.Authorization" />
<SuppressBaselineReference Include="Microsoft.JSInterop" />
<SuppressBaselineReference Include="System.ComponentModel.Annotations" />
</ItemGroup>
@ -38,27 +30,25 @@
BuildInParallel="$(BuildInParallel)"
Projects="
../../Analyzers/src/Microsoft.AspNetCore.Components.Analyzers.csproj;
../../../JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj;
../../../Security/Authorization/Core/src/Microsoft.AspNetCore.Authorization.csproj">
<Output TaskParameter="TargetOutputs" ItemName="_ProjectPathWithVersion" />
</MSBuild>
<ItemGroup>
<NuspecProperty Include="@(_ProjectPathWithVersion->WithMetadataValue('PackageId', 'Microsoft.AspnetCore.Components.Analyzers')->'componentAnalyzerPackageVersion=%(PackageVersion)')" />
<NuspecProperty Include="@(_ProjectPathWithVersion->WithMetadataValue('PackageId', 'Microsoft.AspnetCore.Authorization')->'authorizationPackageVersion=%(PackageVersion)')" />
<NuspecProperty Include="@(_ProjectPathWithVersion->WithMetadataValue('PackageId', 'Microsoft.JSInterop')->'jsInteropPackageVersion=%(PackageVersion)')" />
</ItemGroup>
</Target>
<!-- Pack settings -->
<PropertyGroup>
<NuspecFile>Microsoft.AspNetCore.Components.multitarget.nuspec</NuspecFile>
<NuspecFile Condition="'$(DotNetBuildFromSource)' == 'true'">Microsoft.AspNetCore.Components.netcoreapp.nuspec</NuspecFile>
<NuspecFile>Microsoft.AspNetCore.Components.netcoreapp.nuspec</NuspecFile>
<GenerateNuspecDependsOn>$(GenerateNuspecDependsOn);_GetNuspecDependencyPackageVersions</GenerateNuspecDependsOn>
</PropertyGroup>
<ItemGroup>
<NuspecProperty Condition="'$(DotNetBuildFromSource)' != 'true'" Include="systemComponentModelAnnotationsPackageVersion=$(SystemComponentModelAnnotationsPackageVersion)" />
<NuspecProperty Include="AssemblyName=$(AssemblyName)" />
<NuspecProperty Include="DefaultNetCoreTargetFramework=$(DefaultNetCoreTargetFramework)" />
<NuspecProperty Include="OutputPath=$(OutputPath)" />
<NuspecProperty Include="PackageThirdPartyNoticesFile=$(PackageThirdPartyNoticesFile)" />
</ItemGroup>

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
$CommonMetadataElements$
<dependencies>
<group targetFramework=".NETStandard2.0">
<dependency id="Microsoft.AspNetCore.Components.Analyzers" version="$componentAnalyzerPackageVersion$" />
<dependency id="Microsoft.AspNetCore.Authorization" version="$authorizationPackageVersion$" exclude="Build,Analyzers" />
<dependency id="Microsoft.JSInterop" version="$jsInteropPackageVersion$" exclude="Build,Analyzers" />
<dependency id="System.ComponentModel.Annotations" version="$systemComponentModelAnnotationsPackageVersion$" exclude="Build,Analyzers" />
</group>
<group targetFramework=".net5.0">
<dependency id="Microsoft.AspNetCore.Components.Analyzers" version="$componentAnalyzerPackageVersion$" />
<dependency id="Microsoft.AspNetCore.Authorization" version="$authorizationPackageVersion$" exclude="Build,Analyzers" />
<dependency id="Microsoft.JSInterop" version="$jsInteropPackageVersion$" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
<files>
$CommonFileElements$
<file src="$OutputPath$**\$AssemblyName$.dll" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.pdb" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.xml" target="lib\" />
<file src="$PackageThirdPartyNoticesFile$" target=".\THIRD-PARTY-NOTICES.txt" />
</files>
</package>

View File

@ -6,15 +6,14 @@
<group targetFramework=".net5.0">
<dependency id="Microsoft.AspNetCore.Components.Analyzers" version="$componentAnalyzerPackageVersion$" />
<dependency id="Microsoft.AspNetCore.Authorization" version="$authorizationPackageVersion$" exclude="Build,Analyzers" />
<dependency id="Microsoft.JSInterop" version="$jsInteropPackageVersion$" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
<files>
$CommonFileElements$
<file src="$OutputPath$**\$AssemblyName$.dll" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.pdb" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.xml" target="lib\" />
<file src="$OutputPath$$AssemblyName$.dll" target="lib\$DefaultNetCoreTargetFramework$\" />
<file src="$OutputPath$$AssemblyName$.pdb" target="lib\$DefaultNetCoreTargetFramework$\" />
<file src="$OutputPath$$AssemblyName$.xml" target="lib\$DefaultNetCoreTargetFramework$\" />
<file src="$PackageThirdPartyNoticesFile$" target=".\THIRD-PARTY-NOTICES.txt" />
</files>
</package>

View File

@ -221,7 +221,7 @@ namespace Microsoft.AspNetCore.Components
public override int GetHashCode()
{
var hash = new HashCodeCombiner();
var hash = new HashCode();
if (Assemblies != null)
{
@ -231,7 +231,7 @@ namespace Microsoft.AspNetCore.Components
}
}
return hash;
return hash.ToHashCode();
}
}
}

View File

@ -1,16 +1,10 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.Components.Forms.netstandard2.0.cs" />
<Reference Include="Microsoft.AspNetCore.Components" />
<Reference Include="System.ComponentModel.Annotations" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.AspNetCore.Components.Forms.netcoreapp.cs" />
<Reference Include="Microsoft.AspNetCore.Components" />
</ItemGroup>

View File

@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<Description>Forms and validation support for Blazor applications.</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
@ -13,8 +12,4 @@
<Reference Include="Microsoft.AspNetCore.Components" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'" >
<Reference Include="System.ComponentModel.Annotations" />
</ItemGroup>
</Project>

View File

@ -1,19 +1,10 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.AspNetCore.Components.Web.netstandard2.0.cs" />
<Compile Include="../src/Properties/AssemblyInfo.cs" />
<Reference Include="Microsoft.AspNetCore.Components" />
<Reference Include="Microsoft.AspNetCore.Components.Forms" />
<Reference Include="Microsoft.Extensions.DependencyInjection" />
<Reference Include="Microsoft.JSInterop" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.AspNetCore.Components.Web.netcoreapp.cs" />
<Compile Include="../src/Properties/AssemblyInfo.cs" />
<Reference Include="Microsoft.AspNetCore.Components" />

View File

@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<IsAspNetCoreApp>true</IsAspNetCoreApp>
<Description>Support for rendering ASP.NET Core components for browsers.</Description>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@ -3,9 +3,8 @@
<Sdk Name="Yarn.MSBuild" />
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Description>Authenticate your Blazor webassembly applications with Azure Active Directory and Azure Active Directory B2C</Description>
<RazorLangVersion>3.0</RazorLangVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Description>Abstractions and features for interop between .NET WebAssembly and JavaScript code.</Description>
<PackageTags>wasm;javascript;interop</PackageTags>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@ -3,10 +3,9 @@
<Sdk Name="Yarn.MSBuild" />
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Description>Build client-side authentication for single-page applications (SPAs).</Description>
<IsShippingPackage>true</IsShippingPackage>
<RazorLangVersion>3.0</RazorLangVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Description>Build client-side single-page applications (SPAs) with Blazor running under WebAssembly.</Description>
<IsShippingPackage>true</IsShippingPackage>
<NoWarn>$(NoWarn);BL0006</NoWarn>
@ -44,7 +44,7 @@
</PropertyGroup>
<ItemGroup>
<Content Include="$(BlazorWebAssemblyJSFile)" Pack="true" PackagePath="build\netstandard2.0\" LinkBase="build\netstandard2.0\" />
<Content Include="build\netstandard2.0\*.props" Pack="true" PackagePath="build\netstandard2.0\" />
<Content Include="$(BlazorWebAssemblyJSFile)" Pack="true" PackagePath="build\net5.0\" LinkBase="build\net5.0\" />
<Content Include="build\net5.0\*.props" Pack="true" PackagePath="build\net5.0\" />
</ItemGroup>
</Project>

View File

@ -1,5 +0,0 @@
<Project>
<PropertyGroup>
<BlazorWebAssemblyJSPath>$(MSBuildThisFileDirectory)blazor.webassembly.js</BlazorWebAssemblyJSPath>
</PropertyGroup>
</Project>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<FixupWebAssemblyHttpHandlerReference>true</FixupWebAssemblyHttpHandlerReference>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<UseBlazorWebAssembly>true</UseBlazorWebAssembly>
<IsTestAssetProject>true</IsTestAssetProject>

View File

@ -1,9 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<OutputType>library</OutputType>
<RazorLangVersion>3.0</RazorLangVersion>
<StaticWebAssetBasePath>_content/TestContentPackage</StaticWebAssetBasePath>
</PropertyGroup>

View File

@ -1,16 +1,10 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Nullable>annotations</Nullable>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.JSInterop.netstandard2.0.cs" />
<Reference Include="System.Text.Json" />
<InternalsVisibleTo Include="Microsoft.JSInterop.Tests" Key="" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.JSInterop.netcoreapp.cs" />
<InternalsVisibleTo Include="Microsoft.JSInterop.Tests" Key="" />
</ItemGroup>

View File

@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Description>Abstractions and features for interop between .NET and JavaScript code.</Description>
<PackageTags>javascript;interop</PackageTags>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

View File

@ -1,9 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework Condition="'$(SupportPagesAndViews)' == 'True'">${DefaultNetCoreTargetFramework}</TargetFramework>
<TargetFramework Condition="'$(SupportPagesAndViews)' != 'True'">netstandard2.0</TargetFramework>
<RazorLangVersion Condition="'$(SupportPagesAndViews)' != 'True'">3.0</RazorLangVersion>
<TargetFramework>${DefaultNetCoreTargetFramework}</TargetFramework>
<AddRazorSupportForMvc Condition="'$(SupportPagesAndViews)' == 'True'">true</AddRazorSupportForMvc>
<RootNamespace Condition="'$(name)' != '$(name{-VALUE-FORMS-}safe_namespace)'">Company.RazorClassLibrary1</RootNamespace>
</PropertyGroup>
@ -13,7 +11,6 @@
</ItemGroup>
<ItemGroup Condition="'$(SupportPagesAndViews)' != 'True'">
<PackageReference Include="Microsoft.AspNetCore.Components" Version="${MicrosoftAspNetCoreComponentsPackageVersion}" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="${MicrosoftAspNetCoreComponentsWebPackageVersion}" />
</ItemGroup>

View File

@ -20,7 +20,9 @@ namespace Microsoft.AspNetCore.Razor.Language
public static readonly RazorLanguageVersion Version_3_0 = new RazorLanguageVersion(3, 0);
public static readonly RazorLanguageVersion Latest = Version_3_0;
public static readonly RazorLanguageVersion Version_5_0 = new RazorLanguageVersion(5, 0);
public static readonly RazorLanguageVersion Latest = Version_5_0;
public static readonly RazorLanguageVersion Experimental = new RazorLanguageVersion(1337, 1337);
@ -41,6 +43,11 @@ namespace Microsoft.AspNetCore.Razor.Language
version = Experimental;
return true;
}
else if (languageVersion == "5.0")
{
version = Version_5_0;
return true;
}
else if (languageVersion == "3.0")
{
version = Version_3_0;
@ -49,7 +56,7 @@ namespace Microsoft.AspNetCore.Razor.Language
else if (languageVersion == "2.1")
{
version = Version_2_1;
return true;
return true;
}
else if (languageVersion == "2.0")
{
@ -84,7 +91,7 @@ namespace Microsoft.AspNetCore.Razor.Language
}
throw new ArgumentException(
Resources.FormatRazorLanguageVersion_InvalidVersion(languageVersion),
Resources.FormatRazorLanguageVersion_InvalidVersion(languageVersion),
nameof(languageVersion));
}
@ -131,7 +138,7 @@ namespace Microsoft.AspNetCore.Razor.Language
// We don't need to do anything special for our hash code since reference equality is what we're going for.
return base.GetHashCode();
}
public override string ToString() => $"{Major}.{Minor}";
private string DebuggerToString() => $"Razor '{Major}.{Minor}'";

View File

@ -92,6 +92,20 @@ namespace Microsoft.AspNetCore.Razor.Language
Assert.Same(RazorLanguageVersion.Version_3_0, version);
}
[Fact]
public void TryParse50()
{
// Arrange
var value = "5.0";
// Act
var result = RazorLanguageVersion.TryParse(value, out var version);
// Assert
Assert.True(result);
Assert.Same(RazorLanguageVersion.Version_5_0, version);
}
[Fact]
public void TryParseLatest()
{
@ -103,7 +117,7 @@ namespace Microsoft.AspNetCore.Razor.Language
// Assert
Assert.True(result);
Assert.Same(RazorLanguageVersion.Version_3_0, version);
Assert.Same(RazorLanguageVersion.Version_5_0, version);
}
[Fact]

View File

@ -625,28 +625,26 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
var result = await DotnetMSBuild(
"Build",
"/p:UseRazorBuildServer=false /p:RazorLangVersion=5.0",
"/p:UseRazorBuildServer=false /p:RazorLangVersion=99.0",
suppressBuildServer: true);
Assert.BuildFailed(result);
Assert.BuildOutputContainsLine(
result,
$"Invalid option 5.0 for Razor language version --version; must be Latest or a valid version in range 1.0 to 3.0.");
$"Invalid option 99.0 for Razor language version --version; must be Latest or a valid version in range 1.0 to 5.0.");
// Compilation failed without creating the views assembly
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.dll");
Assert.FileDoesNotExist(result, IntermediateOutputPath, "SimpleMvc.Views.dll");
}
[Fact(Skip = "Default C# version is 7.3 for netcoreapp3.1 and later https://github.com/dotnet/aspnetcore/issues/13930")]
[Fact]
[InitializeTestProject("SimpleMvc")]
public async Task Build_ImplicitCSharp8_NullableEnforcement_WarningsDuringBuild_NoBuildServer()
{
var result = await DotnetMSBuild(
"Build",
// Remove /p:LangVersion=Default once we've picked up a compiler that supports .NET 5.0.
// Tracked by https://github.com/dotnet/aspnetcore/issues/13304
"/p:Nullable=enable /p:LangVersion=Default",
"/p:Nullable=enable",
suppressBuildServer: true);
var indexFilePath = Path.Combine(RazorIntermediateOutputPath, "Views", "Home", "Index.cshtml.g.cs");

View File

@ -88,7 +88,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
}
[Fact]
[InitializeTestProject("SimpleMvc")]
[InitializeTestProject("SimpleMvc31")]
public async Task RazorSdk_ResolvesRazorLangVersionTo30ForNetCoreApp30Projects()
{
var result = await DotnetMSBuild("ResolveRazorConfiguration", "/t:_IntrospectResolvedConfiguration");
@ -98,6 +98,17 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.BuildOutputContainsLine(result, "ResolvedRazorConfiguration: MVC-3.0");
}
[Fact]
[InitializeTestProject("SimpleMvc")]
public async Task RazorSdk_ResolvesRazorLangVersionTo50ForNetCoreApp50Projects()
{
var result = await DotnetMSBuild("ResolveRazorConfiguration", "/t:_IntrospectResolvedConfiguration");
Assert.BuildPassed(result);
Assert.BuildOutputContainsLine(result, "RazorLangVersion: 5.0");
Assert.BuildOutputContainsLine(result, "ResolvedRazorConfiguration: MVC-3.0");
}
[Fact]
[InitializeTestProject("ComponentLibrary")]
public async Task RazorSdk_ResolvesRazorLangVersionFromValueSpecified()
@ -142,7 +153,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
var result = await DotnetMSBuild("ResolveRazorConfiguration", "/t:_IntrospectResolvedConfiguration");
Assert.BuildPassed(result);
Assert.BuildOutputContainsLine(result, "RazorLangVersion: 3.0");
Assert.BuildOutputContainsLine(result, "RazorLangVersion: 5.0");
Assert.BuildOutputContainsLine(result, "ResolvedRazorConfiguration: MVC-3.0");
}

View File

@ -100,12 +100,12 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
var result = await DotnetMSBuild(
"Build",
"/p:_RazorForceBuildServer=true /p:RazorLangVersion=5.0");
"/p:_RazorForceBuildServer=true /p:RazorLangVersion=99.0");
Assert.BuildFailed(result);
Assert.BuildOutputContainsLine(
result,
$"Invalid option 5.0 for Razor language version --version; must be Latest or a valid version in range 1.0 to 3.0.");
$"Invalid option 99.0 for Razor language version --version; must be Latest or a valid version in range 1.0 to 5.0.");
// Compilation failed without creating the views assembly
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc.dll");

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
Assert.FileContainsLine(
result,
razorAssemblyInfo,
"[assembly: Microsoft.AspNetCore.Razor.Hosting.RazorLanguageVersionAttribute(\"3.0\")]");
"[assembly: Microsoft.AspNetCore.Razor.Hosting.RazorLanguageVersionAttribute(\"5.0\")]");
Assert.FileContainsLine(
result,
razorAssemblyInfo,

View File

@ -1,6 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
{
public class MvcBuildIntegrationTest31 : MvcBuildIntegrationTestLegacy
@ -12,5 +16,33 @@ namespace Microsoft.AspNetCore.Razor.Design.IntegrationTests
public override string TestProjectName => "SimpleMvc31";
public override string TargetFramework => "netcoreapp3.1";
[Fact]
public async Task Build_WithGenerateRazorHostingAssemblyInfo_AddsConfigurationMetadata()
{
using var project = CreateTestProject();
var razorAssemblyInfo = Path.Combine(IntermediateOutputPath, "SimpleMvc31.RazorAssemblyInfo.cs");
var result = await DotnetMSBuild("Build", "/p:GenerateRazorHostingAssemblyInfo=true");
Assert.BuildPassed(result);
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc31.Views.dll");
Assert.FileExists(result, IntermediateOutputPath, "SimpleMvc31.Views.pdb");
Assert.FileExists(result, razorAssemblyInfo);
Assert.FileContainsLine(
result,
razorAssemblyInfo,
"[assembly: Microsoft.AspNetCore.Razor.Hosting.RazorLanguageVersionAttribute(\"3.0\")]");
Assert.FileContainsLine(
result,
razorAssemblyInfo,
"[assembly: Microsoft.AspNetCore.Razor.Hosting.RazorConfigurationNameAttribute(\"MVC-3.0\")]");
Assert.FileContainsLine(
result,
razorAssemblyInfo,
"[assembly: Microsoft.AspNetCore.Razor.Hosting.RazorExtensionAssemblyNameAttribute(\"MVC-3.0\", \"Microsoft.AspNetCore.Mvc.Razor.Extensions\")]");
}
}
}

View File

@ -69,6 +69,7 @@ Copyright (c) .NET Foundation. All rights reserved.
Determine the default Razor configuration
-->
<PropertyGroup Condition="'$(RazorDefaultConfiguration)'==''">
<!-- For 5.0, we're not introducing any new language features for MVC. We can continue using the 3.0 configuration \ extension for MVC support. -->
<RazorDefaultConfiguration Condition="'$(AddRazorSupportForMvc)'=='true'">MVC-3.0</RazorDefaultConfiguration>
<RazorDefaultConfiguration Condition="'$(RazorDefaultConfiguration)'==''">Default</RazorDefaultConfiguration>
</PropertyGroup>
@ -80,7 +81,7 @@ Copyright (c) .NET Foundation. All rights reserved.
the project's runtime.
-->
<RazorConfiguration Include="Default" />
<RazorConfiguration Include="MVC-3.0" >
<RazorConfiguration Include="MVC-3.0">
<Extensions>MVC-3.0;$(CustomRazorExtension)</Extensions>
</RazorConfiguration>
</ItemGroup>

View File

@ -45,6 +45,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<!--
Infer the RazorLangVersion if no value was specified. When adding support for newer target frameworks, list newer language versions first.
-->
<RazorLangVersion Condition="'$(RazorLangVersion)' == '' AND '$(_TargetingNET50OrLater)' == 'true'">5.0</RazorLangVersion>
<RazorLangVersion Condition="'$(RazorLangVersion)' == '' AND '$(_TargetingNETCoreApp30OrLater)' == 'true'">3.0</RazorLangVersion>
<!--

View File

@ -137,6 +137,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
public bool DisableStringReuse { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
public bool EnableAltSvc { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
public Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerLimits Limits { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } }
public System.Func<string, System.Text.Encoding> RequestHeaderEncodingSelector { get { throw null; } set { } }
public Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader Configure() { throw null; }
public Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader Configure(Microsoft.Extensions.Configuration.IConfiguration config) { throw null; }
public Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader Configure(Microsoft.Extensions.Configuration.IConfiguration config, bool reloadOnChange) { throw null; }

View File

@ -18,14 +18,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
private const string EndpointDefaultsKey = "EndpointDefaults";
private const string EndpointsKey = "Endpoints";
private const string UrlKey = "Url";
private const string Latin1RequestHeadersKey = "Latin1RequestHeaders";
private readonly IConfiguration _configuration;
private IDictionary<string, CertificateConfig> _certificates;
private EndpointDefaults _endpointDefaults;
private IEnumerable<EndpointConfig> _endpoints;
private bool? _latin1RequestHeaders;
public ConfigurationReader(IConfiguration configuration)
{
@ -35,7 +33,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
public IDictionary<string, CertificateConfig> Certificates => _certificates ??= ReadCertificates();
public EndpointDefaults EndpointDefaults => _endpointDefaults ??= ReadEndpointDefaults();
public IEnumerable<EndpointConfig> Endpoints => _endpoints ??= ReadEndpoints();
public bool Latin1RequestHeaders => _latin1RequestHeaders ??= _configuration.GetValue<bool>(Latin1RequestHeadersKey);
private IDictionary<string, CertificateConfig> ReadCertificates()
{

View File

@ -6270,6 +6270,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public unsafe void Append(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
{
ref byte nameStart = ref MemoryMarshal.GetReference(name);
var nameStr = string.Empty;
ref StringValues values = ref Unsafe.AsRef<StringValues>(null);
var flag = 0L;
@ -6281,6 +6282,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x20000000000L;
values = ref _headers._TE;
nameStr = HeaderNames.TE;
}
break;
case 3:
@ -6289,11 +6291,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x100000000000L;
values = ref _headers._DNT;
nameStr = HeaderNames.DNT;
}
else if ((firstTerm3 == 0x4956u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)2) & 0xdfu) == 0x41u))
{
flag = 0x100L;
values = ref _headers._Via;
nameStr = HeaderNames.Via;
}
break;
case 4:
@ -6302,16 +6306,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x80000000L;
values = ref _headers._Host;
nameStr = HeaderNames.Host;
}
else if ((firstTerm4 == 0x45544144u))
{
flag = 0x4L;
values = ref _headers._Date;
nameStr = HeaderNames.Date;
}
else if ((firstTerm4 == 0x4d4f5246u))
{
flag = 0x40000000L;
values = ref _headers._From;
nameStr = HeaderNames.From;
}
break;
case 5:
@ -6319,16 +6326,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x200000L;
values = ref _headers._Path;
nameStr = HeaderNames.Path;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfdfu) == 0x4f4c4c41u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)4) & 0xdfu) == 0x57u))
{
flag = 0x400L;
values = ref _headers._Allow;
nameStr = HeaderNames.Allow;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfdfu) == 0x474e4152u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)4) & 0xdfu) == 0x45u))
{
flag = 0x10000000000L;
values = ref _headers._Range;
nameStr = HeaderNames.Range;
}
break;
case 6:
@ -6337,26 +6347,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x800000L;
values = ref _headers._Accept;
nameStr = HeaderNames.Accept;
}
else if ((firstTerm6 == 0x4b4f4f43u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4549u))
{
flag = 0x10000000L;
values = ref _headers._Cookie;
nameStr = HeaderNames.Cookie;
}
else if ((firstTerm6 == 0x45505845u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x5443u))
{
flag = 0x20000000L;
values = ref _headers._Expect;
nameStr = HeaderNames.Expect;
}
else if ((firstTerm6 == 0x4749524fu) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4e49u))
{
flag = 0x4000000000000L;
values = ref _headers._Origin;
nameStr = HeaderNames.Origin;
}
else if ((firstTerm6 == 0x47415250u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x414du))
{
flag = 0x10L;
values = ref _headers._Pragma;
nameStr = HeaderNames.Pragma;
}
break;
case 7:
@ -6364,36 +6379,43 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x100000L;
values = ref _headers._Method;
nameStr = HeaderNames.Method;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfffu) == 0x4843533au) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4d45u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x45u))
{
flag = 0x400000L;
values = ref _headers._Scheme;
nameStr = HeaderNames.Scheme;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfdfu) == 0x49505845u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4552u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x53u))
{
flag = 0x20000L;
values = ref _headers._Expires;
nameStr = HeaderNames.Expires;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfdfu) == 0x45464552u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4552u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x52u))
{
flag = 0x8000000000L;
values = ref _headers._Referer;
nameStr = HeaderNames.Referer;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfdfu) == 0x49415254u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x454cu) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x52u))
{
flag = 0x20L;
values = ref _headers._Trailer;
nameStr = HeaderNames.Trailer;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfdfu) == 0x52475055u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4441u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x45u))
{
flag = 0x80L;
values = ref _headers._Upgrade;
nameStr = HeaderNames.Upgrade;
}
else if (((Unsafe.ReadUnaligned<uint>(ref nameStart) & 0xdfdfdfdfu) == 0x4e524157u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4e49u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x47u))
{
flag = 0x200L;
values = ref _headers._Warning;
nameStr = HeaderNames.Warning;
}
break;
case 8:
@ -6402,11 +6424,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x100000000L;
values = ref _headers._IfMatch;
nameStr = HeaderNames.IfMatch;
}
else if ((firstTerm8 == 0x45474e41522d4649uL))
{
flag = 0x800000000L;
values = ref _headers._IfRange;
nameStr = HeaderNames.IfRange;
}
break;
case 9:
@ -6414,6 +6438,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x40000000000L;
values = ref _headers._Translate;
nameStr = HeaderNames.Translate;
}
break;
case 10:
@ -6421,31 +6446,37 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x80000L;
values = ref _headers._Authority;
nameStr = HeaderNames.Authority;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x495443454e4e4f43uL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x4e4fu))
{
flag = 0x2L;
values = ref _headers._Connection;
nameStr = HeaderNames.Connection;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfffdfdfdfdfuL) == 0x4547412d52455355uL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x544eu))
{
flag = 0x80000000000L;
values = ref _headers._UserAgent;
nameStr = HeaderNames.UserAgent;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfffdfdfdfdfuL) == 0x494c412d5045454buL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x4556u))
{
flag = 0x8L;
values = ref _headers._KeepAlive;
nameStr = HeaderNames.KeepAlive;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d54534555514552uL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x4449u))
{
flag = 0x400000000000L;
values = ref _headers._RequestId;
nameStr = HeaderNames.RequestId;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x4154534543415254uL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x4554u))
{
flag = 0x2000000000000L;
values = ref _headers._TraceState;
nameStr = HeaderNames.TraceState;
}
break;
case 11:
@ -6453,11 +6484,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x8000L;
values = ref _headers._ContentMD5;
nameStr = HeaderNames.ContentMD5;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x5241504543415254uL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x4e45u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)10) & 0xdfu) == 0x54u))
{
flag = 0x1000000000000L;
values = ref _headers._TraceParent;
nameStr = HeaderNames.TraceParent;
}
break;
case 12:
@ -6465,11 +6498,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x800L;
values = ref _headers._ContentType;
nameStr = HeaderNames.ContentType;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfdfffdfdfdfuL) == 0x57524f462d58414duL) && ((Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x53445241u))
{
flag = 0x2000000000L;
values = ref _headers._MaxForwards;
nameStr = HeaderNames.MaxForwards;
}
break;
case 13:
@ -6477,26 +6512,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x8000000L;
values = ref _headers._Authorization;
nameStr = HeaderNames.Authorization;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfffdfdfdfdfdfuL) == 0x4f432d4548434143uL) && ((Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x4f52544eu) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x4cu))
{
flag = 0x1L;
values = ref _headers._CacheControl;
nameStr = HeaderNames.CacheControl;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d544e45544e4f43uL) && ((Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x474e4152u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x45u))
{
flag = 0x10000L;
values = ref _headers._ContentRange;
nameStr = HeaderNames.ContentRange;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xffdfdfdfdfffdfdfuL) == 0x2d454e4f4e2d4649uL) && ((Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x4354414du) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x48u))
{
flag = 0x400000000L;
values = ref _headers._IfNoneMatch;
nameStr = HeaderNames.IfNoneMatch;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfffdfdfdfdfuL) == 0x444f4d2d5453414cuL) && ((Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x45494649u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x44u))
{
flag = 0x40000L;
values = ref _headers._LastModified;
nameStr = HeaderNames.LastModified;
}
break;
case 14:
@ -6504,10 +6544,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x1000000L;
values = ref _headers._AcceptCharset;
nameStr = HeaderNames.AcceptCharset;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d544e45544e4f43uL) && ((Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x474e454cu) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(ushort)))) & 0xdfdfu) == 0x4854u))
{
AppendContentLength(value);
if (ReferenceEquals(EncodingSelector, KestrelServerOptions.DefaultRequestHeaderEncodingSelector))
{
AppendContentLength(value);
}
else
{
AppendContentLengthCustomEncoding(value, EncodingSelector(HeaderNames.ContentLength));
}
return;
}
break;
@ -6517,11 +6565,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x2000000L;
values = ref _headers._AcceptEncoding;
nameStr = HeaderNames.AcceptEncoding;
}
else if ((firstTerm15 == 0x4c2d545045434341uL) && ((Unsafe.ReadUnaligned<uint>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x55474e41u) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(ushort)))) & 0xdfdfu) == 0x4741u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)14) & 0xdfu) == 0x45u))
{
flag = 0x4000000L;
values = ref _headers._AcceptLanguage;
nameStr = HeaderNames.AcceptLanguage;
}
break;
case 16:
@ -6532,16 +6582,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x1000L;
values = ref _headers._ContentEncoding;
nameStr = HeaderNames.ContentEncoding;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x45474155474e414cuL))
{
flag = 0x2000L;
values = ref _headers._ContentLanguage;
nameStr = HeaderNames.ContentLanguage;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x4e4f495441434f4cuL))
{
flag = 0x4000L;
values = ref _headers._ContentLocation;
nameStr = HeaderNames.ContentLocation;
}
}
break;
@ -6550,11 +6603,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x200000000L;
values = ref _headers._IfModifiedSince;
nameStr = HeaderNames.IfModifiedSince;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x524546534e415254uL) && ((Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfffuL) == 0x4e49444f434e452duL) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)16) & 0xdfu) == 0x47u))
{
flag = 0x40L;
values = ref _headers._TransferEncoding;
nameStr = HeaderNames.TransferEncoding;
}
break;
case 19:
@ -6562,16 +6617,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x800000000000L;
values = ref _headers._CorrelationContext;
nameStr = HeaderNames.CorrelationContext;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfdfdfdfffdfdfuL) == 0x444f4d4e552d4649uL) && ((Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfffdfdfdfdfdfuL) == 0x49532d4445494649uL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(8 * sizeof(ushort)))) & 0xdfdfu) == 0x434eu) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)18) & 0xdfu) == 0x45u))
{
flag = 0x1000000000L;
values = ref _headers._IfUnmodifiedSince;
nameStr = HeaderNames.IfUnmodifiedSince;
}
else if (((Unsafe.ReadUnaligned<ulong>(ref nameStart) & 0xdfdfffdfdfdfdfdfuL) == 0x55412d59584f5250uL) && ((Unsafe.ReadUnaligned<ulong>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x54415a49524f4854uL) && ((Unsafe.ReadUnaligned<ushort>(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(8 * sizeof(ushort)))) & 0xdfdfu) == 0x4f49u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)18) & 0xdfu) == 0x4eu))
{
flag = 0x4000000000L;
values = ref _headers._ProxyAuthorization;
nameStr = HeaderNames.ProxyAuthorization;
}
break;
case 25:
@ -6579,6 +6637,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x200000000000L;
values = ref _headers._UpgradeInsecureRequests;
nameStr = HeaderNames.UpgradeInsecureRequests;
}
break;
case 29:
@ -6586,6 +6645,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x8000000000000L;
values = ref _headers._AccessControlRequestMethod;
nameStr = HeaderNames.AccessControlRequestMethod;
}
break;
case 30:
@ -6593,6 +6653,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
flag = 0x10000000000000L;
values = ref _headers._AccessControlRequestHeaders;
nameStr = HeaderNames.AccessControlRequestHeaders;
}
break;
}
@ -6622,7 +6683,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
// We didn't have a previous matching header value, or have already added a header, so get the string for this value.
var valueStr = value.GetRequestHeaderStringNonNullCharacters(UseLatin1);
var valueStr = value.GetRequestHeaderString(nameStr, EncodingSelector);
if ((_bits & flag) == 0)
{
// We didn't already have a header set, so add a new one.
@ -6640,8 +6701,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
// The header was not one of the "known" headers.
// Convert value to string first, because passing two spans causes 8 bytes stack zeroing in
// this method with rep stosd, which is slower than necessary.
var valueStr = value.GetRequestHeaderStringNonNullCharacters(UseLatin1);
AppendUnknownHeaders(name, valueStr);
nameStr = name.GetHeaderName();
var valueStr = value.GetRequestHeaderString(nameStr, EncodingSelector);
AppendUnknownHeaders(nameStr, valueStr);
}
}

View File

@ -369,7 +369,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
ConnectionIdFeature = ConnectionId;
HttpRequestHeaders.Reset();
HttpRequestHeaders.UseLatin1 = ServerOptions.Latin1RequestHeaders;
HttpRequestHeaders.EncodingSelector = ServerOptions.RequestHeaderEncodingSelector;
HttpRequestHeaders.ReuseHeaderValues = !ServerOptions.DisableStringReuse;
HttpResponseHeaders.Reset();
RequestHeaders = HttpRequestHeaders;
@ -532,7 +532,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
string key = name.GetHeaderName();
var valueStr = value.GetRequestHeaderStringNonNullCharacters(ServerOptions.Latin1RequestHeaders);
var valueStr = value.GetRequestHeaderString(key, HttpRequestHeaders.EncodingSelector);
RequestTrailers.Append(key, valueStr);
}

View File

@ -5,7 +5,9 @@ using System;
using System.Buffers.Text;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
@ -17,12 +19,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private long _previousBits = 0;
public bool ReuseHeaderValues { get; set; }
public bool UseLatin1 { get; set; }
public Func<string, Encoding> EncodingSelector { get; set; }
public HttpRequestHeaders(bool reuseHeaderValues = true, bool useLatin1 = false)
public HttpRequestHeaders(bool reuseHeaderValues = true, Func<string, Encoding> encodingSelector = null)
{
ReuseHeaderValues = reuseHeaderValues;
UseLatin1 = useLatin1;
EncodingSelector = encodingSelector ?? KestrelServerOptions.DefaultRequestHeaderEncodingSelector;
}
public void OnHeadersComplete()
@ -87,7 +89,30 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
parsed < 0 ||
consumed != value.Length)
{
KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value.GetRequestHeaderStringNonNullCharacters(UseLatin1));
KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value.GetRequestHeaderString(HeaderNames.ContentLength, EncodingSelector));
}
_contentLength = parsed;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void AppendContentLengthCustomEncoding(ReadOnlySpan<byte> value, Encoding customEncoding)
{
if (_contentLength.HasValue)
{
KestrelBadHttpRequestException.Throw(RequestRejectionReason.MultipleContentLengths);
}
// long.MaxValue = 9223372036854775807 (19 chars)
Span<char> decodedChars = stackalloc char[20];
var numChars = customEncoding.GetChars(value, decodedChars);
long parsed = -1;
if (numChars > 19 ||
!long.TryParse(decodedChars.Slice(0, numChars), NumberStyles.Integer, CultureInfo.InvariantCulture, out parsed) ||
parsed < 0)
{
KestrelBadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value.GetRequestHeaderString(HeaderNames.ContentLength, EncodingSelector));
}
_contentLength = parsed;
@ -108,11 +133,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
[MethodImpl(MethodImplOptions.NoInlining)]
private unsafe void AppendUnknownHeaders(ReadOnlySpan<byte> name, string valueString)
private unsafe void AppendUnknownHeaders(string name, string valueString)
{
string key = name.GetHeaderName();
Unknown.TryGetValue(key, out var existing);
Unknown[key] = AppendValue(existing, valueString);
Unknown.TryGetValue(name, out var existing);
Unknown[name] = AppendValue(existing, valueString);
}
public Enumerator GetEnumerator()

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
private const ulong _http10VersionLong = 3471766442030158920; // GetAsciiStringAsLong("HTTP/1.0"); const results in better codegen
private const ulong _http11VersionLong = 3543824036068086856; // GetAsciiStringAsLong("HTTP/1.1"); const results in better codegen
private static readonly UTF8EncodingSealed HeaderValueEncoding = new UTF8EncodingSealed();
private static readonly UTF8EncodingSealed DefaultRequestHeaderEncoding = new UTF8EncodingSealed();
private static readonly SpanAction<char, IntPtr> _getHeaderName = GetHeaderName;
private static readonly SpanAction<char, IntPtr> _getAsciiStringNonNullCharacters = GetAsciiStringNonNullCharacters;
@ -120,11 +120,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
}
}
public static string GetAsciiOrUTF8StringNonNullCharacters(this Span<byte> span)
=> GetAsciiOrUTF8StringNonNullCharacters((ReadOnlySpan<byte>)span);
public static string GetAsciiOrUTF8StringNonNullCharacters(this ReadOnlySpan<byte> span)
=> StringUtilities.GetAsciiOrUTF8StringNonNullCharacters(span, HeaderValueEncoding);
=> StringUtilities.GetAsciiOrUTF8StringNonNullCharacters(span, DefaultRequestHeaderEncoding);
private static unsafe void GetAsciiStringNonNullCharacters(Span<char> buffer, IntPtr state)
{
@ -139,8 +136,34 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
}
}
public static string GetRequestHeaderStringNonNullCharacters(this ReadOnlySpan<byte> span, bool useLatin1) =>
useLatin1 ? span.GetLatin1StringNonNullCharacters() : span.GetAsciiOrUTF8StringNonNullCharacters(HeaderValueEncoding);
public static string GetRequestHeaderString(this ReadOnlySpan<byte> span, string name, Func<string, Encoding> encodingSelector)
{
if (ReferenceEquals(KestrelServerOptions.DefaultRequestHeaderEncodingSelector, encodingSelector))
{
return span.GetAsciiOrUTF8StringNonNullCharacters(DefaultRequestHeaderEncoding);
}
var encoding = encodingSelector(name);
if (encoding is null)
{
return span.GetAsciiOrUTF8StringNonNullCharacters(DefaultRequestHeaderEncoding);
}
if (ReferenceEquals(encoding, Encoding.Latin1))
{
return span.GetLatin1StringNonNullCharacters();
}
try
{
return encoding.GetString(span);
}
catch (DecoderFallbackException ex)
{
throw new InvalidOperationException(ex.Message, ex);
}
}
public static string GetAsciiStringEscaped(this ReadOnlySpan<byte> span, int maxChars)
{

View File

@ -255,8 +255,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel
ConfigurationReader = new ConfigurationReader(Configuration);
Options.Latin1RequestHeaders = ConfigurationReader.Latin1RequestHeaders;
LoadDefaultCert(ConfigurationReader);
foreach (var endpoint in ConfigurationReader.Endpoints)

View File

@ -35,12 +35,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
private IDisposable _configChangedRegistration;
public KestrelServer(IOptions<KestrelServerOptions> options, IEnumerable<IConnectionListenerFactory> transportFactories, ILoggerFactory loggerFactory)
public KestrelServer(
IOptions<KestrelServerOptions> options,
IEnumerable<IConnectionListenerFactory> transportFactories,
ILoggerFactory loggerFactory)
: this(transportFactories, null, CreateServiceContext(options, loggerFactory))
{
}
public KestrelServer(IOptions<KestrelServerOptions> options, IEnumerable<IConnectionListenerFactory> transportFactories, IEnumerable<IMultiplexedConnectionListenerFactory> multiplexedFactories, ILoggerFactory loggerFactory)
public KestrelServer(
IOptions<KestrelServerOptions> options,
IEnumerable<IConnectionListenerFactory> transportFactories,
IEnumerable<IMultiplexedConnectionListenerFactory> multiplexedFactories,
ILoggerFactory loggerFactory)
: this(transportFactories, multiplexedFactories, CreateServiceContext(options, loggerFactory))
{
}
@ -52,7 +59,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
}
// For testing
internal KestrelServer(IEnumerable<IConnectionListenerFactory> transportFactories, IEnumerable<IMultiplexedConnectionListenerFactory> multiplexedFactories, ServiceContext serviceContext)
internal KestrelServer(
IEnumerable<IConnectionListenerFactory> transportFactories,
IEnumerable<IMultiplexedConnectionListenerFactory> multiplexedFactories,
ServiceContext serviceContext)
{
if (transportFactories == null)
{

View File

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Microsoft.AspNetCore.Certificates.Generation;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
@ -22,6 +23,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
/// </summary>
public class KestrelServerOptions
{
// internal to fast-path header decoding when RequestHeaderEncodingSelector is unchanged.
internal static readonly Func<string, Encoding> DefaultRequestHeaderEncodingSelector = _ => null;
private Func<string, Encoding> _requestHeaderEncodingSelector = DefaultRequestHeaderEncodingSelector;
// The following two lists configure the endpoints that Kestrel should listen to. If both lists are empty, the "urls" config setting (e.g. UseUrls) is used.
internal List<ListenOptions> CodeBackedListenOptions { get; } = new List<ListenOptions>();
internal List<ListenOptions> ConfigurationBackedListenOptions { get; } = new List<ListenOptions>();
@ -65,6 +71,24 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
/// </remarks>
public bool DisableStringReuse { get; set; } = false;
/// <summary>
/// Controls whether to return the AltSvcHeader from on an HTTP/2 or lower response for HTTP/3
/// </summary>
/// <remarks>
/// Defaults to false.
/// </remarks>
public bool EnableAltSvc { get; set; } = false;
/// <summary>
/// Gets or sets a callback that returns the <see cref="Encoding"/> to decode the value for the specified request header name,
/// or <see langword="null"/> to use the default <see cref="UTF8Encoding"/>.
/// </summary>
public Func<string, Encoding> RequestHeaderEncodingSelector
{
get => _requestHeaderEncodingSelector;
set => _requestHeaderEncodingSelector = value ?? throw new ArgumentNullException(nameof(value));
}
/// <summary>
/// Enables the Listen options callback to resolve and use services registered by the application during startup.
/// Typically initialized by UseKestrel()"/>.
@ -78,15 +102,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
/// <summary>
/// Provides a configuration source where endpoints will be loaded from on server start.
/// The default is null.
/// The default is <see langword="null"/>.
/// </summary>
public KestrelConfigurationLoader ConfigurationLoader { get; set; }
/// <summary>
/// Controls whether to return the AltSvcHeader from on an HTTP/2 or lower response for HTTP/3
/// </summary>
public bool EnableAltSvc { get; set; } = false;
/// <summary>
/// A default configuration action for all endpoints. Use for Listen, configuration, the default url, and URLs.
/// </summary>
@ -107,11 +126,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
/// </summary>
internal bool IsDevCertLoaded { get; set; }
/// <summary>
/// Treat request headers as Latin-1 or ISO/IEC 8859-1 instead of UTF-8.
/// </summary>
internal bool Latin1RequestHeaders { get; set; }
/// <summary>
/// Specifies a configuration Action to run for each newly created endpoint. Calling this again will replace
/// the prior action.
@ -159,7 +173,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
if (DefaultCertificate == null && !IsDevCertLoaded)
{
IsDevCertLoaded = true; // Only try once
var logger = ApplicationServices.GetRequiredService<ILogger<KestrelServer>>();
var logger = ApplicationServices!.GetRequiredService<ILogger<KestrelServer>>();
try
{
DefaultCertificate = CertificateManager.Instance.ListCertificates(StoreName.My, StoreLocation.CurrentUser, isValid: true)
@ -220,7 +234,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
/// </summary>
/// <param name="config">The configuration section for Kestrel.</param>
/// <param name="reloadOnChange">
/// If <see langword="true" />, Kestrel will dynamically update endpoint bindings when configuration changes.
/// If <see langword="true"/>, Kestrel will dynamically update endpoint bindings when configuration changes.
/// This will only reload endpoints defined in the "Endpoints" section of your <paramref name="config"/>. Endpoints defined in code will not be reloaded.
/// </param>
/// <returns>A <see cref="KestrelConfigurationLoader"/> for further endpoint configuration.</returns>

View File

@ -8,6 +8,7 @@ using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using Xunit;
using static CodeGenerator.KnownHeaders;
@ -307,11 +308,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var headers = new HttpRequestHeaders();
const string key = "\u00141\u00F3d\017c";
var encoding = Encoding.GetEncoding("iso-8859-1");
#pragma warning disable CS0618 // Type or member is obsolete
var exception = Assert.Throws<BadHttpRequestException>(
#pragma warning restore CS0618 // Type or member is obsolete
() => headers.Append(encoding.GetBytes(key), Encoding.ASCII.GetBytes("value")));
() => headers.Append(Encoding.Latin1.GetBytes(key), Encoding.ASCII.GetBytes("value")));
Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode);
}
@ -473,7 +473,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Assert.Throws<InvalidOperationException>(() =>
{
var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
var nextSpan = Encoding.GetEncoding("iso-8859-1").GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();
var nextSpan = Encoding.Latin1.GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();
Assert.False(nextSpan.SequenceEqual(Encoding.ASCII.GetBytes(headerValueUtf16Latin1CrossOver)));
@ -490,7 +490,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[MemberData(nameof(KnownRequestHeaders))]
public void Latin1ValuesAcceptedInLatin1ModeButNotReused(bool reuseValue, KnownHeader header)
{
var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue, useLatin1: true);
var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue, _ => Encoding.Latin1);
var headerValue = new char[127]; // 64 + 32 + 16 + 8 + 4 + 2 + 1
for (var i = 0; i < headerValue.Length; i++)
@ -517,19 +517,24 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
headerValueUtf16Latin1CrossOver = new string(headerValue.AsSpan().Slice(0, i + 1));
}
headers.Reset();
var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
var latinValueSpan = Encoding.GetEncoding("iso-8859-1").GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();
var latinValueSpan = Encoding.Latin1.GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();
Assert.False(latinValueSpan.SequenceEqual(Encoding.ASCII.GetBytes(headerValueUtf16Latin1CrossOver)));
headers.Reset();
headers.Append(headerName, latinValueSpan);
headers.OnHeadersComplete();
var parsedHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();
var parsedHeaderValue1 = ((IHeaderDictionary)headers)[header.Name].ToString();
Assert.Equal(headerValueUtf16Latin1CrossOver, parsedHeaderValue);
Assert.NotSame(headerValueUtf16Latin1CrossOver, parsedHeaderValue);
headers.Reset();
headers.Append(headerName, latinValueSpan);
headers.OnHeadersComplete();
var parsedHeaderValue2 = ((IHeaderDictionary)headers)[header.Name].ToString();
Assert.Equal(headerValueUtf16Latin1CrossOver, parsedHeaderValue1);
Assert.Equal(parsedHeaderValue1, parsedHeaderValue2);
Assert.NotSame(parsedHeaderValue1, parsedHeaderValue2);
}
// Reset back to Ascii
@ -541,7 +546,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[MemberData(nameof(KnownRequestHeaders))]
public void NullCharactersRejectedInUTF8AndLatin1Mode(bool useLatin1, KnownHeader header)
{
var headers = new HttpRequestHeaders(useLatin1: useLatin1);
var headers = new HttpRequestHeaders(encodingSelector: useLatin1 ? _ => Encoding.Latin1 : (Func<string, Encoding>)null);
var valueArray = new char[127]; // 64 + 32 + 16 + 8 + 4 + 2 + 1
for (var i = 0; i < valueArray.Length; i++)
@ -569,6 +574,53 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
}
}
[Fact]
public void CanSpecifyEncodingBasedOnHeaderName()
{
const string headerValue = "Hello \u03a0";
var acceptNameBytes = Encoding.ASCII.GetBytes(HeaderNames.Accept);
var cookieNameBytes = Encoding.ASCII.GetBytes(HeaderNames.Cookie);
var headerValueBytes = Encoding.UTF8.GetBytes(headerValue);
var headers = new HttpRequestHeaders(encodingSelector: headerName =>
{
// For known headers, the HeaderNames value is passed in.
if (ReferenceEquals(headerName, HeaderNames.Accept))
{
return Encoding.GetEncoding("ASCII", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback);
}
return Encoding.UTF8;
});
Assert.Throws<InvalidOperationException>(() => headers.Append(acceptNameBytes, headerValueBytes));
headers.Append(cookieNameBytes, headerValueBytes);
headers.OnHeadersComplete();
var parsedAcceptHeaderValue = ((IHeaderDictionary)headers)[HeaderNames.Accept].ToString();
var parsedCookieHeaderValue = ((IHeaderDictionary)headers)[HeaderNames.Cookie].ToString();
Assert.Empty(parsedAcceptHeaderValue);
Assert.Equal(headerValue, parsedCookieHeaderValue);
}
[Fact]
public void CanSpecifyEncodingForContentLength()
{
var contentLengthNameBytes = Encoding.ASCII.GetBytes(HeaderNames.ContentLength);
// Always 32 bits per code point, so not a superset of ASCII
var contentLengthValueBytes = Encoding.UTF32.GetBytes("1337");
var headers = new HttpRequestHeaders(encodingSelector: _ => Encoding.UTF32);
headers.Append(contentLengthNameBytes, contentLengthValueBytes);
headers.OnHeadersComplete();
Assert.Equal(1337, headers.ContentLength);
Assert.Throws<InvalidOperationException>(() =>
new HttpRequestHeaders().Append(contentLengthNameBytes, contentLengthValueBytes));
}
[Fact]
public void ValueReuseNeverWhenUnknownHeader()
{

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Net;
using Xunit;
@ -60,5 +61,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
// https://github.com/dotnet/aspnetcore/issues/21423
options.ListenLocalhost(5000);
}
[Fact]
public void SettingRequestHeaderEncodingSelecterThrowsArgumentNullException()
{
var options = new KestrelServerOptions();
var ex = Assert.Throws<ArgumentNullException>(() => options.RequestHeaderEncodingSelector = null);
Assert.Equal("value", ex.ParamName);
}
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Linq;
using System.Numerics;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[InlineData(new byte[] { 0xef, 0xbf, 0xbd })] // 3 bytes: Replacement character, highest UTF-8 character currently encoded in the UTF-8 code page
private void FullUTF8RangeSupported(byte[] encodedBytes)
{
var s = HttpUtilities.GetRequestHeaderStringNonNullCharacters(encodedBytes.AsSpan(), useLatin1: false);
var s = HttpUtilities.GetRequestHeaderString(encodedBytes.AsSpan(), HeaderNames.Accept, KestrelServerOptions.DefaultRequestHeaderEncodingSelector);
Assert.Equal(1, s.Length);
}
@ -35,7 +36,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var byteRange = Enumerable.Range(1, length).Select(x => (byte)x).ToArray();
Array.Copy(bytes, 0, byteRange, position, bytes.Length);
Assert.Throws<InvalidOperationException>(() => HttpUtilities.GetRequestHeaderStringNonNullCharacters(byteRange.AsSpan(), useLatin1: false));
Assert.Throws<InvalidOperationException>(() =>
HttpUtilities.GetRequestHeaderString(byteRange.AsSpan(), HeaderNames.Accept, KestrelServerOptions.DefaultRequestHeaderEncodingSelector));
}
}
}

View File

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Https;
@ -587,27 +588,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tests
Assert.True(ran1);
}
[Fact]
public void Latin1RequestHeadersReadFromConfig()
{
var options = CreateServerOptions();
var config = new ConfigurationBuilder().AddInMemoryCollection().Build();
Assert.False(options.Latin1RequestHeaders);
options.Configure(config).Load();
Assert.False(options.Latin1RequestHeaders);
options = CreateServerOptions();
config = new ConfigurationBuilder().AddInMemoryCollection(new[]
{
new KeyValuePair<string, string>("Latin1RequestHeaders", "true"),
}).Build();
Assert.False(options.Latin1RequestHeaders);
options.Configure(config).Load();
Assert.True(options.Latin1RequestHeaders);
}
[Fact]
public void Reload_IdentifiesEndpointsToStartAndStop()
{

View File

@ -2,7 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
@ -10,6 +12,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
private const int Iterations = 50;
private string _headerName;
private byte[] _asciiBytes;
private byte[] _utf8Bytes;
@ -27,24 +30,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
switch (Type)
{
case BenchmarkTypes.KeepAlive:
_headerName = HeaderNames.Connection;
// keep-alive
_asciiBytes = new byte[] { 0x6b, 0x65, 0x65, 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65 };
// kéép-álivé
_utf8Bytes = new byte[] { 0x6b, 0xc3, 0xa9, 0xc3, 0xa9, 0x70, 0x2d, 0xc3, 0xa1, 0x6c, 0x69, 0x76, 0xc3, 0xa9 };
break;
case BenchmarkTypes.Accept:
_headerName = HeaderNames.Accept;
// text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7
_asciiBytes = new byte[] { 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x39, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x39, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x38, 0x2c, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x37 };
// téxt/pláin,téxt/html;q=0.9,ápplicátion/xhtml+xml;q=0.9,ápplicátion/xml;q=0.8,*/*;q=0.7
_utf8Bytes = new byte[] { 0x74, 0xc3, 0xa9, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0xc3, 0xa1, 0x69, 0x6e, 0x2c, 0x74, 0xc3, 0xa9, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x39, 0x2c, 0xc3, 0xa1, 0x70, 0x70, 0x6c, 0x69, 0x63, 0xc3, 0xa1, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x39, 0x2c, 0xc3, 0xa1, 0x70, 0x70, 0x6c, 0x69, 0x63, 0xc3, 0xa1, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, 0x6d, 0x6c, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x38, 0x2c, 0x2a, 0x2f, 0x2a, 0x3b, 0x71, 0x3d, 0x30, 0x2e, 0x37 };
break;
case BenchmarkTypes.UserAgent:
_headerName = HeaderNames.UserAgent;
// Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
_asciiBytes = new byte[] { 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0x2f, 0x35, 0x2e, 0x30, 0x20, 0x28, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, 0x54, 0x20, 0x31, 0x30, 0x2e, 0x30, 0x3b, 0x20, 0x57, 0x4f, 0x57, 0x36, 0x34, 0x29, 0x20, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x57, 0x65, 0x62, 0x4b, 0x69, 0x74, 0x2f, 0x35, 0x33, 0x37, 0x2e, 0x33, 0x36, 0x20, 0x28, 0x4b, 0x48, 0x54, 0x4d, 0x4c, 0x2c, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x47, 0x65, 0x63, 0x6b, 0x6f, 0x29, 0x20, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x2f, 0x35, 0x34, 0x2e, 0x30, 0x2e, 0x32, 0x38, 0x34, 0x30, 0x2e, 0x39, 0x39, 0x20, 0x53, 0x61, 0x66, 0x61, 0x72, 0x69, 0x2f, 0x35, 0x33, 0x37, 0x2e, 0x33, 0x36 };
// Mozillá/5.0 (Windows NT 10.0; WOW64) áppléWébKit/537.36 (KHTML, liké Gécko) Chromé/54.0.2840.99 Sáfári/537.36
_utf8Bytes = new byte[] { 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0xc3, 0xa1, 0x2f, 0x35, 0x2e, 0x30, 0x20, 0x28, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x4e, 0x54, 0x20, 0x31, 0x30, 0x2e, 0x30, 0x3b, 0x20, 0x57, 0x4f, 0x57, 0x36, 0x34, 0x29, 0x20, 0xc3, 0xa1, 0x70, 0x70, 0x6c, 0xc3, 0xa9, 0x57, 0xc3, 0xa9, 0x62, 0x4b, 0x69, 0x74, 0x2f, 0x35, 0x33, 0x37, 0x2e, 0x33, 0x36, 0x20, 0x28, 0x4b, 0x48, 0x54, 0x4d, 0x4c, 0x2c, 0x20, 0x6c, 0x69, 0x6b, 0xc3, 0xa9, 0x20, 0x47, 0xc3, 0xa9, 0x63, 0x6b, 0x6f, 0x29, 0x20, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0xc3, 0xa9, 0x2f, 0x35, 0x34, 0x2e, 0x30, 0x2e, 0x32, 0x38, 0x34, 0x30, 0x2e, 0x39, 0x39, 0x20, 0x53, 0xc3, 0xa1, 0x66, 0xc3, 0xa1, 0x72, 0x69, 0x2f, 0x35, 0x33, 0x37, 0x2e, 0x33, 0x36 };
break;
case BenchmarkTypes.Cookie:
_headerName = HeaderNames.Cookie;
// prov=20629ccd-8b0f-e8ef-2935-cd26609fc0bc; __qca=P0-1591065732-1479167353442; _ga=GA1.2.1298898376.1479167354; _gat=1; sgt=id=9519gfde_3347_4762_8762_df51458c8ec2; acct=t=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric&s=why-is-%e0%a5%a7%e0%a5%a8%e0%a5%a9-numeric
_asciiBytes = new byte[] { 0x70, 0x72, 0x6f, 0x76, 0x3d, 0x32, 0x30, 0x36, 0x32, 0x39, 0x63, 0x63, 0x64, 0x2d, 0x38, 0x62, 0x30, 0x66, 0x2d, 0x65, 0x38, 0x65, 0x66, 0x2d, 0x32, 0x39, 0x33, 0x35, 0x2d, 0x63, 0x64, 0x32, 0x36, 0x36, 0x30, 0x39, 0x66, 0x63, 0x30, 0x62, 0x63, 0x3b, 0x20, 0x5f, 0x5f, 0x71, 0x63, 0x61, 0x3d, 0x50, 0x30, 0x2d, 0x31, 0x35, 0x39, 0x31, 0x30, 0x36, 0x35, 0x37, 0x33, 0x32, 0x2d, 0x31, 0x34, 0x37, 0x39, 0x31, 0x36, 0x37, 0x33, 0x35, 0x33, 0x34, 0x34, 0x32, 0x3b, 0x20, 0x5f, 0x67, 0x61, 0x3d, 0x47, 0x41, 0x31, 0x2e, 0x32, 0x2e, 0x31, 0x32, 0x39, 0x38, 0x38, 0x39, 0x38, 0x33, 0x37, 0x36, 0x2e, 0x31, 0x34, 0x37, 0x39, 0x31, 0x36, 0x37, 0x33, 0x35, 0x34, 0x3b, 0x20, 0x5f, 0x67, 0x61, 0x74, 0x3d, 0x31, 0x3b, 0x20, 0x73, 0x67, 0x74, 0x3d, 0x69, 0x64, 0x3d, 0x39, 0x35, 0x31, 0x39, 0x67, 0x66, 0x64, 0x65, 0x5f, 0x33, 0x33, 0x34, 0x37, 0x5f, 0x34, 0x37, 0x36, 0x32, 0x5f, 0x38, 0x37, 0x36, 0x32, 0x5f, 0x64, 0x66, 0x35, 0x31, 0x34, 0x35, 0x38, 0x63, 0x38, 0x65, 0x63, 0x32, 0x3b, 0x20, 0x61, 0x63, 0x63, 0x74, 0x3d, 0x74, 0x3d, 0x77, 0x68, 0x79, 0x2d, 0x69, 0x73, 0x2d, 0x25, 0x65, 0x30, 0x25, 0x61, 0x35, 0x25, 0x61, 0x37, 0x25, 0x65, 0x30, 0x25, 0x61, 0x35, 0x25, 0x61, 0x38, 0x25, 0x65, 0x30, 0x25, 0x61, 0x35, 0x25, 0x61, 0x39, 0x2d, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x26, 0x73, 0x3d, 0x77, 0x68, 0x79, 0x2d, 0x69, 0x73, 0x2d, 0x25, 0x65, 0x30, 0x25, 0x61, 0x35, 0x25, 0x61, 0x37, 0x25, 0x65, 0x30, 0x25, 0x61, 0x35, 0x25, 0x61, 0x38, 0x25, 0x65, 0x30, 0x25, 0x61, 0x35, 0x25, 0x61, 0x39, 0x2d, 0x6e, 0x75, 0x6d, 0x65, 0x72, 0x69, 0x63 };
// prov=20629ccd-8b0f-é8éf-2935-cd26609fc0bc; __qcá=P0-1591065732-1479167353442; _gá=Gá1.2.1298898376.1479167354; _gát=1; sgt=id=9519gfdé_3347_4762_8762_df51458c8éc2; ácct=t=why-is-%é0%á5%á7%é0%á5%á8%é0%á5%á9-numéric&s=why-is-%é0%á5%á7%é0%á5%á8%é0%á5%á9-numéric
@ -67,7 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
for (uint i = 0; i < Iterations; i++)
{
HttpUtilities.GetRequestHeaderStringNonNullCharacters(_utf8Bytes, useLatin1: false);
HttpUtilities.GetRequestHeaderString(_utf8Bytes, _headerName, KestrelServerOptions.DefaultRequestHeaderEncodingSelector);
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.Net.Http.Headers;
namespace CodeGenerator
{
@ -230,23 +231,39 @@ namespace CodeGenerator
firstTermVar = "";
}
string GenerateIfBody(KnownHeader header, string extraIndent = "")
{
if (header.Identifier == "ContentLength")
{
return $@"
{extraIndent}if (ReferenceEquals(EncodingSelector, KestrelServerOptions.DefaultRequestHeaderEncodingSelector))
{extraIndent}{{
{extraIndent} AppendContentLength(value);
{extraIndent}}}
{extraIndent}else
{extraIndent}{{
{extraIndent} AppendContentLengthCustomEncoding(value, EncodingSelector(HeaderNames.ContentLength));
{extraIndent}}}
{extraIndent}return;";
}
else
{
return $@"
{extraIndent}flag = {header.FlagBit()};
{extraIndent}values = ref _headers._{header.Identifier};
{extraIndent}nameStr = HeaderNames.{header.Identifier};";
}
}
var groups = values.GroupBy(header => header.EqualIgnoreCaseBytesFirstTerm());
return start + $@"{Each(groups, (byFirstTerm, i) => $@"{(byFirstTerm.Count() == 1 ? $@"{Each(byFirstTerm, header => $@"
{(i > 0 ? "else " : "")}if ({header.EqualIgnoreCaseBytes(firstTermVar)})
{{{(header.Identifier == "ContentLength" ? $@"
AppendContentLength(value);
return;" : $@"
flag = {header.FlagBit()};
values = ref _headers._{header.Identifier};")}
{{{GenerateIfBody(header)}
}}")}" : $@"
if ({byFirstTerm.Key.Replace(firstTermVarExpression, firstTermVar)})
{{{Each(byFirstTerm, (header, i) => $@"
{(i > 0 ? "else " : "")}if ({header.EqualIgnoreCaseBytesSecondTermOnwards()})
{{{(header.Identifier == "ContentLength" ? $@"
AppendContentLength(value);
return;" : $@"
flag = {header.FlagBit()};
values = ref _headers._{header.Identifier};")}
{{{GenerateIfBody(header, extraIndent: " ")}
}}")}
}}")}")}";
}
@ -986,6 +1003,7 @@ $@" private void Clear(long bitsToClear)
public unsafe void Append(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
{{
ref byte nameStart = ref MemoryMarshal.GetReference(name);
var nameStr = string.Empty;
ref StringValues values = ref Unsafe.AsRef<StringValues>(null);
var flag = 0L;
@ -1017,7 +1035,7 @@ $@" private void Clear(long bitsToClear)
}}
// We didn't have a previous matching header value, or have already added a header, so get the string for this value.
var valueStr = value.GetRequestHeaderStringNonNullCharacters(UseLatin1);
var valueStr = value.GetRequestHeaderString(nameStr, EncodingSelector);
if ((_bits & flag) == 0)
{{
// We didn't already have a header set, so add a new one.
@ -1035,8 +1053,9 @@ $@" private void Clear(long bitsToClear)
// The header was not one of the ""known"" headers.
// Convert value to string first, because passing two spans causes 8 bytes stack zeroing in
// this method with rep stosd, which is slower than necessary.
var valueStr = value.GetRequestHeaderStringNonNullCharacters(UseLatin1);
AppendUnknownHeaders(name, valueStr);
nameStr = name.GetHeaderName();
var valueStr = value.GetRequestHeaderString(nameStr, EncodingSelector);
AppendUnknownHeaders(nameStr, valueStr);
}}
}}" : "")}

View File

@ -4609,7 +4609,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[Fact]
public async Task HEADERS_Received_Latin1_AcceptedWhenLatin1OptionIsConfigured()
{
_serviceContext.ServerOptions.Latin1RequestHeaders = true;
_serviceContext.ServerOptions.RequestHeaderEncodingSelector = _ => Encoding.Latin1;
await InitializeConnectionAsync(context =>
{

View File

@ -406,7 +406,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
void IHttpHeadersHandler.OnHeader(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
{
_decodedHeaders[name.GetAsciiStringNonNullCharacters()] = value.GetRequestHeaderStringNonNullCharacters(useLatin1: _serviceContext.ServerOptions.Latin1RequestHeaders);
var nameStr = name.GetHeaderName();
_decodedHeaders[nameStr] = value.GetRequestHeaderString(nameStr, _serviceContext.ServerOptions.RequestHeaderEncodingSelector);
}
void IHttpHeadersHandler.OnHeadersComplete(bool endStream) { }

View File

@ -356,7 +356,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
public void OnStaticIndexedHeader(int index)
{
var knownHeader = H3StaticTable.GetHeaderFieldAt(index);
_decodedHeaders[((Span<byte>)knownHeader.Name).GetAsciiStringNonNullCharacters()] = HttpUtilities.GetAsciiOrUTF8StringNonNullCharacters(knownHeader.Value);
_decodedHeaders[((Span<byte>)knownHeader.Name).GetAsciiStringNonNullCharacters()] = HttpUtilities.GetAsciiOrUTF8StringNonNullCharacters((ReadOnlySpan<byte>)knownHeader.Value);
}
public void OnStaticIndexedHeader(int index, ReadOnlySpan<byte> value)

View File

@ -2000,7 +2000,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
{
var testContext = new TestServiceContext(LoggerFactory);
testContext.ServerOptions.Latin1RequestHeaders = true;
testContext.ServerOptions.RequestHeaderEncodingSelector = _ => Encoding.Latin1;
await using (var server = new TestServer(context =>
{
@ -2058,6 +2058,42 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
}
}
[Fact]
public async Task CustomRequestHeaderEncodingSelectorCanBeConfigured()
{
var testContext = new TestServiceContext(LoggerFactory);
testContext.ServerOptions.RequestHeaderEncodingSelector = _ => Encoding.UTF32;
await using (var server = new TestServer(context =>
{
Assert.Equal("£", context.Request.Headers["X-Test"]);
return Task.CompletedTask;
}, testContext))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"Host:",
"X-Test: ");
await connection.Stream.WriteAsync(Encoding.UTF32.GetBytes("£")).DefaultTimeout();
await connection.Send("",
"",
"");
await connection.Receive(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
}
public static TheoryData<string, string> HostHeaderData => HttpParsingData.HostHeaderData;
private class IntAsClass

View File

@ -15,6 +15,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
{
internal static class StringUtilities
{
private static readonly SpanAction<char, IntPtr> s_getAsciiOrUtf8StringNonNullCharacters = GetAsciiStringNonNullCharacters;
private static string GetAsciiOrUTF8StringNonNullCharacters(this Span<byte> span, Encoding defaultEncoding)
=> GetAsciiOrUTF8StringNonNullCharacters((ReadOnlySpan<byte>)span, defaultEncoding);
@ -52,15 +54,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
}
}
private static readonly SpanAction<char, IntPtr> s_getAsciiOrUtf8StringNonNullCharacters = GetAsciiOrUTF8StringNonNullCharacters;
private static unsafe void GetAsciiOrUTF8StringNonNullCharacters(Span<char> buffer, IntPtr state)
private static unsafe void GetAsciiStringNonNullCharacters(Span<char> buffer, IntPtr state)
{
fixed (char* output = &MemoryMarshal.GetReference(buffer))
{
// This version if AsciiUtilities returns null if there are any null (0 byte) characters
// in the string
if (!StringUtilities.TryGetAsciiString((byte*)state.ToPointer(), output, buffer.Length))
// This version if AsciiUtilities returns false if there are any null ('\0') or non-Ascii
// character (> 127) in the string.
if (!TryGetAsciiString((byte*)state.ToPointer(), output, buffer.Length))
{
// Mark resultString for UTF-8 encoding
output[0] = '\0';