Merge pull request #22902 from dotnet-maestro-bot/merge/release/3.1-to-master
[automated] Merge branch 'release/3.1' => 'master'
This commit is contained in:
commit
214df1c8ef
|
|
@ -10,6 +10,7 @@ using BasicTestApp.FormsTest;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
|
||||||
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
|
||||||
using Microsoft.AspNetCore.E2ETesting;
|
using Microsoft.AspNetCore.E2ETesting;
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
using OpenQA.Selenium;
|
using OpenQA.Selenium;
|
||||||
using OpenQA.Selenium.Support.UI;
|
using OpenQA.Selenium.Support.UI;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
@ -190,6 +191,7 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
[QuarantinedTest("https://github.com/dotnet/aspnetcore-internal/issues/3615")]
|
||||||
public void InputDateInteractsWithEditContext_NonNullableDateTime()
|
public void InputDateInteractsWithEditContext_NonNullableDateTime()
|
||||||
{
|
{
|
||||||
var appElement = MountTypicalValidationComponent();
|
var appElement = MountTypicalValidationComponent();
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,8 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="$(SharedSourceRoot)HttpSys\**\*.cs" />
|
<Compile Include="$(SharedSourceRoot)HttpSys\**\*.cs" />
|
||||||
<Compile Include="$(SharedSourceRoot)Buffers.MemoryPool\*.cs" LinkBase="MemoryPool" />
|
<Compile Include="$(SharedSourceRoot)Buffers.MemoryPool\*.cs" LinkBase="MemoryPool" />
|
||||||
</ItemGroup>
|
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\StringUtilities.cs" LinkBase="ServerInfrastructure\StringUtilities.cs" />
|
||||||
|
<Compile Include="$(SharedSourceRoot)TaskToApm.cs" />
|
||||||
<ItemGroup>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
<Compile Include="$(SharedSourceRoot)runtime\SR.cs" LinkBase="Shared\SR.cs" />
|
<Compile Include="$(SharedSourceRoot)runtime\SR.cs" LinkBase="Shared\SR.cs" />
|
||||||
<Compile Include="$(SharedSourceRoot)Http2cat\**\*.cs" LinkBase="Shared\Http2cat" />
|
<Compile Include="$(SharedSourceRoot)Http2cat\**\*.cs" LinkBase="Shared\Http2cat" />
|
||||||
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\**\*.cs" LinkBase="Shared\" />
|
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\**\*.cs" LinkBase="Shared\" />
|
||||||
<Compile Include="$(SharedSourceRoot)TaskToApm.cs" Link="Shared\TaskToApm.cs" />
|
<Compile Remove="$(SharedSourceRoot)ServerInfrastructure\StringUtilities.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,9 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
IntPtr pInProcessHandler,
|
IntPtr pInProcessHandler,
|
||||||
IISServerOptions options,
|
IISServerOptions options,
|
||||||
IISHttpServer server,
|
IISHttpServer server,
|
||||||
ILogger logger)
|
ILogger logger,
|
||||||
: base((HttpApiTypes.HTTP_REQUEST*)NativeMethods.HttpGetRawRequest(pInProcessHandler))
|
bool useLatin1)
|
||||||
|
: base((HttpApiTypes.HTTP_REQUEST*)NativeMethods.HttpGetRawRequest(pInProcessHandler), useLatin1: useLatin1)
|
||||||
{
|
{
|
||||||
_memoryPool = memoryPool;
|
_memoryPool = memoryPool;
|
||||||
_pInProcessHandler = pInProcessHandler;
|
_pInProcessHandler = pInProcessHandler;
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
|
@ -17,8 +18,8 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
{
|
{
|
||||||
private readonly IHttpApplication<TContext> _application;
|
private readonly IHttpApplication<TContext> _application;
|
||||||
|
|
||||||
public IISHttpContextOfT(MemoryPool<byte> memoryPool, IHttpApplication<TContext> application, IntPtr pInProcessHandler, IISServerOptions options, IISHttpServer server, ILogger logger)
|
public IISHttpContextOfT(MemoryPool<byte> memoryPool, IHttpApplication<TContext> application, IntPtr pInProcessHandler, IISServerOptions options, IISHttpServer server, ILogger logger, bool useLatin1)
|
||||||
: base(memoryPool, pInProcessHandler, options, server, logger)
|
: base(memoryPool, pInProcessHandler, options, server, logger, useLatin1)
|
||||||
{
|
{
|
||||||
_application = application;
|
_application = application;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -214,11 +214,14 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
|
|
||||||
private class IISContextFactory<T> : IISContextFactory
|
private class IISContextFactory<T> : IISContextFactory
|
||||||
{
|
{
|
||||||
|
private const string Latin1Suppport = "Microsoft.AspNetCore.Server.IIS.Latin1RequestHeaders";
|
||||||
|
|
||||||
private readonly IHttpApplication<T> _application;
|
private readonly IHttpApplication<T> _application;
|
||||||
private readonly MemoryPool<byte> _memoryPool;
|
private readonly MemoryPool<byte> _memoryPool;
|
||||||
private readonly IISServerOptions _options;
|
private readonly IISServerOptions _options;
|
||||||
private readonly IISHttpServer _server;
|
private readonly IISHttpServer _server;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
private readonly bool _useLatin1;
|
||||||
|
|
||||||
public IISContextFactory(MemoryPool<byte> memoryPool, IHttpApplication<T> application, IISServerOptions options, IISHttpServer server, ILogger logger)
|
public IISContextFactory(MemoryPool<byte> memoryPool, IHttpApplication<T> application, IISServerOptions options, IISHttpServer server, ILogger logger)
|
||||||
{
|
{
|
||||||
|
|
@ -227,11 +230,12 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
_options = options;
|
_options = options;
|
||||||
_server = server;
|
_server = server;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
AppContext.TryGetSwitch(Latin1Suppport, out _useLatin1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IISHttpContext CreateHttpContext(IntPtr pInProcessHandler)
|
public IISHttpContext CreateHttpContext(IntPtr pInProcessHandler)
|
||||||
{
|
{
|
||||||
return new IISHttpContextOfT<T>(_memoryPool, _application, pInProcessHandler, _options, _server, _logger);
|
return new IISHttpContextOfT<T>(_memoryPool, _application, pInProcessHandler, _options, _server, _logger, _useLatin1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@
|
||||||
<Compile Include="$(SharedSourceRoot)StackTrace\**\*.cs" LinkBase="Shared\" />
|
<Compile Include="$(SharedSourceRoot)StackTrace\**\*.cs" LinkBase="Shared\" />
|
||||||
<Compile Include="$(SharedSourceRoot)RazorViews\*.cs" LinkBase="Shared\" />
|
<Compile Include="$(SharedSourceRoot)RazorViews\*.cs" LinkBase="Shared\" />
|
||||||
<Compile Include="$(SharedSourceRoot)ErrorPage\*.cs" LinkBase="Shared\" />
|
<Compile Include="$(SharedSourceRoot)ErrorPage\*.cs" LinkBase="Shared\" />
|
||||||
<Compile Include="$(RepoRoot)src\Shared\TaskToApm.cs" Link="Shared\TaskToApm.cs" />
|
<Compile Include="$(SharedSourceRoot)TaskToApm.cs" Link="Shared\TaskToApm.cs" />
|
||||||
|
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\*.cs" LinkBase="Shared\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="ValidateNativeComponentsBuilt" AfterTargets="Build" >
|
<Target Name="ValidateNativeComponentsBuilt" AfterTargets="Build" >
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
// 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 System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting;
|
||||||
|
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.InProcess
|
||||||
|
{
|
||||||
|
[Collection(PublishedSitesCollection.Name)]
|
||||||
|
public class Latin1Tests : IISFunctionalTestBase
|
||||||
|
{
|
||||||
|
public Latin1Tests(PublishedSitesFixture fixture) : base(fixture)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
public async Task Latin1Works()
|
||||||
|
{
|
||||||
|
var deploymentParameters = Fixture.GetBaseDeploymentParameters();
|
||||||
|
deploymentParameters.TransformArguments((a, _) => $"{a} AddLatin1");
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
var client = new HttpClient(new LoggingHandler(new WinHttpHandler() { SendTimeout = TimeSpan.FromMinutes(3) }, deploymentResult.Logger));
|
||||||
|
|
||||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Get, $"{deploymentResult.ApplicationBaseUri}Latin1");
|
||||||
|
requestMessage.Headers.Add("foo", "£");
|
||||||
|
|
||||||
|
var result = await client.SendAsync(requestMessage);
|
||||||
|
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
public async Task Latin1ReplacedWithoutAppContextSwitch()
|
||||||
|
{
|
||||||
|
var deploymentParameters = Fixture.GetBaseDeploymentParameters();
|
||||||
|
deploymentParameters.TransformArguments((a, _) => $"{a}");
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
var client = new HttpClient(new LoggingHandler(new WinHttpHandler() { SendTimeout = TimeSpan.FromMinutes(3) }, deploymentResult.Logger));
|
||||||
|
|
||||||
|
var requestMessage = new HttpRequestMessage(HttpMethod.Get, $"{deploymentResult.ApplicationBaseUri}InvalidCharacter");
|
||||||
|
requestMessage.Headers.Add("foo", "£");
|
||||||
|
|
||||||
|
var result = await client.SendAsync(requestMessage);
|
||||||
|
Assert.Equal(HttpStatusCode.OK, result.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ConditionalFact]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
public async Task Latin1InvalidCharacters_HttpSysRejects()
|
||||||
|
{
|
||||||
|
var deploymentParameters = Fixture.GetBaseDeploymentParameters();
|
||||||
|
deploymentParameters.TransformArguments((a, _) => $"{a} AddLatin1");
|
||||||
|
|
||||||
|
var deploymentResult = await DeployAsync(deploymentParameters);
|
||||||
|
|
||||||
|
using (var connection = new TestConnection(deploymentResult.HttpClient.BaseAddress.Port))
|
||||||
|
{
|
||||||
|
await connection.Send(
|
||||||
|
"GET /ReadAndFlushEcho HTTP/1.1",
|
||||||
|
"Host: localhost",
|
||||||
|
"Connection: close",
|
||||||
|
"foo: £\0a",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
|
||||||
|
await connection.ReceiveStartsWith("HTTP/1.1 400 Bad Request");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
||||||
<Reference Include="Microsoft.Extensions.Logging" />
|
<Reference Include="Microsoft.Extensions.Logging" />
|
||||||
<Reference Include="System.Diagnostics.EventLog" />
|
<Reference Include="System.Diagnostics.EventLog" />
|
||||||
|
<Reference Include="System.Net.Http.WinHttpHandler" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
<Reference Include="Microsoft.Extensions.Logging" />
|
<Reference Include="Microsoft.Extensions.Logging" />
|
||||||
<Reference Include="System.Diagnostics.EventLog" />
|
<Reference Include="System.Diagnostics.EventLog" />
|
||||||
<Reference Include="System.Net.WebSockets.WebSocketProtocol" />
|
<Reference Include="System.Net.WebSockets.WebSocketProtocol" />
|
||||||
|
<Reference Include="System.Net.Http.WinHttpHandler" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
||||||
<Reference Include="Microsoft.Extensions.Logging" />
|
<Reference Include="Microsoft.Extensions.Logging" />
|
||||||
<Reference Include="System.Diagnostics.EventLog" />
|
<Reference Include="System.Diagnostics.EventLog" />
|
||||||
|
<Reference Include="System.Net.Http.WinHttpHandler" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<Import Project="../FunctionalTest.props" />
|
<Import Project="../FunctionalTest.props" />
|
||||||
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
<Reference Include="Microsoft.AspNetCore.Hosting" />
|
||||||
<Reference Include="Microsoft.Extensions.Logging" />
|
<Reference Include="Microsoft.Extensions.Logging" />
|
||||||
<Reference Include="System.Diagnostics.EventLog" />
|
<Reference Include="System.Diagnostics.EventLog" />
|
||||||
|
<Reference Include="System.Net.Http.WinHttpHandler" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -145,9 +145,9 @@ namespace TestSite
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#if !FORWARDCOMPAT
|
||||||
case "ThrowInStartupGenericHost":
|
case "ThrowInStartupGenericHost":
|
||||||
{
|
{
|
||||||
#if !FORWARDCOMPAT
|
|
||||||
var host = new HostBuilder().ConfigureWebHost((c) =>
|
var host = new HostBuilder().ConfigureWebHost((c) =>
|
||||||
{
|
{
|
||||||
c.ConfigureLogging((_, factory) =>
|
c.ConfigureLogging((_, factory) =>
|
||||||
|
|
@ -161,9 +161,26 @@ namespace TestSite
|
||||||
|
|
||||||
|
|
||||||
host.Build().Run();
|
host.Build().Run();
|
||||||
#endif
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
case "AddLatin1":
|
||||||
|
{
|
||||||
|
AppContext.SetSwitch("Microsoft.AspNetCore.Server.IIS.Latin1RequestHeaders", isEnabled: true);
|
||||||
|
var host = new HostBuilder().ConfigureWebHost((c) =>
|
||||||
|
{
|
||||||
|
c.ConfigureLogging((_, factory) =>
|
||||||
|
{
|
||||||
|
factory.AddConsole();
|
||||||
|
factory.AddFilter("Console", level => level >= LogLevel.Information);
|
||||||
|
})
|
||||||
|
.UseIIS()
|
||||||
|
.UseStartup<Startup>();
|
||||||
|
});
|
||||||
|
|
||||||
|
host.Build().Run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
return StartServer();
|
return StartServer();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1016,5 +1016,19 @@ namespace TestSite
|
||||||
|
|
||||||
await context.Response.WriteAsync(httpsPort.HasValue ? httpsPort.Value.ToString() : "NOVALUE");
|
await context.Response.WriteAsync(httpsPort.HasValue ? httpsPort.Value.ToString() : "NOVALUE");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task Latin1(HttpContext context)
|
||||||
|
{
|
||||||
|
var value = context.Request.Headers["foo"];
|
||||||
|
Assert.Equal("£", value);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task InvalidCharacter(HttpContext context)
|
||||||
|
{
|
||||||
|
var value = context.Request.Headers["foo"];
|
||||||
|
Assert.Equal("<22>", value);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,12 @@ 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);
|
||||||
|
|
||||||
private static unsafe void GetAsciiStringNonNullCharacters(Span<char> buffer, IntPtr state)
|
private static unsafe void GetAsciiStringNonNullCharacters(Span<char> buffer, IntPtr state)
|
||||||
{
|
{
|
||||||
fixed (char* output = &MemoryMarshal.GetReference(buffer))
|
fixed (char* output = &MemoryMarshal.GetReference(buffer))
|
||||||
|
|
@ -133,84 +139,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetAsciiOrUTF8StringNonNullCharacters(this Span<byte> span)
|
|
||||||
=> GetAsciiOrUTF8StringNonNullCharacters((ReadOnlySpan<byte>)span);
|
|
||||||
|
|
||||||
public static unsafe string GetAsciiOrUTF8StringNonNullCharacters(this ReadOnlySpan<byte> span)
|
|
||||||
{
|
|
||||||
if (span.IsEmpty)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed (byte* source = &MemoryMarshal.GetReference(span))
|
|
||||||
{
|
|
||||||
var resultString = string.Create(span.Length, new IntPtr(source), s_getAsciiOrUtf8StringNonNullCharacters);
|
|
||||||
|
|
||||||
// If resultString is marked, perform UTF-8 encoding
|
|
||||||
if (resultString[0] == '\0')
|
|
||||||
{
|
|
||||||
// null characters are considered invalid
|
|
||||||
if (span.IndexOf((byte)0) != -1)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
resultString = HeaderValueEncoding.GetString(span);
|
|
||||||
}
|
|
||||||
catch (DecoderFallbackException)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly SpanAction<char, IntPtr> s_getAsciiOrUtf8StringNonNullCharacters = GetAsciiOrUTF8StringNonNullCharacters;
|
|
||||||
|
|
||||||
private static unsafe void GetAsciiOrUTF8StringNonNullCharacters(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))
|
|
||||||
{
|
|
||||||
// Mark resultString for UTF-8 encoding
|
|
||||||
output[0] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe string GetLatin1StringNonNullCharacters(this ReadOnlySpan<byte> span)
|
|
||||||
{
|
|
||||||
if (span.IsEmpty)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultString = new string('\0', span.Length);
|
|
||||||
|
|
||||||
fixed (char* output = resultString)
|
|
||||||
fixed (byte* buffer = span)
|
|
||||||
{
|
|
||||||
// This returns false if there are any null (0 byte) characters in the string.
|
|
||||||
if (!StringUtilities.TryGetLatin1String(buffer, output, span.Length))
|
|
||||||
{
|
|
||||||
// null characters are considered invalid
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetRequestHeaderStringNonNullCharacters(this ReadOnlySpan<byte> span, bool useLatin1) =>
|
public static string GetRequestHeaderStringNonNullCharacters(this ReadOnlySpan<byte> span, bool useLatin1) =>
|
||||||
useLatin1 ? GetLatin1StringNonNullCharacters(span) : GetAsciiOrUTF8StringNonNullCharacters(span);
|
useLatin1 ? span.GetLatin1StringNonNullCharacters() : span.GetAsciiOrUTF8StringNonNullCharacters(HeaderValueEncoding);
|
||||||
|
|
||||||
public static string GetAsciiStringEscaped(this ReadOnlySpan<byte> span, int maxChars)
|
public static string GetAsciiStringEscaped(this ReadOnlySpan<byte> span, int maxChars)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>Core components of ASP.NET Core Kestrel cross-platform web server.</Description>
|
<Description>Core components of ASP.NET Core Kestrel cross-platform web server.</Description>
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<Compile Include="$(SharedSourceRoot)runtime\Http2\**\*.cs" Link="Shared\runtime\Http2\%(Filename)%(Extension)" />
|
<Compile Include="$(SharedSourceRoot)runtime\Http2\**\*.cs" Link="Shared\runtime\Http2\%(Filename)%(Extension)" />
|
||||||
<Compile Include="$(SharedSourceRoot)runtime\Http3\**\*.cs" Link="Shared\runtime\Http3\%(Filename)%(Extension)" />
|
<Compile Include="$(SharedSourceRoot)runtime\Http3\**\*.cs" Link="Shared\runtime\Http3\%(Filename)%(Extension)" />
|
||||||
<Compile Include="$(SharedSourceRoot)Hpack\**\*.cs" Link="Shared\Hpack\%(Filename)%(Extension)" />
|
<Compile Include="$(SharedSourceRoot)Hpack\**\*.cs" Link="Shared\Hpack\%(Filename)%(Extension)" />
|
||||||
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\**\*.cs" LinkBase="Shared\" />
|
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\**\*.cs" />
|
||||||
<Compile Include="$(RepoRoot)src\Shared\TaskToApm.cs" Link="Internal\TaskToApm.cs" />
|
<Compile Include="$(RepoRoot)src\Shared\TaskToApm.cs" Link="Internal\TaskToApm.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,24 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
{
|
{
|
||||||
internal static class HeaderEncoding
|
internal static class HeaderEncoding
|
||||||
{
|
{
|
||||||
// It should just be ASCII or ANSI, but they break badly with un-expected values. We use UTF-8 because it's the same for
|
private static readonly Encoding Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);
|
||||||
// ASCII, and because some old client would send UTF8 Host headers and expect UTF8 Location responses
|
|
||||||
// (e.g. IE and HttpWebRequest on intranets).
|
|
||||||
private static Encoding Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);
|
|
||||||
|
|
||||||
internal static unsafe string GetString(byte* pBytes, int byteCount)
|
internal static unsafe string GetString(byte* pBytes, int byteCount, bool useLatin1)
|
||||||
{
|
{
|
||||||
return Encoding.GetString(new ReadOnlySpan<byte>(pBytes, byteCount));
|
if (useLatin1)
|
||||||
|
{
|
||||||
|
return new ReadOnlySpan<byte>(pBytes, byteCount).GetLatin1StringNonNullCharacters();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ReadOnlySpan<byte>(pBytes, byteCount).GetAsciiOrUTF8StringNonNullCharacters(Encoding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte[] GetBytes(string myString)
|
internal static byte[] GetBytes(string myString)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
private const int AlignmentPadding = 8;
|
private const int AlignmentPadding = 8;
|
||||||
private const int DefaultBufferSize = 4096 - AlignmentPadding;
|
private const int DefaultBufferSize = 4096 - AlignmentPadding;
|
||||||
private IntPtr _originalBufferAddress;
|
private IntPtr _originalBufferAddress;
|
||||||
|
private bool _useLatin1;
|
||||||
private HttpApiTypes.HTTP_REQUEST* _nativeRequest;
|
private HttpApiTypes.HTTP_REQUEST* _nativeRequest;
|
||||||
private IMemoryOwner<byte> _backingBuffer;
|
private IMemoryOwner<byte> _backingBuffer;
|
||||||
private MemoryHandle _memoryHandle;
|
private MemoryHandle _memoryHandle;
|
||||||
|
|
@ -61,8 +62,9 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
// To be used by IIS Integration.
|
// To be used by IIS Integration.
|
||||||
internal NativeRequestContext(HttpApiTypes.HTTP_REQUEST* request)
|
internal NativeRequestContext(HttpApiTypes.HTTP_REQUEST* request, bool useLatin1)
|
||||||
{
|
{
|
||||||
|
_useLatin1 = useLatin1;
|
||||||
_nativeRequest = request;
|
_nativeRequest = request;
|
||||||
_bufferAlignment = 0;
|
_bufferAlignment = 0;
|
||||||
_permanentlyPinned = true;
|
_permanentlyPinned = true;
|
||||||
|
|
@ -155,7 +157,8 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
}
|
}
|
||||||
else if (verb == HttpApiTypes.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null)
|
else if (verb == HttpApiTypes.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null)
|
||||||
{
|
{
|
||||||
return HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength);
|
// Never use Latin1 for the VERB
|
||||||
|
return HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength, useLatin1: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -321,7 +324,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
// pRawValue will point to empty string ("\0")
|
// pRawValue will point to empty string ("\0")
|
||||||
if (pKnownHeader->RawValueLength > 0)
|
if (pKnownHeader->RawValueLength > 0)
|
||||||
{
|
{
|
||||||
value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength);
|
value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength, _useLatin1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
@ -359,11 +362,11 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
// pRawValue will be null.
|
// pRawValue will be null.
|
||||||
if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0)
|
if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0)
|
||||||
{
|
{
|
||||||
var headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength);
|
var headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength, _useLatin1);
|
||||||
string headerValue;
|
string headerValue;
|
||||||
if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0)
|
if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0)
|
||||||
{
|
{
|
||||||
headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength);
|
headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength, _useLatin1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,82 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
{
|
{
|
||||||
internal static class StringUtilities
|
internal static class StringUtilities
|
||||||
{
|
{
|
||||||
|
private static string GetAsciiOrUTF8StringNonNullCharacters(this Span<byte> span, Encoding defaultEncoding)
|
||||||
|
=> GetAsciiOrUTF8StringNonNullCharacters((ReadOnlySpan<byte>)span, defaultEncoding);
|
||||||
|
|
||||||
|
public static unsafe string GetAsciiOrUTF8StringNonNullCharacters(this ReadOnlySpan<byte> span, Encoding defaultEncoding)
|
||||||
|
{
|
||||||
|
if (span.IsEmpty)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed (byte* source = &MemoryMarshal.GetReference(span))
|
||||||
|
{
|
||||||
|
var resultString = string.Create(span.Length, new IntPtr(source), s_getAsciiOrUtf8StringNonNullCharacters);
|
||||||
|
|
||||||
|
// If resultString is marked, perform UTF-8 encoding
|
||||||
|
if (resultString[0] == '\0')
|
||||||
|
{
|
||||||
|
// null characters are considered invalid
|
||||||
|
if (span.IndexOf((byte)0) != -1)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
resultString = defaultEncoding.GetString(span);
|
||||||
|
}
|
||||||
|
catch (DecoderFallbackException)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly SpanAction<char, IntPtr> s_getAsciiOrUtf8StringNonNullCharacters = GetAsciiOrUTF8StringNonNullCharacters;
|
||||||
|
|
||||||
|
private static unsafe void GetAsciiOrUTF8StringNonNullCharacters(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))
|
||||||
|
{
|
||||||
|
// Mark resultString for UTF-8 encoding
|
||||||
|
output[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static unsafe string GetLatin1StringNonNullCharacters(this ReadOnlySpan<byte> span)
|
||||||
|
{
|
||||||
|
if (span.IsEmpty)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultString = new string('\0', span.Length);
|
||||||
|
|
||||||
|
fixed (char* output = resultString)
|
||||||
|
fixed (byte* buffer = span)
|
||||||
|
{
|
||||||
|
// This returns false if there are any null (0 byte) characters in the string.
|
||||||
|
if (!TryGetLatin1String(buffer, output, span.Length))
|
||||||
|
{
|
||||||
|
// null characters are considered invalid
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultString;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||||
public static unsafe bool TryGetAsciiString(byte* input, char* output, int count)
|
public static unsafe bool TryGetAsciiString(byte* input, char* output, int count)
|
||||||
{
|
{
|
||||||
|
|
@ -626,7 +702,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
|
||||||
{
|
{
|
||||||
// These must be explicity typed as ReadOnlySpan<byte>
|
// These must be explicity typed as ReadOnlySpan<byte>
|
||||||
// They then become a non-allocating mappings to the data section of the assembly.
|
// They then become a non-allocating mappings to the data section of the assembly.
|
||||||
// This uses C# compiler's ability to refer to static data directly. For more information see https://vcsjones.dev/2019/02/01/csharp-readonly-span-bytes-static
|
// This uses C# compiler's ability to refer to static data directly. For more information see https://vcsjones.dev/2019/02/01/csharp-readonly-span-bytes-static
|
||||||
ReadOnlySpan<byte> shuffleMaskData = new byte[16]
|
ReadOnlySpan<byte> shuffleMaskData = new byte[16]
|
||||||
{
|
{
|
||||||
0xF, 0xF, 3, 0xF,
|
0xF, 0xF, 3, 0xF,
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,13 @@
|
||||||
<Compile Include="$(SharedSourceRoot)PropertyActivator\*.cs" Link="Shared\PropertyActivator\%(Filename)%(Extension)"/>
|
<Compile Include="$(SharedSourceRoot)PropertyActivator\*.cs" Link="Shared\PropertyActivator\%(Filename)%(Extension)"/>
|
||||||
<Compile Include="$(SharedSourceRoot)PropertyHelper\*.cs" Link="Shared\PropertyHelper\%(Filename)%(Extension)"/>
|
<Compile Include="$(SharedSourceRoot)PropertyHelper\*.cs" Link="Shared\PropertyHelper\%(Filename)%(Extension)"/>
|
||||||
<Compile Include="$(SharedSourceRoot)SecurityHelper\**\*.cs" Link="Shared\SecurityHelper\%(Filename)%(Extension)"/>
|
<Compile Include="$(SharedSourceRoot)SecurityHelper\**\*.cs" Link="Shared\SecurityHelper\%(Filename)%(Extension)"/>
|
||||||
|
<Compile Include="$(SharedSourceRoot)ServerInfrastructure\**\*.cs" Link="Shared\ServerInfrastructure\%(Filename)%(Extension)"/>
|
||||||
<Compile Include="$(SharedSourceRoot)StackTrace\StackFrame\**\*.cs" Link="Shared\StackTrace\%(Filename)%(Extension)"/>
|
<Compile Include="$(SharedSourceRoot)StackTrace\StackFrame\**\*.cs" Link="Shared\StackTrace\%(Filename)%(Extension)"/>
|
||||||
<Compile Include="$(SharedSourceRoot)TypeNameHelper\StackFrame\**\*.cs" Link="Shared\TypeNameHelper\%(Filename)%(Extension)"/>
|
<Compile Include="$(SharedSourceRoot)TypeNameHelper\StackFrame\**\*.cs" Link="Shared\TypeNameHelper\%(Filename)%(Extension)"/>
|
||||||
<Compile Include="$(SharedSourceRoot)ValueStopwatch\**\*.cs" Link="Shared\ValueStopwatch\%(Filename)%(Extension)"/>
|
<Compile Include="$(SharedSourceRoot)ValueStopwatch\**\*.cs" Link="Shared\ValueStopwatch\%(Filename)%(Extension)"/>
|
||||||
<Compile Include="$(SharedSourceRoot)WebEncoders\**\*.cs" Link="Shared\WebEncoders\%(Filename)%(Extension)"/>
|
<Compile Include="$(SharedSourceRoot)WebEncoders\**\*.cs" Link="Shared\WebEncoders\%(Filename)%(Extension)"/>
|
||||||
<Compile Include="$(SharedSourceRoot)TypeNameHelper\*.cs" />
|
<Compile Include="$(SharedSourceRoot)TypeNameHelper\*.cs" />
|
||||||
|
<Compile Include="$(SharedSourceRoot)TaskToApm.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -56,6 +58,10 @@
|
||||||
<ManifestResourceName>System.Net.Http.SR</ManifestResourceName>
|
<ManifestResourceName>System.Net.Http.SR</ManifestResourceName>
|
||||||
<Generator></Generator>
|
<Generator></Generator>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="$(SharedSourceRoot)ServerInfrastructure\SharedStrings.resx" Link="Shared\SharedStrings.resx">
|
||||||
|
<ManifestResourceName>Microsoft.AspNetCore.Server.SharedStrings</ManifestResourceName>
|
||||||
|
<Generator></Generator>
|
||||||
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue