diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index d9677ceaa6..5e84dbbf0b 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -13,288 +13,288 @@
https://github.com/dotnet/blazor
cc449601d638ffaab58ae9487f0fd010bb178a12
-
+
https://github.com/dotnet/efcore
- dbb4ec7b7b94df404b32d592c658bf5df2dbba55
+ e4884bbaf11c3b75fe4021c49ac1da5dfa0f293a
-
+
https://github.com/dotnet/efcore
- dbb4ec7b7b94df404b32d592c658bf5df2dbba55
+ e4884bbaf11c3b75fe4021c49ac1da5dfa0f293a
-
+
https://github.com/dotnet/efcore
- dbb4ec7b7b94df404b32d592c658bf5df2dbba55
+ e4884bbaf11c3b75fe4021c49ac1da5dfa0f293a
-
+
https://github.com/dotnet/efcore
- dbb4ec7b7b94df404b32d592c658bf5df2dbba55
+ e4884bbaf11c3b75fe4021c49ac1da5dfa0f293a
-
+
https://github.com/dotnet/efcore
- dbb4ec7b7b94df404b32d592c658bf5df2dbba55
+ e4884bbaf11c3b75fe4021c49ac1da5dfa0f293a
-
+
https://github.com/dotnet/efcore
- dbb4ec7b7b94df404b32d592c658bf5df2dbba55
+ e4884bbaf11c3b75fe4021c49ac1da5dfa0f293a
-
+
https://github.com/dotnet/efcore
- dbb4ec7b7b94df404b32d592c658bf5df2dbba55
+ e4884bbaf11c3b75fe4021c49ac1da5dfa0f293a
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
-
+
https://github.com/dotnet/runtime
- 17df0b885273d0f4d22794fd830361d28bf3b663
+ d6b8109177d0ba0eeafc8f7570c63cbc0b2f2562
https://github.com/dotnet/arcade
diff --git a/eng/Versions.props b/eng/Versions.props
index 93ddb85ac8..e8977a9bad 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -9,7 +9,7 @@
5
0
0
- 7
+ 8
@@ -66,79 +66,79 @@
3.7.0-4.20319.6
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
- 5.0.0-preview.7.20323.4
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
+ 5.0.0-preview.7.20322.7
- 5.0.0-preview.7.20323.4
+ 5.0.0-preview.7.20322.7
3.2.0
- 5.0.0-preview.7.20322.5
- 5.0.0-preview.7.20322.5
- 5.0.0-preview.7.20322.5
- 5.0.0-preview.7.20322.5
- 5.0.0-preview.7.20322.5
- 5.0.0-preview.7.20322.5
- 5.0.0-preview.7.20322.5
+ 5.0.0-preview.8.20323.2
+ 5.0.0-preview.8.20323.2
+ 5.0.0-preview.8.20323.2
+ 5.0.0-preview.8.20323.2
+ 5.0.0-preview.8.20323.2
+ 5.0.0-preview.8.20323.2
+ 5.0.0-preview.8.20323.2
diff --git a/src/Components/Components/test/Rendering/RendererSynchronizationContextTest.cs b/src/Components/Components/test/Rendering/RendererSynchronizationContextTest.cs
index 77544baa77..b8908caff8 100644
--- a/src/Components/Components/test/Rendering/RendererSynchronizationContextTest.cs
+++ b/src/Components/Components/test/Rendering/RendererSynchronizationContextTest.cs
@@ -26,7 +26,7 @@ namespace Microsoft.AspNetCore.Components.Rendering
Thread capturedThread = null;
var e = new ManualResetEventSlim();
-
+
// Act
context.Post((_) =>
{
@@ -766,7 +766,6 @@ namespace Microsoft.AspNetCore.Components.Rendering
}
[Fact]
- [QuarantinedTest]
public async Task InvokeAsync_SyncWorkInAsyncTaskIsCompletedFirst()
{
// Simplified version of ServerComponentRenderingTest.CanDispatchAsyncWorkToSyncContext
diff --git a/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.csproj b/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.csproj
index 72e71d1c31..11eb4ad78e 100644
--- a/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.csproj
+++ b/src/Hosting/Hosting/ref/Microsoft.AspNetCore.Hosting.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj b/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj
index c78cef809d..c0e3e77284 100644
--- a/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj
+++ b/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj
@@ -1,4 +1,4 @@
-
+
ASP.NET Core hosting infrastructure and startup logic for web applications.
@@ -26,7 +26,7 @@
-
+
diff --git a/src/Identity/Specification.Tests/src/UserManagerSpecificationTests.cs b/src/Identity/Specification.Tests/src/UserManagerSpecificationTests.cs
index 4bc1a37559..f675482bfb 100644
--- a/src/Identity/Specification.Tests/src/UserManagerSpecificationTests.cs
+++ b/src/Identity/Specification.Tests/src/UserManagerSpecificationTests.cs
@@ -1450,7 +1450,6 @@ namespace Microsoft.AspNetCore.Identity.Test
///
/// Task
[Fact]
- [QuarantinedTest]
public async Task ChangePhoneNumberFailsWithWrongPhoneNumber()
{
var manager = CreateManager();
@@ -1471,7 +1470,6 @@ namespace Microsoft.AspNetCore.Identity.Test
///
/// Task
[Fact]
- [QuarantinedTest]
public async Task CanVerifyPhoneNumber()
{
var manager = CreateManager();
@@ -1519,7 +1517,6 @@ namespace Microsoft.AspNetCore.Identity.Test
///
/// Task
[Fact]
- [QuarantinedTest]
public async Task CanChangeEmailOnlyIfEmailSame()
{
var manager = CreateManager();
diff --git a/src/JSInterop/Microsoft.JSInterop.JS/src/package.json b/src/JSInterop/Microsoft.JSInterop.JS/src/package.json
index b73521f14f..40db20ee63 100644
--- a/src/JSInterop/Microsoft.JSInterop.JS/src/package.json
+++ b/src/JSInterop/Microsoft.JSInterop.JS/src/package.json
@@ -18,9 +18,9 @@
"author": "Microsoft",
"license": "Apache-2.0",
"bugs": {
- "url": "https://github.com/dotnet/extensions/issues"
+ "url": "https://github.com/dotnet/aspnetcore/issues"
},
- "homepage": "https://github.com/dotnet/extensions/tree/master/src/JSInterop#readme",
+ "homepage": "https://github.com/dotnet/aspnetcore/tree/master/src/JSInterop",
"files": [
"dist/**"
],
diff --git a/src/Middleware/SpaServices.Extensions/src/Proxying/SpaProxy.cs b/src/Middleware/SpaServices.Extensions/src/Proxying/SpaProxy.cs
index 04d7e697a1..20f516540d 100644
--- a/src/Middleware/SpaServices.Extensions/src/Proxying/SpaProxy.cs
+++ b/src/Middleware/SpaServices.Extensions/src/Proxying/SpaProxy.cs
@@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.SpaServices.Extensions.Proxy
// Don't forward User-Agent/Accept because of https://github.com/aspnet/JavaScriptServices/issues/1469
// Others just aren't applicable in proxy scenarios
- private static readonly string[] NotForwardedWebSocketHeaders = new[] { "Accept", "Connection", "Host", "User-Agent", "Upgrade", "Sec-WebSocket-Key", "Sec-WebSocket-Version" };
+ private static readonly string[] NotForwardedWebSocketHeaders = new[] { "Accept", "Connection", "Host", "User-Agent", "Upgrade", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol", "Sec-WebSocket-Version" };
public static HttpClient CreateHttpClientForProxy(TimeSpan requestTimeout)
{
@@ -209,6 +209,10 @@ namespace Microsoft.AspNetCore.SpaServices.Extensions.Proxy
using (var client = new ClientWebSocket())
{
+ foreach (var protocol in context.WebSockets.WebSocketRequestedProtocols)
+ {
+ client.Options.AddSubProtocol(protocol);
+ }
foreach (var headerEntry in context.Request.Headers)
{
if (!NotForwardedWebSocketHeaders.Contains(headerEntry.Key, StringComparer.OrdinalIgnoreCase))
diff --git a/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.csproj b/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.csproj
index ce0671621e..2ae7b2695e 100644
--- a/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.csproj
+++ b/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.csproj
@@ -2,6 +2,7 @@
$(DefaultNetCoreTargetFramework)
+ annotations
diff --git a/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.netcoreapp.cs b/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.netcoreapp.cs
index 84ca15ad39..267c99ef8a 100644
--- a/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.netcoreapp.cs
+++ b/src/Mvc/Mvc.Abstractions/ref/Microsoft.AspNetCore.Mvc.Abstractions.netcoreapp.cs
@@ -33,10 +33,10 @@ namespace Microsoft.AspNetCore.Mvc.Abstractions
public partial class ActionDescriptor
{
public ActionDescriptor() { }
- public System.Collections.Generic.IList ActionConstraints { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
- public Microsoft.AspNetCore.Mvc.Routing.AttributeRouteInfo AttributeRouteInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
+ public System.Collections.Generic.IList? ActionConstraints { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
+ public Microsoft.AspNetCore.Mvc.Routing.AttributeRouteInfo? AttributeRouteInfo { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
public System.Collections.Generic.IList BoundProperties { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
- public virtual string DisplayName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
+ public virtual string? DisplayName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } }
public System.Collections.Generic.IList
@@ -20,8 +21,4 @@ Microsoft.AspNetCore.Mvc.IActionResult
-
-
-
-
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingInfo.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingInfo.cs
index 38fbc894a9..b7379ae4e0 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingInfo.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingInfo.cs
@@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
public class BindingInfo
{
- private Type _binderType;
+ private Type? _binderType;
///
/// Creates a new .
@@ -44,12 +44,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Gets or sets the .
///
- public BindingSource BindingSource { get; set; }
+ public BindingSource? BindingSource { get; set; }
///
/// Gets or sets the binder model name.
///
- public string BinderModelName { get; set; }
+ public string? BinderModelName { get; set; }
///
/// Gets or sets the of the implementation used to bind the
@@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Also set if the specified implementation does not
/// use values from form data, route values or the query string.
///
- public Type BinderType
+ public Type? BinderType
{
get => _binderType;
set
@@ -80,13 +80,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Gets or sets the .
///
- public IPropertyFilterProvider PropertyFilterProvider { get; set; }
+ public IPropertyFilterProvider? PropertyFilterProvider { get; set; }
///
/// Gets or sets a predicate which determines whether or not the model should be bound based on state
/// from the current request.
///
- public Func RequestPredicate { get; set; }
+ public Func? RequestPredicate { get; set; }
///
/// Gets or sets the value which decides if empty bodies are treated as valid inputs.
@@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// A collection of attributes which are used to construct
///
/// A new instance of .
- public static BindingInfo GetBindingInfo(IEnumerable attributes)
+ public static BindingInfo? GetBindingInfo(IEnumerable attributes)
{
var bindingInfo = new BindingInfo();
var isBindingInfoPresent = false;
@@ -182,7 +182,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// A collection of attributes which are used to construct .
/// The .
/// A new instance of if any binding metadata was discovered; otherwise or .
- public static BindingInfo GetBindingInfo(IEnumerable attributes, ModelMetadata modelMetadata)
+ public static BindingInfo? GetBindingInfo(IEnumerable attributes, ModelMetadata modelMetadata)
{
if (attributes == null)
{
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingSource.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingSource.cs
index 97105efe3c..ea06036844 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingSource.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/BindingSource.cs
@@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// A metadata object representing a source of data for model binding.
///
[DebuggerDisplay("Source: {DisplayName}")]
- public class BindingSource : IEquatable
+ public class BindingSource : IEquatable
{
///
/// A for the request body.
@@ -210,13 +210,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
///
- public bool Equals(BindingSource other)
+ public bool Equals(BindingSource? other)
{
return string.Equals(other?.Id, Id, StringComparison.Ordinal);
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
return Equals(obj as BindingSource);
}
@@ -228,7 +228,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
///
- public static bool operator ==(BindingSource s1, BindingSource s2)
+ public static bool operator ==(BindingSource? s1, BindingSource? s2)
{
if (s1 is null)
{
@@ -239,7 +239,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
///
- public static bool operator !=(BindingSource s1, BindingSource s2)
+ public static bool operator !=(BindingSource? s1, BindingSource? s2)
{
return !(s1 == s2);
}
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/CompositeBindingSource.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/CompositeBindingSource.cs
index 886deb9951..99044400b5 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/CompositeBindingSource.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/CompositeBindingSource.cs
@@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
public override bool CanAcceptDataFrom(BindingSource bindingSource)
{
- if (bindingSource == null)
+ if (bindingSource is null)
{
throw new ArgumentNullException(nameof(bindingSource));
}
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/IBindingSourceMetadata.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/IBindingSourceMetadata.cs
index 4a1ed31275..8639ce826e 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/IBindingSourceMetadata.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/IBindingSourceMetadata.cs
@@ -15,6 +15,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// The is metadata which can be used to determine which data
/// sources are valid for model binding of a property or parameter.
///
- BindingSource BindingSource { get; }
+ BindingSource? BindingSource { get; }
}
}
\ No newline at end of file
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelBindingMessageProvider.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelBindingMessageProvider.cs
index c91bfe4cb0..7992450f37 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelBindingMessageProvider.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelBindingMessageProvider.cs
@@ -17,28 +17,28 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
///
/// Default is "A value for the '{0}' parameter or property was not provided.".
///
- public virtual Func MissingBindRequiredValueAccessor { get; }
+ public virtual Func MissingBindRequiredValueAccessor { get; } = default!;
///
/// Error message the model binding system adds when either the key or the value of a
/// is bound but not both.
///
/// Default is "A value is required.".
- public virtual Func MissingKeyOrValueAccessor { get; }
+ public virtual Func MissingKeyOrValueAccessor { get; } = default!;
///
/// Error message the model binding system adds when no value is provided for the request body,
/// but a value is required.
///
/// Default is "A non-empty request body is required.".
- public virtual Func MissingRequestBodyRequiredValueAccessor { get; }
+ public virtual Func MissingRequestBodyRequiredValueAccessor { get; } = default!;
///
/// Error message the model binding system adds when a null value is bound to a
/// non- property.
///
/// Default is "The value '{0}' is invalid.".
- public virtual Func ValueMustNotBeNullAccessor { get; }
+ public virtual Func ValueMustNotBeNullAccessor { get; } = default!;
///
/// Error message the model binding system adds when is of type
@@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// with a property.
///
/// Default is "The value '{0}' is not valid for {1}.".
- public virtual Func AttemptedValueIsInvalidAccessor { get; }
+ public virtual Func AttemptedValueIsInvalidAccessor { get; } = default!;
///
/// Error message the model binding system adds when is of type
@@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// with a collection element or action parameter.
///
/// Default is "The value '{0}' is not valid.".
- public virtual Func NonPropertyAttemptedValueIsInvalidAccessor { get; }
+ public virtual Func NonPropertyAttemptedValueIsInvalidAccessor { get; } = default!;
///
/// Error message the model binding system adds when is of type
@@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// with a property.
///
/// Default is "The supplied value is invalid for {0}.".
- public virtual Func UnknownValueIsInvalidAccessor { get; }
+ public virtual Func UnknownValueIsInvalidAccessor { get; } = default!;
///
/// Error message the model binding system adds when is of type
@@ -70,21 +70,21 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// with a collection element or action parameter.
///
/// Default is "The supplied value is invalid.".
- public virtual Func NonPropertyUnknownValueIsInvalidAccessor { get; }
+ public virtual Func NonPropertyUnknownValueIsInvalidAccessor { get; } = default!;
///
/// Fallback error message HTML and tag helpers display when a property is invalid but the
/// s have null s.
///
/// Default is "The value '{0}' is invalid.".
- public virtual Func ValueIsInvalidAccessor { get; }
+ public virtual Func ValueIsInvalidAccessor { get; } = default!;
///
/// Error message HTML and tag helpers add for client-side validation of numeric formats. Visible in the
/// browser if the field for a float (for example) property does not have a correctly-formatted value.
///
/// Default is "The field {0} must be a number.".
- public virtual Func ValueMustBeANumberAccessor { get; }
+ public virtual Func ValueMustBeANumberAccessor { get; } = default!;
///
/// Error message HTML and tag helpers add for client-side validation of numeric formats. Visible in the
@@ -92,6 +92,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// correctly-formatted value.
///
/// Default is "The field must be a number.".
- public virtual Func NonPropertyValueMustBeANumberAccessor { get; }
+ public virtual Func NonPropertyValueMustBeANumberAccessor { get; } = default!;
}
}
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelMetadataIdentity.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelMetadataIdentity.cs
index 9b1cf4fec2..5fff9bad3d 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelMetadataIdentity.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Metadata/ModelMetadataIdentity.cs
@@ -4,7 +4,6 @@
using System;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.Abstractions;
-using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
{
@@ -15,9 +14,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
{
private ModelMetadataIdentity(
Type modelType,
- string name = null,
- Type containerType = null,
- object fieldInfo = null)
+ string? name = null,
+ Type? containerType = null,
+ object? fieldInfo = null)
{
ModelType = modelType;
Name = name;
@@ -107,7 +106,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// The .
/// A .
public static ModelMetadataIdentity ForParameter(ParameterInfo parameter)
- => ForParameter(parameter, parameter?.ParameterType);
+ => ForParameter(parameter, parameter.ParameterType);
///
/// Creates a for the provided parameter with the specified
@@ -135,7 +134,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// Gets the defining the model property represented by the current
/// instance, or null if the current instance does not represent a property.
///
- public Type ContainerType { get; }
+ public Type? ContainerType { get; }
///
/// Gets the represented by the current instance.
@@ -168,21 +167,21 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
/// Gets the name of the current instance if it represents a parameter or property, or null if
/// the current instance represents a type.
///
- public string Name { get; }
+ public string? Name { get; }
- private object FieldInfo { get; }
+ private object? FieldInfo { get; }
///
/// Gets a descriptor for the parameter, or null if this instance
/// does not represent a parameter.
///
- public ParameterInfo ParameterInfo => FieldInfo as ParameterInfo;
+ public ParameterInfo? ParameterInfo => FieldInfo as ParameterInfo;
///
/// Gets a descriptor for the property, or null if this instance
/// does not represent a property.
///
- public PropertyInfo PropertyInfo => FieldInfo as PropertyInfo;
+ public PropertyInfo? PropertyInfo => FieldInfo as PropertyInfo;
///
public bool Equals(ModelMetadataIdentity other)
@@ -196,7 +195,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
var other = obj as ModelMetadataIdentity?;
return other.HasValue && Equals(other.Value);
@@ -205,13 +204,13 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata
///
public override int GetHashCode()
{
- var hash = new HashCodeCombiner();
+ var hash = new HashCode();
hash.Add(ContainerType);
hash.Add(ModelType);
hash.Add(Name, StringComparer.Ordinal);
hash.Add(ParameterInfo);
hash.Add(PropertyInfo);
- return hash;
+ return hash.ToHashCode();
}
}
}
\ No newline at end of file
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBinderProviderContext.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBinderProviderContext.cs
index 6228923e70..c35c8c4814 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBinderProviderContext.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBinderProviderContext.cs
@@ -48,6 +48,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Gets the .
///
- public virtual IServiceProvider Services { get; }
+ public virtual IServiceProvider Services { get; } = default!;
}
}
\ No newline at end of file
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingContext.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingContext.cs
index 915ea38085..3dfd4790f3 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingContext.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingContext.cs
@@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Gets the associated with this context.
///
- public virtual HttpContext HttpContext => ActionContext?.HttpContext;
+ public virtual HttpContext HttpContext => ActionContext?.HttpContext!;
///
/// Gets or sets an indication that the current binder is handling the top-level object.
@@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Gets or sets the name of the top-level model. This is not reset to when value
/// providers have no match for that model.
///
- public string OriginalModelName { get; protected set; }
+ public string OriginalModelName { get; protected set; } = default!;
///
/// Gets or sets the used to capture values
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingResult.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingResult.cs
index 2bfc3dd5fd..3ab9c0ba4f 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingResult.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelBindingResult.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
-using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
@@ -19,7 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
{
return new ModelBindingResult(model: null, isModelSet: false);
}
-
+
///
/// Creates a representing a successful model binding operation.
///
@@ -27,10 +26,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// A representing a successful model bind.
public static ModelBindingResult Success(object model)
{
- return new ModelBindingResult( model, isModelSet: true);
+ return new ModelBindingResult(model, isModelSet: true);
}
- private ModelBindingResult(object model, bool isModelSet)
+ private ModelBindingResult(object? model, bool isModelSet)
{
Model = model;
IsModelSet = isModelSet;
@@ -39,7 +38,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Gets the model associated with this context.
///
- public object Model { get; }
+ public object? Model { get; }
///
///
@@ -53,7 +52,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public bool IsModelSet { get; }
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
var other = obj as ModelBindingResult?;
if (other == null)
@@ -69,11 +68,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
public override int GetHashCode()
{
- var hashCodeCombiner = HashCodeCombiner.Start();
+ var hashCodeCombiner = new HashCode();
hashCodeCombiner.Add(IsModelSet);
hashCodeCombiner.Add(Model);
- return hashCodeCombiner.CombinedHash;
+ return hashCodeCombiner.ToHashCode();
}
///
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelError.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelError.cs
index 0473e20d5d..d30796e081 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelError.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelError.cs
@@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// The .
/// The error message.
- public ModelError(Exception exception, string errorMessage)
+ public ModelError(Exception exception, string? errorMessage)
: this(errorMessage)
{
Exception = exception ?? throw new ArgumentNullException(nameof(exception));
@@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Initializes a new instance of with the specified .
///
/// The error message.
- public ModelError(string errorMessage)
+ public ModelError(string? errorMessage)
{
ErrorMessage = errorMessage ?? string.Empty;
}
@@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Gets the associated with this instance.
///
- public Exception Exception { get; }
+ public Exception? Exception { get; }
///
/// Gets the error message associated with this instance.
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelMetadata.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelMetadata.cs
index 4733f732cd..f04cac166e 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelMetadata.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelMetadata.cs
@@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// A metadata representation of a model type, property or parameter.
///
[DebuggerDisplay("{DebuggerToString(),nq}")]
- public abstract class ModelMetadata : IEquatable, IModelMetadataProvider
+ public abstract class ModelMetadata : IEquatable, IModelMetadataProvider
{
///
/// The default value of .
@@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Gets the type containing the property if this metadata is for a property; otherwise.
///
- public Type ContainerType => Identity.ContainerType;
+ public Type? ContainerType => Identity.ContainerType;
///
/// Gets the metadata for if this metadata is for a property;
@@ -68,17 +68,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Gets the name of the parameter or property if this metadata is for a parameter or property;
/// otherwise i.e. if this is the metadata for a type.
///
- public string Name => Identity.Name;
+ public string? Name => Identity.Name;
///
/// Gets the name of the parameter if this metadata is for a parameter; otherwise.
///
- public string ParameterName => MetadataKind == ModelMetadataKind.Parameter ? Identity.Name : null;
+ public string? ParameterName => MetadataKind == ModelMetadataKind.Parameter ? Identity.Name : null;
///
/// Gets the name of the property if this metadata is for a property; otherwise.
///
- public string PropertyName => MetadataKind == ModelMetadataKind.Property ? Identity.Name : null;
+ public string? PropertyName => MetadataKind == ModelMetadataKind.Property ? Identity.Name : null;
///
/// Gets the key for the current instance.
@@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// implements but not . null otherwise i.e. when
/// is false.
///
- public abstract ModelMetadata ElementMetadata { get; }
+ public abstract ModelMetadata? ElementMetadata { get; }
///
/// Gets the ordered and grouped display names and values of all values in
@@ -318,7 +318,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// validated. If null, properties with this are validated.
///
/// Defaults to null.
- public virtual IPropertyValidationFilter PropertyValidationFilter => null;
+ public virtual IPropertyValidationFilter? PropertyValidationFilter => null;
///
/// Gets a value that indicates whether properties or elements of the model should be validated.
@@ -343,7 +343,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// Gets the for elements of if that
/// implements .
///
- public Type ElementType { get; private set; }
+ public Type? ElementType { get; private set; }
///
/// Gets a value indicating whether is a complex type.
@@ -389,7 +389,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// Identical to unless is true.
///
- public Type UnderlyingOrModelType { get; private set; }
+ public Type UnderlyingOrModelType { get; private set; } = default!;
///
/// Gets a property getter delegate to get the property value from a model object.
@@ -415,7 +415,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
///
- public bool Equals(ModelMetadata other)
+ public bool Equals(ModelMetadata? other)
{
if (object.ReferenceEquals(this, other))
{
@@ -433,7 +433,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
return Equals(obj as ModelMetadata);
}
@@ -469,14 +469,14 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
else if (ModelType.IsArray)
{
IsEnumerableType = true;
- ElementType = ModelType.GetElementType();
+ ElementType = ModelType.GetElementType()!;
}
else
{
IsEnumerableType = true;
var enumerableType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(IEnumerable<>));
- ElementType = enumerableType?.GenericTypeArguments[0];
+ ElementType = enumerableType?.GenericTypeArguments[0]!;
if (ElementType == null)
{
@@ -497,7 +497,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
case ModelMetadataKind.Parameter:
return $"ModelMetadata (Parameter: '{ParameterName}' Type: '{ModelType.Name}')";
case ModelMetadataKind.Property:
- return $"ModelMetadata (Property: '{ContainerType.Name}.{PropertyName}' Type: '{ModelType.Name}')";
+ return $"ModelMetadata (Property: '{ContainerType!.Name}.{PropertyName}' Type: '{ModelType.Name}')";
case ModelMetadataKind.Type:
return $"ModelMetadata (Type: '{ModelType.Name}')";
default:
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelPropertyCollection.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelPropertyCollection.cs
index 733da709ba..797e1b9514 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelPropertyCollection.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelPropertyCollection.cs
@@ -32,7 +32,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// The instance for the property specified by , or
/// null if no match can be found.
///
- public ModelMetadata this[string propertyName]
+ public ModelMetadata? this[string propertyName]
{
get
{
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs
index 48b8b9ee3a..24581e0510 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateDictionary.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Formatters;
@@ -166,7 +167,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
TryGetValue(key, out var entry);
- return entry;
+ return entry!;
}
}
@@ -305,15 +306,15 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
else if (entry == null)
{
- errorMessage = messageProvider.UnknownValueIsInvalidAccessor(name);
+ errorMessage = messageProvider.UnknownValueIsInvalidAccessor(name!);
}
else if (name == null)
{
- errorMessage = messageProvider.NonPropertyAttemptedValueIsInvalidAccessor(entry.AttemptedValue);
+ errorMessage = messageProvider.NonPropertyAttemptedValueIsInvalidAccessor(entry.AttemptedValue!);
}
else
{
- errorMessage = messageProvider.AttemptedValueIsInvalidAccessor(entry.AttemptedValue, name);
+ errorMessage = messageProvider.AttemptedValueIsInvalidAccessor(entry.AttemptedValue!, name);
}
return TryAddModelError(key, errorMessage);
@@ -511,7 +512,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
/// The values of in a comma-separated .
///
- public void SetModelValue(string key, object rawValue, string attemptedValue)
+ public void SetModelValue(string key, object? rawValue, string attemptedValue)
{
if (key == null)
{
@@ -540,7 +541,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
// Avoid creating a new array for rawValue if there's only one value.
- object rawValue;
+ object? rawValue;
if (valueProviderResult == ValueProviderResult.None)
{
rawValue = null;
@@ -573,10 +574,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
}
- private ModelStateNode GetNode(string key)
+ private ModelStateNode? GetNode(string key)
{
- Debug.Assert(key != null);
-
var current = _root;
if (key.Length > 0)
{
@@ -661,7 +660,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return new StringSegment(key, keyStart, index - keyStart);
}
- private static ModelValidationState? GetValidity(ModelStateNode node)
+ private static ModelValidationState? GetValidity(ModelStateNode? node)
{
if (node == null)
{
@@ -774,7 +773,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
///
- public bool TryGetValue(string key, out ModelStateEntry value)
+ public bool TryGetValue(string key, [NotNullWhen(true)] out ModelStateEntry? value)
{
if (key == null)
{
@@ -893,11 +892,11 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
SubKey = subKey;
}
- public List ChildNodes { get; set; }
+ public List? ChildNodes { get; set; }
- public override IReadOnlyList Children => ChildNodes;
+ public override IReadOnlyList? Children => ChildNodes;
- public string Key { get; set; }
+ public string Key { get; set; } = default!;
public StringSegment SubKey { get; }
@@ -931,9 +930,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ModelStateNode GetNode(StringSegment subKey)
+ public ModelStateNode? GetNode(StringSegment subKey)
{
- ModelStateNode modelStateNode = null;
+ ModelStateNode? modelStateNode = null;
if (subKey.Length == 0)
{
modelStateNode = this;
@@ -981,7 +980,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
return modelStateNode;
}
- public override ModelStateEntry GetModelStateForProperty(string propertyName)
+ public override ModelStateEntry? GetModelStateForProperty(string propertyName)
=> GetNode(new StringSegment(propertyName));
private int BinarySearch(StringSegment searchKey)
@@ -1068,9 +1067,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
public struct Enumerator : IEnumerator>
{
- private readonly ModelStateNode _rootNode;
+ private readonly ModelStateNode? _rootNode;
private ModelStateNode _modelStateNode;
- private List _nodes;
+ private List? _nodes;
private int _index;
private bool _visitedRoot;
@@ -1093,7 +1092,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
_index = -1;
_rootNode = dictionary.GetNode(prefix);
- _modelStateNode = null;
+ _modelStateNode = default!;
_nodes = null;
_visitedRoot = false;
}
@@ -1141,7 +1140,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
while (_nodes.Count > 0)
{
var node = _nodes[0];
- if (_index == node.ChildNodes.Count - 1)
+ if (_index == node.ChildNodes!.Count - 1)
{
// We've exhausted the current sublist.
_nodes.RemoveAt(0);
@@ -1173,9 +1172,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public void Reset()
{
_index = -1;
- _nodes.Clear();
+ _nodes?.Clear();
_visitedRoot = false;
- _modelStateNode = null;
+ _modelStateNode = default!;
}
}
@@ -1218,7 +1217,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public KeyEnumerator(ModelStateDictionary dictionary, string prefix)
{
_prefixEnumerator = new Enumerator(dictionary, prefix);
- Current = null;
+ Current = default!;
}
///
@@ -1240,7 +1239,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
else
{
- Current = null;
+ Current = default!;
}
return result;
@@ -1250,7 +1249,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public void Reset()
{
_prefixEnumerator.Reset();
- Current = null;
+ Current = default!;
}
}
@@ -1293,7 +1292,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public ValueEnumerator(ModelStateDictionary dictionary, string prefix)
{
_prefixEnumerator = new Enumerator(dictionary, prefix);
- Current = null;
+ Current = default!;
}
///
@@ -1315,7 +1314,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
}
else
{
- Current = null;
+ Current = default!;
}
return result;
@@ -1325,7 +1324,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public void Reset()
{
_prefixEnumerator.Reset();
- Current = null;
+ Current = default!;
}
}
}
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateEntry.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateEntry.cs
index b73eab4f77..d56ef3dd81 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateEntry.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ModelStateEntry.cs
@@ -10,17 +10,17 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
///
public abstract class ModelStateEntry
{
- private ModelErrorCollection _errors;
+ private ModelErrorCollection? _errors;
///
/// Gets the raw value from the request associated with this entry.
///
- public object RawValue { get; set; }
+ public object? RawValue { get; set; }
///
/// Gets the set of values contained in , joined into a comma-separated string.
///
- public string AttemptedValue { get; set; }
+ public string? AttemptedValue { get; set; }
///
/// Gets the for this entry.
@@ -61,7 +61,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// This method returns any existing entry, even those with with value
/// .
///
- public abstract ModelStateEntry GetModelStateForProperty(string propertyName);
+ public abstract ModelStateEntry? GetModelStateForProperty(string propertyName);
///
/// Gets the values for sub-properties.
@@ -70,6 +70,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// This property returns all existing entries, even those with with value
/// .
///
- public abstract IReadOnlyList Children { get; }
+ public abstract IReadOnlyList? Children { get; }
}
}
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ClientValidatorItem.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ClientValidatorItem.cs
index e346509701..be8552d8df 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ClientValidatorItem.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ClientValidatorItem.cs
@@ -30,12 +30,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
///
/// Gets the metadata associated with the .
///
- public object ValidatorMetadata { get; }
+ public object ValidatorMetadata { get; } = default!;
///
/// Gets or sets the .
///
- public IClientModelValidator Validator { get; set; }
+ public IClientModelValidator Validator { get; set; } = default!;
///
/// Gets or sets a value indicating whether or not can be reused across requests.
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationEntry.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationEntry.cs
index a873273ca7..cedca096a4 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationEntry.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationEntry.cs
@@ -10,8 +10,8 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
///
public struct ValidationEntry
{
- private object _model;
- private Func _modelAccessor;
+ private object? _model;
+ private Func? _modelAccessor;
///
/// Creates a new .
@@ -79,7 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
///
/// The model object.
///
- public object Model
+ public object? Model
{
get
{
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateDictionary.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateDictionary.cs
index 11179b014d..2d40811d5c 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateDictionary.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateDictionary.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Runtime.CompilerServices;
+using System.Diagnostics.CodeAnalysis;
namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
{
@@ -25,8 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
_inner = new Dictionary(ReferenceEqualityComparer.Instance);
}
- ///
- public ValidationStateEntry this[object key]
+ public ValidationStateEntry? this[object key]
{
get
{
@@ -36,10 +35,19 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
set
{
- _inner[key] = value;
+ _inner[key] = value!;
}
}
+ ///
+ ValidationStateEntry IDictionary.this[object key]
+ {
+ get => this[key]!;
+ set => this[key] = value;
+ }
+
+ ValidationStateEntry IReadOnlyDictionary.this[object key] => this[key]!;
+
///
public int Count => _inner.Count;
@@ -115,7 +123,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
}
///
- public bool TryGetValue(object key, out ValidationStateEntry value)
+ public bool TryGetValue(object key, [MaybeNullWhen(false)] out ValidationStateEntry value)
{
return _inner.TryGetValue(key, out value);
}
@@ -125,30 +133,5 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
{
return ((IDictionary)_inner).GetEnumerator();
}
-
- private class ReferenceEqualityComparer : IEqualityComparer
- {
- private static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;
-
- public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer();
-
- public new bool Equals(object x, object y)
- {
- return Object.ReferenceEquals(x, y);
- }
-
- public int GetHashCode(object obj)
- {
- // RuntimeHelpers.GetHashCode sometimes crashes the runtime on Mono 4.0.4
- // See: https://github.com/aspnet/External/issues/45
- // The workaround here is to just not hash anything, and fall back to an equality check.
- if (IsMono)
- {
- return 0;
- }
-
- return RuntimeHelpers.GetHashCode(obj);
- }
- }
}
}
\ No newline at end of file
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateEntry.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateEntry.cs
index 970cbb8dfa..ee94334283 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateEntry.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidationStateEntry.cs
@@ -12,12 +12,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
///
/// Gets or sets the model prefix associated with the entry.
///
- public string Key { get; set; }
+ public string Key { get; set; } = default!;
///
/// Gets or sets the associated with the entry.
///
- public ModelMetadata Metadata { get; set; }
+ public ModelMetadata Metadata { get; set; } = default!;
///
/// Gets or sets a value indicating whether the associated model object should be validated.
@@ -28,6 +28,6 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
/// Gets or sets an for enumerating child entries of the associated
/// model object.
///
- public IValidationStrategy Strategy { get; set; }
+ public IValidationStrategy Strategy { get; set; } = default!;
}
}
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidatorItem.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidatorItem.cs
index 8592eeca71..ca8b291e1a 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidatorItem.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/Validation/ValidatorItem.cs
@@ -30,12 +30,12 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation
///
/// Gets the metadata associated with the .
///
- public object ValidatorMetadata { get; }
+ public object ValidatorMetadata { get; } = default!;
///
/// Gets or sets the .
///
- public IModelValidator Validator { get; set; }
+ public IModelValidator Validator { get; set; } = default!;
///
/// Gets or sets a value indicating whether or not can be reused across requests.
diff --git a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ValueProviderResult.cs b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ValueProviderResult.cs
index 3a0b8e1fa8..e5b088b4a0 100644
--- a/src/Mvc/Mvc.Abstractions/src/ModelBinding/ValueProviderResult.cs
+++ b/src/Mvc/Mvc.Abstractions/src/ModelBinding/ValueProviderResult.cs
@@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
/// to get a single value for processing regardless of whether a single or multiple values were provided
/// in the request.
///
- public string FirstValue
+ public string? FirstValue
{
get
{
@@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public int Length => Values.Count;
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
var other = obj as ValueProviderResult?;
return other.HasValue && Equals(other.Value);
diff --git a/src/Mvc/Mvc.Abstractions/src/Routing/AttributeRouteInfo.cs b/src/Mvc/Mvc.Abstractions/src/Routing/AttributeRouteInfo.cs
index f2fc4ea77b..1aae06847e 100644
--- a/src/Mvc/Mvc.Abstractions/src/Routing/AttributeRouteInfo.cs
+++ b/src/Mvc/Mvc.Abstractions/src/Routing/AttributeRouteInfo.cs
@@ -13,7 +13,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The route template. May be null if the action has no attribute routes.
///
- public string Template { get; set; }
+ public string? Template { get; set; }
///
/// Gets the order of the route associated with a given action. This property determines
@@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
/// to generate a link by referring to the route by name instead of attempting to match a
/// route by provided route data.
///
- public string Name { get; set; }
+ public string Name { get; set; } = default!;
///
/// Gets or sets a value that determines if the route entry associated with this model participates in link generation.
diff --git a/src/Mvc/Mvc.Abstractions/src/Routing/UrlActionContext.cs b/src/Mvc/Mvc.Abstractions/src/Routing/UrlActionContext.cs
index 8260b6b680..09853000d0 100644
--- a/src/Mvc/Mvc.Abstractions/src/Routing/UrlActionContext.cs
+++ b/src/Mvc/Mvc.Abstractions/src/Routing/UrlActionContext.cs
@@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The name of the action method that uses to generate URLs.
///
- public string Action
+ public string? Action
{
get;
set;
@@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The name of the controller that uses to generate URLs.
///
- public string Controller
+ public string? Controller
{
get;
set;
@@ -30,7 +30,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
/// The object that contains the route values that
/// uses to generate URLs.
///
- public object Values
+ public object? Values
{
get;
set;
@@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
/// The protocol for the URLs that generates,
/// such as "http" or "https"
///
- public string Protocol
+ public string? Protocol
{
get;
set;
@@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The host name for the URLs that generates.
///
- public string Host
+ public string? Host
{
get;
set;
@@ -58,7 +58,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The fragment for the URLs that generates.
///
- public string Fragment
+ public string? Fragment
{
get;
set;
diff --git a/src/Mvc/Mvc.Abstractions/src/Routing/UrlRouteContext.cs b/src/Mvc/Mvc.Abstractions/src/Routing/UrlRouteContext.cs
index 706414f958..d713e69212 100644
--- a/src/Mvc/Mvc.Abstractions/src/Routing/UrlRouteContext.cs
+++ b/src/Mvc/Mvc.Abstractions/src/Routing/UrlRouteContext.cs
@@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The name of the route that uses to generate URLs.
///
- public string RouteName
+ public string? RouteName
{
get;
set;
@@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
/// The object that contains the route values that
/// uses to generate URLs.
///
- public object Values
+ public object? Values
{
get;
set;
@@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
/// The protocol for the URLs that generates,
/// such as "http" or "https"
///
- public string Protocol
+ public string? Protocol
{
get;
set;
@@ -40,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The host name for the URLs that generates.
///
- public string Host
+ public string? Host
{
get;
set;
@@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
///
/// The fragment for the URLs that generates.
///
- public string Fragment
+ public string? Fragment
{
get;
set;
diff --git a/src/Mvc/Mvc.ApiExplorer/src/DefaultApiDescriptionProvider.cs b/src/Mvc/Mvc.ApiExplorer/src/DefaultApiDescriptionProvider.cs
index bbc1f86ef1..73a4c35492 100644
--- a/src/Mvc/Mvc.ApiExplorer/src/DefaultApiDescriptionProvider.cs
+++ b/src/Mvc/Mvc.ApiExplorer/src/DefaultApiDescriptionProvider.cs
@@ -662,11 +662,11 @@ namespace Microsoft.AspNetCore.Mvc.ApiExplorer
public int GetHashCode(PropertyKey obj)
{
- var hashCodeCombiner = HashCodeCombiner.Start();
+ var hashCodeCombiner = new HashCode();
hashCodeCombiner.Add(obj.ContainerType);
hashCodeCombiner.Add(obj.PropertyName);
hashCodeCombiner.Add(obj.Source);
- return hashCodeCombiner.CombinedHash;
+ return hashCodeCombiner.ToHashCode();
}
}
}
diff --git a/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs b/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs
index 1cd59d4c72..180fb433e1 100644
--- a/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs
+++ b/src/Mvc/Mvc.Core/src/ModelBinding/ModelBinderFactory.cs
@@ -319,10 +319,10 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
public override int GetHashCode()
{
- var hash = new HashCodeCombiner();
+ var hash = new HashCode();
hash.Add(_metadata);
hash.Add(RuntimeHelpers.GetHashCode(_token));
- return hash;
+ return hash.ToHashCode();
}
public override string ToString()
diff --git a/src/Mvc/Mvc.Core/src/Routing/AttributeRoute.cs b/src/Mvc/Mvc.Core/src/Routing/AttributeRoute.cs
index da0fc4594e..185e77fb58 100644
--- a/src/Mvc/Mvc.Core/src/Routing/AttributeRoute.cs
+++ b/src/Mvc/Mvc.Core/src/Routing/AttributeRoute.cs
@@ -291,10 +291,10 @@ namespace Microsoft.AspNetCore.Mvc.Routing
return 0;
}
- var hash = new HashCodeCombiner();
+ var hash = new HashCode();
hash.Add(obj.Order);
hash.Add(obj.RouteTemplate.TemplateText, StringComparer.OrdinalIgnoreCase);
- return hash;
+ return hash.ToHashCode();
}
}
diff --git a/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs b/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs
index 9acc858e5a..49eb5c05a9 100644
--- a/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs
+++ b/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs
@@ -123,14 +123,14 @@ namespace Microsoft.AspNetCore.Mvc.Razor
public override int GetHashCode()
{
- var hashCodeCombiner = HashCodeCombiner.Start();
+ var hashCodeCombiner = new HashCode();
hashCodeCombiner.Add(PageType);
if (ProvidedModelType != null)
{
hashCodeCombiner.Add(ProvidedModelType);
}
- return hashCodeCombiner.CombinedHash;
+ return hashCodeCombiner.ToHashCode();
}
}
}
diff --git a/src/Mvc/Mvc.Razor/src/ViewLocationCacheKey.cs b/src/Mvc/Mvc.Razor/src/ViewLocationCacheKey.cs
index 2640110dd5..140b55ba9e 100644
--- a/src/Mvc/Mvc.Razor/src/ViewLocationCacheKey.cs
+++ b/src/Mvc/Mvc.Razor/src/ViewLocationCacheKey.cs
@@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
///
public override int GetHashCode()
{
- var hashCodeCombiner = HashCodeCombiner.Start();
+ var hashCodeCombiner = new HashCode();
hashCodeCombiner.Add(IsMainPage ? 1 : 0);
hashCodeCombiner.Add(ViewName, StringComparer.Ordinal);
hashCodeCombiner.Add(ControllerName, StringComparer.Ordinal);
@@ -151,7 +151,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
}
}
- return hashCodeCombiner;
+ return hashCodeCombiner.ToHashCode();
}
}
}
diff --git a/src/Mvc/Mvc.TagHelpers/src/Cache/CacheTagKey.cs b/src/Mvc/Mvc.TagHelpers/src/Cache/CacheTagKey.cs
index bf327f30ca..f527f8f55f 100644
--- a/src/Mvc/Mvc.TagHelpers/src/Cache/CacheTagKey.cs
+++ b/src/Mvc/Mvc.TagHelpers/src/Cache/CacheTagKey.cs
@@ -247,7 +247,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
return _hashcode.Value;
}
- var hashCodeCombiner = new HashCodeCombiner();
+ var hashCodeCombiner = new HashCode();
hashCodeCombiner.Add(Key, StringComparer.Ordinal);
hashCodeCombiner.Add(_expiresAfter);
@@ -258,12 +258,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
hashCodeCombiner.Add(_requestCulture);
hashCodeCombiner.Add(_requestUICulture);
- CombineCollectionHashCode(hashCodeCombiner, VaryByCookieName, _cookies);
- CombineCollectionHashCode(hashCodeCombiner, VaryByHeaderName, _headers);
- CombineCollectionHashCode(hashCodeCombiner, VaryByQueryName, _queries);
- CombineCollectionHashCode(hashCodeCombiner, VaryByRouteName, _routeValues);
+ CombineCollectionHashCode(ref hashCodeCombiner, VaryByCookieName, _cookies);
+ CombineCollectionHashCode(ref hashCodeCombiner, VaryByHeaderName, _headers);
+ CombineCollectionHashCode(ref hashCodeCombiner, VaryByQueryName, _queries);
+ CombineCollectionHashCode(ref hashCodeCombiner, VaryByRouteName, _routeValues);
- _hashcode = hashCodeCombiner.CombinedHash;
+ _hashcode = hashCodeCombiner.ToHashCode();
return _hashcode.Value;
}
@@ -331,7 +331,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
}
private static void CombineCollectionHashCode(
- HashCodeCombiner hashCodeCombiner,
+ ref HashCode hashCodeCombiner,
string collectionName,
IList> values)
{
diff --git a/src/Mvc/Mvc.TagHelpers/src/GlobbingUrlBuilder.cs b/src/Mvc/Mvc.TagHelpers/src/GlobbingUrlBuilder.cs
index 82c176bc8b..e0a04a5374 100644
--- a/src/Mvc/Mvc.TagHelpers/src/GlobbingUrlBuilder.cs
+++ b/src/Mvc/Mvc.TagHelpers/src/GlobbingUrlBuilder.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Security.Policy;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.FileProviders;
@@ -373,11 +374,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
public override int GetHashCode()
{
- var hashCodeCombiner = HashCodeCombiner.Start();
+ var hashCodeCombiner = new HashCode();
hashCodeCombiner.Add(Include);
hashCodeCombiner.Add(Exclude);
- return hashCodeCombiner.CombinedHash;
+ return hashCodeCombiner.ToHashCode();
}
}
}
diff --git a/src/Mvc/Mvc.TagHelpers/test/CacheTagHelperTest.cs b/src/Mvc/Mvc.TagHelpers/test/CacheTagHelperTest.cs
index 90313c0efa..525f1107f2 100644
--- a/src/Mvc/Mvc.TagHelpers/test/CacheTagHelperTest.cs
+++ b/src/Mvc/Mvc.TagHelpers/test/CacheTagHelperTest.cs
@@ -887,7 +887,6 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
}
[Fact]
- [QuarantinedTest]
public async Task ProcessAsync_AwaitersUseTheResultOfExecutor()
{
// Arrange
diff --git a/src/Mvc/Mvc.ViewFeatures/ref/Microsoft.AspNetCore.Mvc.ViewFeatures.netcoreapp.cs b/src/Mvc/Mvc.ViewFeatures/ref/Microsoft.AspNetCore.Mvc.ViewFeatures.netcoreapp.cs
index 62cfeb38a0..b6c137cfea 100644
--- a/src/Mvc/Mvc.ViewFeatures/ref/Microsoft.AspNetCore.Mvc.ViewFeatures.netcoreapp.cs
+++ b/src/Mvc/Mvc.ViewFeatures/ref/Microsoft.AspNetCore.Mvc.ViewFeatures.netcoreapp.cs
@@ -652,6 +652,7 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
[System.Diagnostics.DebuggerDisplayAttribute("{DebuggerToString()}")]
public partial class TagBuilder : Microsoft.AspNetCore.Html.IHtmlContent
{
+ public TagBuilder(Microsoft.AspNetCore.Mvc.Rendering.TagBuilder tagBuilder) { }
public TagBuilder(string tagName) { }
public Microsoft.AspNetCore.Mvc.ViewFeatures.AttributeDictionary Attributes { get { throw null; } }
public bool HasInnerHtml { get { throw null; } }
diff --git a/src/Mvc/Mvc.ViewFeatures/src/LambdaExpressionComparer.cs b/src/Mvc/Mvc.ViewFeatures/src/LambdaExpressionComparer.cs
index 1e0dcc7fe7..e3448c15c0 100644
--- a/src/Mvc/Mvc.ViewFeatures/src/LambdaExpressionComparer.cs
+++ b/src/Mvc/Mvc.ViewFeatures/src/LambdaExpressionComparer.cs
@@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
public int GetHashCode(LambdaExpression lambdaExpression)
{
var expression = lambdaExpression.Body;
- var hashCodeCombiner = HashCodeCombiner.Start();
+ var hashCodeCombiner = new HashCode();
while (true)
{
@@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
}
}
- return hashCodeCombiner.CombinedHash;
+ return hashCodeCombiner.ToHashCode();
}
}
}
diff --git a/src/Mvc/Mvc.ViewFeatures/src/MemberExpressionCacheKeyComparer.cs b/src/Mvc/Mvc.ViewFeatures/src/MemberExpressionCacheKeyComparer.cs
index 5911611c89..b1586e71ba 100644
--- a/src/Mvc/Mvc.ViewFeatures/src/MemberExpressionCacheKeyComparer.cs
+++ b/src/Mvc/Mvc.ViewFeatures/src/MemberExpressionCacheKeyComparer.cs
@@ -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.Collections.Generic;
using Microsoft.Extensions.Internal;
@@ -39,7 +40,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
public int GetHashCode(MemberExpressionCacheKey obj)
{
- var hashCodeCombiner = new HashCodeCombiner();
+ var hashCodeCombiner = new HashCode();
hashCodeCombiner.Add(obj.ModelType);
foreach (var member in obj)
@@ -47,7 +48,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
hashCodeCombiner.Add(member);
}
- return hashCodeCombiner.CombinedHash;
+ return hashCodeCombiner.ToHashCode();
}
}
}
diff --git a/src/Mvc/Mvc.ViewFeatures/src/Rendering/TagBuilder.cs b/src/Mvc/Mvc.ViewFeatures/src/Rendering/TagBuilder.cs
index e3e4edfbb8..4b6d8b6fcb 100644
--- a/src/Mvc/Mvc.ViewFeatures/src/Rendering/TagBuilder.cs
+++ b/src/Mvc/Mvc.ViewFeatures/src/Rendering/TagBuilder.cs
@@ -37,6 +37,34 @@ namespace Microsoft.AspNetCore.Mvc.Rendering
TagName = tagName;
}
+ ///
+ /// Creates a copy of the HTML tag passed as .
+ ///
+ /// Tag to copy.
+ public TagBuilder(TagBuilder tagBuilder)
+ {
+ if (tagBuilder == null)
+ {
+ throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(tagBuilder));
+ }
+
+ if (tagBuilder._attributes != null)
+ {
+ foreach (var tag in tagBuilder._attributes)
+ {
+ Attributes.Add(tag);
+ }
+ }
+
+ if (tagBuilder._innerHtml != null)
+ {
+ tagBuilder.InnerHtml.CopyTo(InnerHtml);
+ }
+
+ TagName = tagBuilder.TagName;
+ TagRenderMode = tagBuilder.TagRenderMode;
+ }
+
///
/// Gets the set of attributes that will be written to the tag.
///
diff --git a/src/Mvc/Mvc.ViewFeatures/test/Rendering/TagBuilderTest.cs b/src/Mvc/Mvc.ViewFeatures/test/Rendering/TagBuilderTest.cs
index 0132887614..3ceaeef37b 100644
--- a/src/Mvc/Mvc.ViewFeatures/test/Rendering/TagBuilderTest.cs
+++ b/src/Mvc/Mvc.ViewFeatures/test/Rendering/TagBuilderTest.cs
@@ -253,5 +253,64 @@ namespace Microsoft.AspNetCore.Mvc.Core.Rendering
// Assert
Assert.Equal("Hello", HtmlContentUtilities.HtmlContentToString(tag));
}
+
+ [Fact]
+ public void Constructor_Copy_CopiesTagRenderMode()
+ {
+ // Arrange
+ var originalTagBuilder = new TagBuilder("p");
+ originalTagBuilder.TagRenderMode = TagRenderMode.SelfClosing;
+
+ // Act
+ var clonedTagBuilder = new TagBuilder(originalTagBuilder);
+
+
+ // Assert
+ Assert.Equal(originalTagBuilder.TagRenderMode, clonedTagBuilder.TagRenderMode);
+ }
+
+ [Fact]
+ public void Constructor_Copy_DoesShallowCopyOfInnerHtml()
+ {
+ // Arrange
+ var originalTagBuilder = new TagBuilder("p");
+ originalTagBuilder.InnerHtml.AppendHtml("Hello");
+
+ // Act
+ var clonedTagBuilder = new TagBuilder(originalTagBuilder);
+
+ // Assert
+ Assert.NotEqual(originalTagBuilder.InnerHtml, clonedTagBuilder.InnerHtml);
+ Assert.Equal(HtmlContentUtilities.HtmlContentToString(originalTagBuilder.RenderBody()), HtmlContentUtilities.HtmlContentToString(clonedTagBuilder.RenderBody()));
+ }
+
+ [Fact]
+ public void Constructor_Copy_DoesShallowCopyOfAttributes()
+ {
+ // Arrange
+ var originalTagBuilder = new TagBuilder("p");
+ originalTagBuilder.AddCssClass("class1");
+
+ // Act
+ var clonedTagBuilder = new TagBuilder(originalTagBuilder);
+
+ // Assert
+ Assert.NotSame(originalTagBuilder.Attributes, clonedTagBuilder.Attributes);
+ Assert.Equal(originalTagBuilder.Attributes, clonedTagBuilder.Attributes);
+ }
+
+ [Fact]
+ public void Constructor_Copy_CopiesTagName()
+ {
+ // Arrange
+ var originalTagBuilder = new TagBuilder("p");
+
+ // Act
+
+ var clonedTagBuilder = new TagBuilder(originalTagBuilder);
+
+ // Assert
+ Assert.Equal(originalTagBuilder.TagName, clonedTagBuilder.TagName);
+ }
}
}
\ No newline at end of file
diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs
index d61c6fa5da..f883d88f83 100644
--- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs
+++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/ClientCertificateTests.cs
@@ -34,7 +34,6 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
.WithAllHostingModels();
[ConditionalTheory]
- [QuarantinedTest]
[MemberData(nameof(TestVariants))]
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
public Task HttpsNoClientCert_NoClientCert(TestVariant variant)
diff --git a/src/Servers/Kestrel/Core/src/CoreStrings.resx b/src/Servers/Kestrel/Core/src/CoreStrings.resx
index 96f6e49969..46f2e263a3 100644
--- a/src/Servers/Kestrel/Core/src/CoreStrings.resx
+++ b/src/Servers/Kestrel/Core/src/CoreStrings.resx
@@ -268,7 +268,7 @@
Overriding endpoints defined in UseKestrel() because {settingName} is set to true. Binding to address(es) '{addresses}' instead.
- Unrecognized scheme in server address '{address}'. Only 'http://' is supported.
+ Unrecognized scheme in server address '{address}'. Only 'http://' and 'https://' are supported.
Headers are read-only, response has already started.
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/HPackHeaderWriter.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/HPackHeaderWriter.cs
index 33c7b920f3..c914595bc9 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http2/HPackHeaderWriter.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http2/HPackHeaderWriter.cs
@@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
case 404:
case 500:
// Status codes which exist in the HTTP/2 StaticTable.
- return HPackEncoder.EncodeIndexedHeaderField(H2StaticTable.StatusIndex[statusCode], buffer, out length);
+ return HPackEncoder.EncodeIndexedHeaderField(H2StaticTable.GetStatusIndex(statusCode), buffer, out length);
default:
const string name = ":status";
var value = StatusCodes.ToStatusString(statusCode);
diff --git a/src/Servers/Kestrel/perf/Kestrel.Performance/HPackDecoderBenchmark.cs b/src/Servers/Kestrel/perf/Kestrel.Performance/HPackDecoderBenchmark.cs
new file mode 100644
index 0000000000..31382bbf5e
--- /dev/null
+++ b/src/Servers/Kestrel/perf/Kestrel.Performance/HPackDecoderBenchmark.cs
@@ -0,0 +1,135 @@
+// 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.Linq;
+using System.Net.Http.HPack;
+using System.Text;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Attributes;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Performance
+{
+ public class HPackDecoderBenchmark
+ {
+ // Indexed Header Field Representation - Dynamic Table - Index 62 (first index in dynamic table)
+ private static readonly byte[] _indexedHeaderDynamic = new byte[] { 0xbe };
+
+ private static readonly byte[] _literalHeaderFieldWithoutIndexingNewName = new byte[] { 0x00 };
+
+ private const string _headerNameString = "new-header";
+
+ private static readonly byte[] _headerNameBytes = Encoding.ASCII.GetBytes(_headerNameString);
+
+ private static readonly byte[] _headerName = new byte[] { (byte)_headerNameBytes.Length }
+ .Concat(_headerNameBytes)
+ .ToArray();
+
+ private const string _headerValueString = "value";
+
+ private static readonly byte[] _headerValueBytes = Encoding.ASCII.GetBytes(_headerValueString);
+
+ private static readonly byte[] _headerValue = new byte[] { (byte)_headerValueBytes.Length }
+ .Concat(_headerValueBytes)
+ .ToArray();
+
+ private static readonly byte[] _literalHeaderFieldNeverIndexed_NewName = _literalHeaderFieldWithoutIndexingNewName
+ .Concat(_headerName)
+ .Concat(_headerValue)
+ .ToArray();
+
+ private static readonly byte[] _literalHeaderFieldNeverIndexed_NewName_Large;
+ private static readonly byte[] _literalHeaderFieldNeverIndexed_NewName_Multiple;
+ private static readonly byte[] _indexedHeaderDynamic_Multiple;
+
+ static HPackDecoderBenchmark()
+ {
+ string string8193 = new string('a', 8193);
+
+ _literalHeaderFieldNeverIndexed_NewName_Large = _literalHeaderFieldWithoutIndexingNewName
+ .Concat(new byte[] { 0x7f, 0x82, 0x3f }) // 8193 encoded with 7-bit prefix, no Huffman encoding
+ .Concat(Encoding.ASCII.GetBytes(string8193))
+ .Concat(new byte[] { 0x7f, 0x82, 0x3f }) // 8193 encoded with 7-bit prefix, no Huffman encoding
+ .Concat(Encoding.ASCII.GetBytes(string8193))
+ .ToArray();
+
+ _literalHeaderFieldNeverIndexed_NewName_Multiple = _literalHeaderFieldNeverIndexed_NewName
+ .Concat(_literalHeaderFieldNeverIndexed_NewName)
+ .Concat(_literalHeaderFieldNeverIndexed_NewName)
+ .Concat(_literalHeaderFieldNeverIndexed_NewName)
+ .Concat(_literalHeaderFieldNeverIndexed_NewName)
+ .ToArray();
+
+ _indexedHeaderDynamic_Multiple = _indexedHeaderDynamic
+ .Concat(_indexedHeaderDynamic)
+ .Concat(_indexedHeaderDynamic)
+ .Concat(_indexedHeaderDynamic)
+ .Concat(_indexedHeaderDynamic)
+ .ToArray();
+ }
+
+ private HPackDecoder _decoder;
+ private TestHeadersHandler _testHeadersHandler;
+ private DynamicTable _dynamicTable;
+
+ [GlobalSetup]
+ public void GlobalSetup()
+ {
+ _dynamicTable = new DynamicTable(maxSize: 4096);
+ _dynamicTable.Insert(_headerNameBytes, _headerValueBytes);
+ _decoder = new HPackDecoder(maxDynamicTableSize: 4096, maxHeadersLength: 65536, _dynamicTable);
+ _testHeadersHandler = new TestHeadersHandler();
+ }
+
+ [Benchmark]
+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName()
+ {
+ _decoder.Decode(_literalHeaderFieldNeverIndexed_NewName, endHeaders: true, handler: _testHeadersHandler);
+ }
+
+ [Benchmark]
+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_Large()
+ {
+ _decoder.Decode(_literalHeaderFieldNeverIndexed_NewName_Large, endHeaders: true, handler: _testHeadersHandler);
+ }
+
+ [Benchmark]
+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_Multiple()
+ {
+ _decoder.Decode(_literalHeaderFieldNeverIndexed_NewName_Multiple, endHeaders: true, handler: _testHeadersHandler);
+ }
+
+ [Benchmark]
+ public void DecodesIndexedHeaderField_DynamicTable()
+ {
+ _decoder.Decode(_indexedHeaderDynamic, endHeaders: true, handler: _testHeadersHandler);
+ }
+
+ [Benchmark]
+ public void DecodesIndexedHeaderField_DynamicTable_Multiple()
+ {
+ _decoder.Decode(_indexedHeaderDynamic_Multiple, endHeaders: true, handler: _testHeadersHandler);
+ }
+
+ private class TestHeadersHandler : IHttpHeadersHandler
+ {
+ public void OnHeader(ReadOnlySpan name, ReadOnlySpan value)
+ {
+ }
+
+ public void OnHeadersComplete(bool endStream)
+ {
+ }
+
+ public void OnStaticIndexedHeader(int index)
+ {
+ }
+
+ public void OnStaticIndexedHeader(int index, ReadOnlySpan value)
+ {
+ }
+ }
+ }
+}
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
index 43a3f9d7a2..a1cf418fe3 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2ConnectionTests.cs
@@ -300,7 +300,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
}
[Fact]
- [QuarantinedTest]
public async Task StreamPool_MultipleStreamsInSequence_PooledStreamReused()
{
TaskCompletionSource appDelegateTcs = null;
@@ -365,7 +364,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
}
[Fact]
- [QuarantinedTest]
public async Task StreamPool_StreamIsInvalidState_DontReturnedToPool()
{
var serverTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -4010,7 +4008,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
[Theory]
[InlineData(true)]
[InlineData(false)]
- [QuarantinedTest]
public async Task CONTINUATION_Received_WithTrailers_Available(bool sendData)
{
await InitializeConnectionAsync(_readTrailersApplication);
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs
index 99bbd21ea5..c433bb90be 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/Http2/Http2TimeoutTests.cs
@@ -371,7 +371,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
}
[Fact]
- [QuarantinedTest]
public async Task DATA_Sent_TooSlowlyDueToFlowControlOnSmallWrite_AbortsConnectionAfterGracePeriod()
{
var mockSystemClock = _serviceContext.MockSystemClock;
@@ -426,7 +425,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
}
[Fact]
- [QuarantinedTest]
public async Task DATA_Sent_TooSlowlyDueToOutputFlowControlOnLargeWrite_AbortsConnectionAfterRateTimeout()
{
var mockSystemClock = _serviceContext.MockSystemClock;
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsTests.cs
index 4849965c40..e36759544c 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsTests.cs
@@ -220,7 +220,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
[Fact]
[Repeat(20)]
- [QuarantinedTest]
public async Task DoesNotThrowObjectDisposedExceptionFromWriteAsyncAfterConnectionIsAborted()
{
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestHeaderLimitsTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestHeaderLimitsTests.cs
index c5002a8c8c..5ab5b467e8 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestHeaderLimitsTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestHeaderLimitsTests.cs
@@ -23,7 +23,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
[InlineData(5, 0)]
[InlineData(5, 1)]
[InlineData(5, 1337)]
- [QuarantinedTest]
public async Task ServerAcceptsRequestWithHeaderTotalSizeWithinLimit(int headerCount, int extraLimit)
{
var headers = MakeHeaders(headerCount);
diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs
index 3ada9a09a6..0d1c028fe5 100644
--- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs
+++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs
@@ -559,7 +559,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.InMemory.FunctionalTests
}
[Fact]
- [QuarantinedTest]
public async Task TraceIdentifierIsUnique()
{
const int identifierLength = 22;
diff --git a/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs b/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs
index f234c2edbc..fc41de2069 100644
--- a/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs
+++ b/src/Shared/ClosedGenericMatcher/ClosedGenericMatcher.cs
@@ -1,8 +1,9 @@
// 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.
+#nullable enable
+
using System;
-using System.Linq;
using System.Reflection;
namespace Microsoft.Extensions.Internal
@@ -28,7 +29,7 @@ namespace Microsoft.Extensions.Internal
/// typeof(KeyValuePair{,}), and is
/// typeof(KeyValuePair{string, object}).
///
- public static Type ExtractGenericInterface(Type queryType, Type interfaceType)
+ public static Type? ExtractGenericInterface(Type queryType, Type interfaceType)
{
if (queryType == null)
{
@@ -62,9 +63,9 @@ namespace Microsoft.Extensions.Internal
candidate.GetGenericTypeDefinition() == interfaceType;
}
- private static Type GetGenericInstantiation(Type queryType, Type interfaceType)
+ private static Type? GetGenericInstantiation(Type queryType, Type interfaceType)
{
- Type bestMatch = null;
+ Type? bestMatch = null;
var interfaces = queryType.GetInterfaces();
foreach (var @interface in interfaces)
{
@@ -103,4 +104,4 @@ namespace Microsoft.Extensions.Internal
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Shared/runtime/Http2/Hpack/DynamicTable.cs b/src/Shared/runtime/Http2/Hpack/DynamicTable.cs
index 5a8fdf170f..9e93dca87c 100644
--- a/src/Shared/runtime/Http2/Hpack/DynamicTable.cs
+++ b/src/Shared/runtime/Http2/Hpack/DynamicTable.cs
@@ -25,7 +25,7 @@ namespace System.Net.Http.HPack
public int MaxSize => _maxSize;
- public HeaderField this[int index]
+ public ref readonly HeaderField this[int index]
{
get
{
@@ -42,7 +42,7 @@ namespace System.Net.Http.HPack
index += _buffer.Length;
}
- return _buffer[index];
+ return ref _buffer[index];
}
}
diff --git a/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs b/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs
index 7f3b775582..c0f203fef4 100644
--- a/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs
+++ b/src/Shared/runtime/Http2/Hpack/H2StaticTable.cs
@@ -9,23 +9,22 @@ namespace System.Net.Http.HPack
{
internal static class H2StaticTable
{
- // Index of status code into s_staticDecoderTable
- private static readonly Dictionary s_statusIndex = new Dictionary
- {
- [200] = 8,
- [204] = 9,
- [206] = 10,
- [304] = 11,
- [400] = 12,
- [404] = 13,
- [500] = 14,
- };
-
public static int Count => s_staticDecoderTable.Length;
- public static HeaderField Get(int index) => s_staticDecoderTable[index];
+ public static ref readonly HeaderField Get(int index) => ref s_staticDecoderTable[index];
- public static IReadOnlyDictionary StatusIndex => s_statusIndex;
+ public static int GetStatusIndex(int status) =>
+ status switch
+ {
+ 200 => 8,
+ 204 => 9,
+ 206 => 10,
+ 304 => 11,
+ 400 => 12,
+ 404 => 13,
+ 500 => 14,
+ _ => throw new ArgumentOutOfRangeException()
+ };
private static readonly HeaderField[] s_staticDecoderTable = new HeaderField[]
{
diff --git a/src/Shared/runtime/Http2/Hpack/HPackDecoder.cs b/src/Shared/runtime/Http2/Hpack/HPackDecoder.cs
index 3fe3c86243..b07dc47d9a 100644
--- a/src/Shared/runtime/Http2/Hpack/HPackDecoder.cs
+++ b/src/Shared/runtime/Http2/Hpack/HPackDecoder.cs
@@ -5,6 +5,7 @@
#nullable enable
using System.Buffers;
using System.Diagnostics;
+using System.Numerics;
#if KESTREL
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
#endif
@@ -37,7 +38,6 @@ namespace System.Net.Http.HPack
// | 1 | Index (7+) |
// +---+---------------------------+
private const byte IndexedHeaderFieldMask = 0x80;
- private const byte IndexedHeaderFieldRepresentation = 0x80;
// http://httpwg.org/specs/rfc7541.html#rfc.section.6.2.1
// 0 1 2 3 4 5 6 7
@@ -45,7 +45,6 @@ namespace System.Net.Http.HPack
// | 0 | 1 | Index (6+) |
// +---+---+-----------------------+
private const byte LiteralHeaderFieldWithIncrementalIndexingMask = 0xc0;
- private const byte LiteralHeaderFieldWithIncrementalIndexingRepresentation = 0x40;
// http://httpwg.org/specs/rfc7541.html#rfc.section.6.2.2
// 0 1 2 3 4 5 6 7
@@ -53,7 +52,6 @@ namespace System.Net.Http.HPack
// | 0 | 0 | 0 | 0 | Index (4+) |
// +---+---+-----------------------+
private const byte LiteralHeaderFieldWithoutIndexingMask = 0xf0;
- private const byte LiteralHeaderFieldWithoutIndexingRepresentation = 0x00;
// http://httpwg.org/specs/rfc7541.html#rfc.section.6.2.3
// 0 1 2 3 4 5 6 7
@@ -61,7 +59,6 @@ namespace System.Net.Http.HPack
// | 0 | 0 | 0 | 1 | Index (4+) |
// +---+---+-----------------------+
private const byte LiteralHeaderFieldNeverIndexedMask = 0xf0;
- private const byte LiteralHeaderFieldNeverIndexedRepresentation = 0x10;
// http://httpwg.org/specs/rfc7541.html#rfc.section.6.3
// 0 1 2 3 4 5 6 7
@@ -69,7 +66,6 @@ namespace System.Net.Http.HPack
// | 0 | 0 | 1 | Max size (5+) |
// +---+---------------------------+
private const byte DynamicTableSizeUpdateMask = 0xe0;
- private const byte DynamicTableSizeUpdateRepresentation = 0x20;
// http://httpwg.org/specs/rfc7541.html#rfc.section.5.2
// 0 1 2 3 4 5 6 7
@@ -92,6 +88,8 @@ namespace System.Net.Http.HPack
private byte[] _stringOctets;
private byte[] _headerNameOctets;
private byte[] _headerValueOctets;
+ private (int start, int length)? _headerNameRange;
+ private (int start, int length)? _headerValueRange;
private State _state = State.Ready;
private byte[]? _headerName;
@@ -124,107 +122,247 @@ namespace System.Net.Http.HPack
{
foreach (ReadOnlyMemory segment in data)
{
- DecodeInternal(segment.Span, endHeaders, handler);
+ DecodeInternal(segment.Span, handler);
}
CheckIncompleteHeaderBlock(endHeaders);
}
- public void Decode(ReadOnlySpan data, bool endHeaders, IHttpHeadersHandler? handler)
+ public void Decode(ReadOnlySpan data, bool endHeaders, IHttpHeadersHandler handler)
{
- DecodeInternal(data, endHeaders, handler);
+ DecodeInternal(data, handler);
CheckIncompleteHeaderBlock(endHeaders);
}
- private void DecodeInternal(ReadOnlySpan data, bool endHeaders, IHttpHeadersHandler? handler)
+ private void DecodeInternal(ReadOnlySpan data, IHttpHeadersHandler handler)
{
- int intResult;
+ int currentIndex = 0;
- for (int i = 0; i < data.Length; i++)
+ do
{
- byte b = data[i];
switch (_state)
{
case State.Ready:
- // TODO: Instead of masking and comparing each prefix value,
- // consider doing a 16-way switch on the first four bits (which is the max prefix size).
- // Look at this once we have more concrete perf data.
- if ((b & IndexedHeaderFieldMask) == IndexedHeaderFieldRepresentation)
+ Parse(data, ref currentIndex, handler);
+ break;
+ case State.HeaderFieldIndex:
+ ParseHeaderFieldIndex(data, ref currentIndex, handler);
+ break;
+ case State.HeaderNameIndex:
+ ParseHeaderNameIndex(data, ref currentIndex, handler);
+ break;
+ case State.HeaderNameLength:
+ ParseHeaderNameLength(data, ref currentIndex, handler);
+ break;
+ case State.HeaderNameLengthContinue:
+ ParseHeaderNameLengthContinue(data, ref currentIndex, handler);
+ break;
+ case State.HeaderName:
+ ParseHeaderName(data, ref currentIndex, handler);
+ break;
+ case State.HeaderValueLength:
+ ParseHeaderValueLength(data, ref currentIndex, handler);
+ break;
+ case State.HeaderValueLengthContinue:
+ ParseHeaderValueLengthContinue(data, ref currentIndex, handler);
+ break;
+ case State.HeaderValue:
+ ParseHeaderValue(data, ref currentIndex, handler);
+ break;
+ case State.DynamicTableSizeUpdate:
+ ParseDynamicTableSizeUpdate(data, ref currentIndex);
+ break;
+ default:
+ // Can't happen
+ Debug.Fail("HPACK decoder reach an invalid state");
+ throw new NotImplementedException(_state.ToString());
+ }
+ }
+ // Parse methods each check the length. This check is to see whether there is still data available
+ // and to continue parsing.
+ while (currentIndex < data.Length);
+
+ // If a header range was set, but the value was not in the data, then copy the range
+ // to the name buffer. Must copy because because the data will be replaced and the range
+ // will no longer be valid.
+ if (_headerNameRange != null)
+ {
+ EnsureStringCapacity(ref _headerNameOctets);
+ _headerName = _headerNameOctets;
+
+ ReadOnlySpan headerBytes = data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length);
+ headerBytes.CopyTo(_headerName);
+ _headerNameLength = headerBytes.Length;
+ _headerNameRange = null;
+ }
+ }
+
+ private void ParseDynamicTableSizeUpdate(ReadOnlySpan data, ref int currentIndex)
+ {
+ if (TryDecodeInteger(data, ref currentIndex, out int intResult))
+ {
+ SetDynamicHeaderTableSize(intResult);
+ _state = State.Ready;
+ }
+ }
+
+ private void ParseHeaderValueLength(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ if (currentIndex < data.Length)
+ {
+ byte b = data[currentIndex++];
+
+ _huffman = IsHuffmanEncoded(b);
+
+ if (_integerDecoder.BeginTryDecode((byte)(b & ~HuffmanMask), StringLengthPrefix, out int intResult))
+ {
+ OnStringLength(intResult, nextState: State.HeaderValue);
+
+ if (intResult == 0)
+ {
+ OnString(nextState: State.Ready);
+ ProcessHeaderValue(data, handler);
+ }
+ else
+ {
+ ParseHeaderValue(data, ref currentIndex, handler);
+ }
+ }
+ else
+ {
+ _state = State.HeaderValueLengthContinue;
+ ParseHeaderValueLengthContinue(data, ref currentIndex, handler);
+ }
+ }
+ }
+
+ private void ParseHeaderNameLengthContinue(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ if (TryDecodeInteger(data, ref currentIndex, out int intResult))
+ {
+ // IntegerDecoder disallows overlong encodings, where an integer is encoded with more bytes than is strictly required.
+ // 0 should always be represented by a single byte, so we shouldn't need to check for it in the continuation case.
+ Debug.Assert(intResult != 0, "A header name length of 0 should never be encoded with a continuation byte.");
+
+ OnStringLength(intResult, nextState: State.HeaderName);
+ ParseHeaderName(data, ref currentIndex, handler);
+ }
+ }
+
+ private void ParseHeaderValueLengthContinue(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ if (TryDecodeInteger(data, ref currentIndex, out int intResult))
+ {
+ // 0 should always be represented by a single byte, so we shouldn't need to check for it in the continuation case.
+ Debug.Assert(intResult != 0, "A header value length of 0 should never be encoded with a continuation byte.");
+
+ OnStringLength(intResult, nextState: State.HeaderValue);
+ ParseHeaderValue(data, ref currentIndex, handler);
+ }
+ }
+
+ private void ParseHeaderFieldIndex(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ if (TryDecodeInteger(data, ref currentIndex, out int intResult))
+ {
+ OnIndexedHeaderField(intResult, handler);
+ }
+ }
+
+ private void ParseHeaderNameIndex(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ if (TryDecodeInteger(data, ref currentIndex, out int intResult))
+ {
+ OnIndexedHeaderName(intResult);
+ ParseHeaderValueLength(data, ref currentIndex, handler);
+ }
+ }
+
+ private void ParseHeaderNameLength(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ if (currentIndex < data.Length)
+ {
+ byte b = data[currentIndex++];
+
+ _huffman = IsHuffmanEncoded(b);
+
+ if (_integerDecoder.BeginTryDecode((byte)(b & ~HuffmanMask), StringLengthPrefix, out int intResult))
+ {
+ if (intResult == 0)
+ {
+ throw new HPackDecodingException(SR.Format(SR.net_http_invalid_header_name, ""));
+ }
+
+ OnStringLength(intResult, nextState: State.HeaderName);
+ ParseHeaderName(data, ref currentIndex, handler);
+ }
+ else
+ {
+ _state = State.HeaderNameLengthContinue;
+ ParseHeaderNameLengthContinue(data, ref currentIndex, handler);
+ }
+ }
+ }
+
+ private void Parse(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ if (currentIndex < data.Length)
+ {
+ Debug.Assert(_state == State.Ready, "Should be ready to parse a new header.");
+
+ byte b = data[currentIndex++];
+
+ switch (BitOperations.LeadingZeroCount(b) - 24) // byte 'b' is extended to uint, so will have 24 extra 0s.
+ {
+ case 0: // Indexed Header Field
{
_headersObserved = true;
int val = b & ~IndexedHeaderFieldMask;
- if (_integerDecoder.BeginTryDecode((byte)val, IndexedHeaderFieldPrefix, out intResult))
+ if (_integerDecoder.BeginTryDecode((byte)val, IndexedHeaderFieldPrefix, out int intResult))
{
OnIndexedHeaderField(intResult, handler);
}
else
{
_state = State.HeaderFieldIndex;
+ ParseHeaderFieldIndex(data, ref currentIndex, handler);
}
+ break;
}
- else if ((b & LiteralHeaderFieldWithIncrementalIndexingMask) == LiteralHeaderFieldWithIncrementalIndexingRepresentation)
- {
- _headersObserved = true;
-
- _index = true;
- int val = b & ~LiteralHeaderFieldWithIncrementalIndexingMask;
-
- if (val == 0)
- {
- _state = State.HeaderNameLength;
- }
- else if (_integerDecoder.BeginTryDecode((byte)val, LiteralHeaderFieldWithIncrementalIndexingPrefix, out intResult))
- {
- OnIndexedHeaderName(intResult);
- }
- else
- {
- _state = State.HeaderNameIndex;
- }
- }
- else if ((b & LiteralHeaderFieldWithoutIndexingMask) == LiteralHeaderFieldWithoutIndexingRepresentation)
- {
- _headersObserved = true;
-
- _index = false;
- int val = b & ~LiteralHeaderFieldWithoutIndexingMask;
-
- if (val == 0)
- {
- _state = State.HeaderNameLength;
- }
- else if (_integerDecoder.BeginTryDecode((byte)val, LiteralHeaderFieldWithoutIndexingPrefix, out intResult))
- {
- OnIndexedHeaderName(intResult);
- }
- else
- {
- _state = State.HeaderNameIndex;
- }
- }
- else if ((b & LiteralHeaderFieldNeverIndexedMask) == LiteralHeaderFieldNeverIndexedRepresentation)
- {
- _headersObserved = true;
-
- _index = false;
- int val = b & ~LiteralHeaderFieldNeverIndexedMask;
-
- if (val == 0)
- {
- _state = State.HeaderNameLength;
- }
- else if (_integerDecoder.BeginTryDecode((byte)val, LiteralHeaderFieldNeverIndexedPrefix, out intResult))
- {
- OnIndexedHeaderName(intResult);
- }
- else
- {
- _state = State.HeaderNameIndex;
- }
- }
- else if ((b & DynamicTableSizeUpdateMask) == DynamicTableSizeUpdateRepresentation)
+ case 1: // Literal Header Field with Incremental Indexing
+ ParseLiteralHeaderField(
+ data,
+ ref currentIndex,
+ b,
+ LiteralHeaderFieldWithIncrementalIndexingMask,
+ LiteralHeaderFieldWithIncrementalIndexingPrefix,
+ index: true,
+ handler);
+ break;
+ case 4:
+ default: // Literal Header Field without Indexing
+ ParseLiteralHeaderField(
+ data,
+ ref currentIndex,
+ b,
+ LiteralHeaderFieldWithoutIndexingMask,
+ LiteralHeaderFieldWithoutIndexingPrefix,
+ index: false,
+ handler);
+ break;
+ case 3: // Literal Header Field Never Indexed
+ ParseLiteralHeaderField(
+ data,
+ ref currentIndex,
+ b,
+ LiteralHeaderFieldNeverIndexedMask,
+ LiteralHeaderFieldNeverIndexedPrefix,
+ index: false,
+ handler);
+ break;
+ case 2: // Dynamic Table Size Update
{
// https://tools.ietf.org/html/rfc7541#section-4.2
// This dynamic table size
@@ -235,125 +373,107 @@ namespace System.Net.Http.HPack
throw new HPackDecodingException(SR.net_http_hpack_late_dynamic_table_size_update);
}
- if (_integerDecoder.BeginTryDecode((byte)(b & ~DynamicTableSizeUpdateMask), DynamicTableSizeUpdatePrefix, out intResult))
+ if (_integerDecoder.BeginTryDecode((byte)(b & ~DynamicTableSizeUpdateMask), DynamicTableSizeUpdatePrefix, out int intResult))
{
SetDynamicHeaderTableSize(intResult);
}
else
{
_state = State.DynamicTableSizeUpdate;
+ ParseDynamicTableSizeUpdate(data, ref currentIndex);
}
+ break;
}
- else
- {
- // Can't happen
- Debug.Fail("Unreachable code");
- throw new InvalidOperationException("Unreachable code.");
- }
+ }
+ }
+ }
- break;
- case State.HeaderFieldIndex:
- if (_integerDecoder.TryDecode(b, out intResult))
- {
- OnIndexedHeaderField(intResult, handler);
- }
+ private void ParseLiteralHeaderField(ReadOnlySpan data, ref int currentIndex, byte b, byte mask, byte indexPrefix, bool index, IHttpHeadersHandler handler)
+ {
+ _headersObserved = true;
- break;
- case State.HeaderNameIndex:
- if (_integerDecoder.TryDecode(b, out intResult))
- {
- OnIndexedHeaderName(intResult);
- }
+ _index = index;
+ int val = b & ~mask;
- break;
- case State.HeaderNameLength:
- _huffman = (b & HuffmanMask) != 0;
+ if (val == 0)
+ {
+ _state = State.HeaderNameLength;
+ ParseHeaderNameLength(data, ref currentIndex, handler);
+ }
+ else
+ {
+ if (_integerDecoder.BeginTryDecode((byte)val, indexPrefix, out int intResult))
+ {
+ OnIndexedHeaderName(intResult);
+ ParseHeaderValueLength(data, ref currentIndex, handler);
+ }
+ else
+ {
+ _state = State.HeaderNameIndex;
+ ParseHeaderNameIndex(data, ref currentIndex, handler);
+ }
+ }
+ }
- if (_integerDecoder.BeginTryDecode((byte)(b & ~HuffmanMask), StringLengthPrefix, out intResult))
- {
- if (intResult == 0)
- {
- throw new HPackDecodingException(SR.Format(SR.net_http_invalid_header_name, ""));
- }
+ private void ParseHeaderName(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ // Read remaining chars, up to the length of the current data
+ int count = Math.Min(_stringLength - _stringIndex, data.Length - currentIndex);
- OnStringLength(intResult, nextState: State.HeaderName);
- }
- else
- {
- _state = State.HeaderNameLengthContinue;
- }
+ // Check whether the whole string is available in the data and no decompression required.
+ // If string is good then mark its range.
+ // NOTE: it may need to be copied to buffer later the if value is not current data.
+ if (count == _stringLength && !_huffman)
+ {
+ // Fast path. Store the range rather than copying.
+ _headerNameRange = (start: currentIndex, count);
+ currentIndex += count;
- break;
- case State.HeaderNameLengthContinue:
- if (_integerDecoder.TryDecode(b, out intResult))
- {
- // IntegerDecoder disallows overlong encodings, where an integer is encoded with more bytes than is strictly required.
- // 0 should always be represented by a single byte, so we shouldn't need to check for it in the continuation case.
- Debug.Assert(intResult != 0, "A header name length of 0 should never be encoded with a continuation byte.");
+ _state = State.HeaderValueLength;
+ }
+ else
+ {
+ // Copy string to temporary buffer.
+ // _stringOctets was already
+ data.Slice(currentIndex, count).CopyTo(_stringOctets.AsSpan(_stringIndex));
+ _stringIndex += count;
+ currentIndex += count;
- OnStringLength(intResult, nextState: State.HeaderName);
- }
+ if (_stringIndex == _stringLength)
+ {
+ OnString(nextState: State.HeaderValueLength);
+ ParseHeaderValueLength(data, ref currentIndex, handler);
+ }
+ }
+ }
- break;
- case State.HeaderName:
- _stringOctets[_stringIndex++] = b;
+ private void ParseHeaderValue(ReadOnlySpan data, ref int currentIndex, IHttpHeadersHandler handler)
+ {
+ // Read remaining chars, up to the length of the current data
+ int count = Math.Min(_stringLength - _stringIndex, data.Length - currentIndex);
- if (_stringIndex == _stringLength)
- {
- OnString(nextState: State.HeaderValueLength);
- }
+ // Check whether the whole string is available in the data and no decompressed required.
+ // If string is good then mark its range.
+ if (count == _stringLength && !_huffman)
+ {
+ // Fast path. Store the range rather than copying.
+ _headerValueRange = (start: currentIndex, count);
+ currentIndex += count;
- break;
- case State.HeaderValueLength:
- _huffman = (b & HuffmanMask) != 0;
+ _state = State.Ready;
+ ProcessHeaderValue(data, handler);
+ }
+ else
+ {
+ // Copy string to temporary buffer.
+ data.Slice(currentIndex, count).CopyTo(_stringOctets.AsSpan(_stringIndex));
+ _stringIndex += count;
+ currentIndex += count;
- if (_integerDecoder.BeginTryDecode((byte)(b & ~HuffmanMask), StringLengthPrefix, out intResult))
- {
- OnStringLength(intResult, nextState: State.HeaderValue);
-
- if (intResult == 0)
- {
- ProcessHeaderValue(handler);
- }
- }
- else
- {
- _state = State.HeaderValueLengthContinue;
- }
-
- break;
- case State.HeaderValueLengthContinue:
- if (_integerDecoder.TryDecode(b, out intResult))
- {
- // IntegerDecoder disallows overlong encodings where an integer is encoded with more bytes than is strictly required.
- // 0 should always be represented by a single byte, so we shouldn't need to check for it in the continuation case.
- Debug.Assert(intResult != 0, "A header value length of 0 should never be encoded with a continuation byte.");
-
- OnStringLength(intResult, nextState: State.HeaderValue);
- }
-
- break;
- case State.HeaderValue:
- _stringOctets[_stringIndex++] = b;
-
- if (_stringIndex == _stringLength)
- {
- ProcessHeaderValue(handler);
- }
-
- break;
- case State.DynamicTableSizeUpdate:
- if (_integerDecoder.TryDecode(b, out intResult))
- {
- SetDynamicHeaderTableSize(intResult);
- _state = State.Ready;
- }
-
- break;
- default:
- // Can't happen
- Debug.Fail("HPACK decoder reach an invalid state");
- throw new NotImplementedException(_state.ToString());
+ if (_stringIndex == _stringLength)
+ {
+ OnString(nextState: State.Ready);
+ ProcessHeaderValue(data, handler);
}
}
}
@@ -371,14 +491,20 @@ namespace System.Net.Http.HPack
}
}
- private void ProcessHeaderValue(IHttpHeadersHandler? handler)
+ private void ProcessHeaderValue(ReadOnlySpan data, IHttpHeadersHandler handler)
{
- OnString(nextState: State.Ready);
+ ReadOnlySpan headerNameSpan = _headerNameRange == null
+ ? new Span(_headerName, 0, _headerNameLength)
+ : data.Slice(_headerNameRange.GetValueOrDefault().start, _headerNameRange.GetValueOrDefault().length);
- var headerNameSpan = new Span(_headerName, 0, _headerNameLength);
- var headerValueSpan = new Span(_headerValueOctets, 0, _headerValueLength);
+ ReadOnlySpan headerValueSpan = _headerValueRange == null
+ ? new Span(_headerValueOctets, 0, _headerValueLength)
+ : data.Slice(_headerValueRange.GetValueOrDefault().start, _headerValueRange.GetValueOrDefault().length);
- handler?.OnHeader(headerNameSpan, headerValueSpan);
+ handler.OnHeader(headerNameSpan, headerValueSpan);
+
+ _headerNameRange = null;
+ _headerValueRange = null;
if (_index)
{
@@ -395,18 +521,17 @@ namespace System.Net.Http.HPack
}
}
- private void OnIndexedHeaderField(int index, IHttpHeadersHandler? handler)
+ private void OnIndexedHeaderField(int index, IHttpHeadersHandler handler)
{
- HeaderField header = GetHeader(index);
- handler?.OnHeader(header.Name, header.Value);
+ ref readonly HeaderField header = ref GetHeader(index);
+ handler.OnHeader(header.Name, header.Value);
_state = State.Ready;
}
private void OnIndexedHeaderName(int index)
{
- HeaderField header = GetHeader(index);
- _headerName = header.Name;
- _headerNameLength = header.Name.Length;
+ _headerName = GetHeader(index).Name;
+ _headerNameLength = _headerName.Length;
_state = State.HeaderValueLength;
}
@@ -437,11 +562,7 @@ namespace System.Net.Http.HPack
}
else
{
- if (dst.Length < _stringLength)
- {
- dst = new byte[Math.Max(_stringLength, dst.Length * 2)];
- }
-
+ EnsureStringCapacity(ref dst);
Buffer.BlockCopy(_stringOctets, 0, dst, 0, _stringLength);
return _stringLength;
}
@@ -467,13 +588,41 @@ namespace System.Net.Http.HPack
_state = nextState;
}
- private HeaderField GetHeader(int index)
+ private void EnsureStringCapacity(ref byte[] dst)
+ {
+ if (dst.Length < _stringLength)
+ {
+ dst = new byte[Math.Max(_stringLength, dst.Length * 2)];
+ }
+ }
+
+ private bool TryDecodeInteger(ReadOnlySpan data, ref int currentIndex, out int result)
+ {
+ for (; currentIndex < data.Length; currentIndex++)
+ {
+ if (_integerDecoder.TryDecode(data[currentIndex], out result))
+ {
+ currentIndex++;
+ return true;
+ }
+ }
+
+ result = default;
+ return false;
+ }
+
+ private static bool IsHuffmanEncoded(byte b)
+ {
+ return (b & HuffmanMask) != 0;
+ }
+
+ private ref readonly HeaderField GetHeader(int index)
{
try
{
- return index <= H2StaticTable.Count
- ? H2StaticTable.Get(index - 1)
- : _dynamicTable[index - H2StaticTable.Count - 1];
+ return ref index <= H2StaticTable.Count
+ ? ref H2StaticTable.Get(index - 1)
+ : ref _dynamicTable[index - H2StaticTable.Count - 1];
}
catch (IndexOutOfRangeException)
{
diff --git a/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs b/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs
index 97cdea1c50..4a8511e682 100644
--- a/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs
+++ b/src/Shared/runtime/Http2/Hpack/HPackEncoder.cs
@@ -54,7 +54,7 @@ namespace System.Net.Http.HPack
case 404:
case 500:
// Status codes which exist in the HTTP/2 StaticTable.
- return EncodeIndexedHeaderField(H2StaticTable.StatusIndex[statusCode], destination, out bytesWritten);
+ return EncodeIndexedHeaderField(H2StaticTable.GetStatusIndex(statusCode), destination, out bytesWritten);
default:
// If the status code doesn't have a static index then we need to include the full value.
// Write a status index and then the number bytes as a string literal.
diff --git a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs
index 2afdb29901..d5d26ccb37 100644
--- a/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs
+++ b/src/Shared/test/Shared.Tests/runtime/Http2/HPackDecoderTest.cs
@@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
namespace System.Net.Http.Unit.Tests.HPack
{
- public class HPackDecoderTests : IHttpHeadersHandler
+ public class HPackDecoderTests
{
private const int DynamicTableInitialMaxSize = 4096;
private const int MaxHeaderFieldSize = 8192;
@@ -89,42 +89,26 @@ namespace System.Net.Http.Unit.Tests.HPack
private readonly DynamicTable _dynamicTable;
private readonly HPackDecoder _decoder;
-
- private readonly Dictionary _decodedHeaders = new Dictionary();
+ private readonly TestHttpHeadersHandler _handler = new TestHttpHeadersHandler();
public HPackDecoderTests()
{
- _dynamicTable = new DynamicTable(DynamicTableInitialMaxSize);
- _decoder = new HPackDecoder(DynamicTableInitialMaxSize, MaxHeaderFieldSize, _dynamicTable);
+ (_dynamicTable, _decoder) = CreateDecoderAndTable();
}
- void IHttpHeadersHandler.OnHeader(ReadOnlySpan name, ReadOnlySpan value)
+ private static (DynamicTable, HPackDecoder) CreateDecoderAndTable()
{
- string headerName = Encoding.ASCII.GetString(name);
- string headerValue = Encoding.ASCII.GetString(value);
+ var dynamicTable = new DynamicTable(DynamicTableInitialMaxSize);
+ var decoder = new HPackDecoder(DynamicTableInitialMaxSize, MaxHeaderFieldSize, dynamicTable);
- _decodedHeaders[headerName] = headerValue;
+ return (dynamicTable, decoder);
}
- void IHttpHeadersHandler.OnStaticIndexedHeader(int index)
- {
- // Not yet implemented for HPACK.
- throw new NotImplementedException();
- }
-
- void IHttpHeadersHandler.OnStaticIndexedHeader(int index, ReadOnlySpan value)
- {
- // Not yet implemented for HPACK.
- throw new NotImplementedException();
- }
-
- void IHttpHeadersHandler.OnHeadersComplete(bool endStream) { }
-
[Fact]
public void DecodesIndexedHeaderField_StaticTable()
{
- _decoder.Decode(_indexedHeaderStatic, endHeaders: true, handler: this);
- Assert.Equal("GET", _decodedHeaders[":method"]);
+ _decoder.Decode(_indexedHeaderStatic, endHeaders: true, handler: _handler);
+ Assert.Equal("GET", _handler.DecodedHeaders[":method"]);
}
[Fact]
@@ -134,17 +118,17 @@ namespace System.Net.Http.Unit.Tests.HPack
_dynamicTable.Insert(_headerNameBytes, _headerValueBytes);
// Index it
- _decoder.Decode(_indexedHeaderDynamic, endHeaders: true, handler: this);
- Assert.Equal(_headerValueString, _decodedHeaders[_headerNameString]);
+ _decoder.Decode(_indexedHeaderDynamic, endHeaders: true, handler: _handler);
+ Assert.Equal(_headerValueString, _handler.DecodedHeaders[_headerNameString]);
}
[Fact]
public void DecodesIndexedHeaderField_OutOfRange_Error()
{
HPackDecodingException exception = Assert.Throws(() =>
- _decoder.Decode(_indexedHeaderDynamic, endHeaders: true, handler: this));
+ _decoder.Decode(_indexedHeaderDynamic, endHeaders: true, handler: _handler));
Assert.Equal(SR.Format(SR.net_http_hpack_invalid_index, 62), exception.Message);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
[Fact]
@@ -218,9 +202,9 @@ namespace System.Net.Http.Unit.Tests.HPack
// 11 1110 (Indexed Name - Index 62 encoded with 6-bit prefix - see http://httpwg.org/specs/rfc7541.html#integer.representation)
// Index 62 is the first entry in the dynamic table. If there's nothing there, the decoder should throw.
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(new byte[] { 0x7e }, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(new byte[] { 0x7e }, endHeaders: true, handler: _handler));
Assert.Equal(SR.Format(SR.net_http_hpack_invalid_index, 62), exception.Message);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
[Fact]
@@ -294,9 +278,9 @@ namespace System.Net.Http.Unit.Tests.HPack
// 1111 0010 1111 (Indexed Name - Index 62 encoded with 4-bit prefix - see http://httpwg.org/specs/rfc7541.html#integer.representation)
// Index 62 is the first entry in the dynamic table. If there's nothing there, the decoder should throw.
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(new byte[] { 0x0f, 0x2f }, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(new byte[] { 0x0f, 0x2f }, endHeaders: true, handler: _handler));
Assert.Equal(SR.Format(SR.net_http_hpack_invalid_index, 62), exception.Message);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
[Fact]
@@ -310,6 +294,19 @@ namespace System.Net.Http.Unit.Tests.HPack
TestDecodeWithoutIndexing(encoded, _headerNameString, _headerValueString);
}
+ [Fact]
+ public void DecodesLiteralHeaderFieldNeverIndexed_NewName_Duplicated()
+ {
+ byte[] encoded = _literalHeaderFieldNeverIndexedNewName
+ .Concat(_headerName)
+ .Concat(_headerValue)
+ .ToArray();
+
+ encoded = encoded.Concat(encoded).ToArray();
+
+ TestDecodeWithoutIndexing(encoded, _headerNameString, _headerValueString);
+ }
+
[Fact]
public void DecodesLiteralHeaderFieldNeverIndexed_NewName_HuffmanEncodedName()
{
@@ -376,9 +373,9 @@ namespace System.Net.Http.Unit.Tests.HPack
// 1111 0010 1111 (Indexed Name - Index 62 encoded with 4-bit prefix - see http://httpwg.org/specs/rfc7541.html#integer.representation)
// Index 62 is the first entry in the dynamic table. If there's nothing there, the decoder should throw.
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(new byte[] { 0x1f, 0x2f }, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(new byte[] { 0x1f, 0x2f }, endHeaders: true, handler: _handler));
Assert.Equal(SR.Format(SR.net_http_hpack_invalid_index, 62), exception.Message);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
[Fact]
@@ -389,10 +386,10 @@ namespace System.Net.Http.Unit.Tests.HPack
Assert.Equal(DynamicTableInitialMaxSize, _dynamicTable.MaxSize);
- _decoder.Decode(new byte[] { 0x3e }, endHeaders: true, handler: this);
+ _decoder.Decode(new byte[] { 0x3e }, endHeaders: true, handler: _handler);
Assert.Equal(30, _dynamicTable.MaxSize);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
[Fact]
@@ -404,7 +401,7 @@ namespace System.Net.Http.Unit.Tests.HPack
Assert.Equal(DynamicTableInitialMaxSize, _dynamicTable.MaxSize);
byte[] data = _indexedHeaderStatic.Concat(new byte[] { 0x3e }).ToArray();
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(data, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(data, endHeaders: true, handler: _handler));
Assert.Equal(SR.net_http_hpack_late_dynamic_table_size_update, exception.Message);
}
@@ -413,13 +410,13 @@ namespace System.Net.Http.Unit.Tests.HPack
{
Assert.Equal(DynamicTableInitialMaxSize, _dynamicTable.MaxSize);
- _decoder.Decode(_indexedHeaderStatic, endHeaders: false, handler: this);
- Assert.Equal("GET", _decodedHeaders[":method"]);
+ _decoder.Decode(_indexedHeaderStatic, endHeaders: false, handler: _handler);
+ Assert.Equal("GET", _handler.DecodedHeaders[":method"]);
// 001 (Dynamic Table Size Update)
// 11110 (30 encoded with 5-bit prefix - see http://httpwg.org/specs/rfc7541.html#integer.representation)
byte[] data = new byte[] { 0x3e };
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(data, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(data, endHeaders: true, handler: _handler));
Assert.Equal(SR.net_http_hpack_late_dynamic_table_size_update, exception.Message);
}
@@ -428,12 +425,12 @@ namespace System.Net.Http.Unit.Tests.HPack
{
Assert.Equal(DynamicTableInitialMaxSize, _dynamicTable.MaxSize);
- _decoder.Decode(_indexedHeaderStatic, endHeaders: true, handler: this);
- Assert.Equal("GET", _decodedHeaders[":method"]);
+ _decoder.Decode(_indexedHeaderStatic, endHeaders: true, handler: _handler);
+ Assert.Equal("GET", _handler.DecodedHeaders[":method"]);
// 001 (Dynamic Table Size Update)
// 11110 (30 encoded with 5-bit prefix - see http://httpwg.org/specs/rfc7541.html#integer.representation)
- _decoder.Decode(new byte[] { 0x3e }, endHeaders: true, handler: this);
+ _decoder.Decode(new byte[] { 0x3e }, endHeaders: true, handler: _handler);
Assert.Equal(30, _dynamicTable.MaxSize);
}
@@ -447,9 +444,9 @@ namespace System.Net.Http.Unit.Tests.HPack
Assert.Equal(DynamicTableInitialMaxSize, _dynamicTable.MaxSize);
HPackDecodingException exception = Assert.Throws(() =>
- _decoder.Decode(new byte[] { 0x3f, 0xe2, 0x1f }, endHeaders: true, handler: this));
+ _decoder.Decode(new byte[] { 0x3f, 0xe2, 0x1f }, endHeaders: true, handler: _handler));
Assert.Equal(SR.Format(SR.net_http_hpack_large_table_size_update, 4097, DynamicTableInitialMaxSize), exception.Message);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
[Fact]
@@ -459,9 +456,9 @@ namespace System.Net.Http.Unit.Tests.HPack
.Concat(new byte[] { 0xff, 0x82, 0x3f }) // 8193 encoded with 7-bit prefix
.ToArray();
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(encoded, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(encoded, endHeaders: true, handler: _handler));
Assert.Equal(SR.Format(SR.net_http_headers_exceeded_length, MaxHeaderFieldSize), exception.Message);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
[Fact]
@@ -477,9 +474,57 @@ namespace System.Net.Http.Unit.Tests.HPack
.Concat(Encoding.ASCII.GetBytes(string8193))
.ToArray();
- decoder.Decode(encoded, endHeaders: true, handler: this);
+ decoder.Decode(encoded, endHeaders: true, handler: _handler);
- Assert.Equal(string8193, _decodedHeaders[string8193]);
+ Assert.Equal(string8193, _handler.DecodedHeaders[string8193]);
+ }
+
+ [Fact]
+ public void DecodesStringLength_IndividualBytes()
+ {
+ HPackDecoder decoder = new HPackDecoder(DynamicTableInitialMaxSize, MaxHeaderFieldSize + 1);
+ string string8193 = new string('a', MaxHeaderFieldSize + 1);
+
+ byte[] encoded = _literalHeaderFieldWithoutIndexingNewName
+ .Concat(new byte[] { 0x7f, 0x82, 0x3f }) // 8193 encoded with 7-bit prefix, no Huffman encoding
+ .Concat(Encoding.ASCII.GetBytes(string8193))
+ .Concat(new byte[] { 0x7f, 0x82, 0x3f }) // 8193 encoded with 7-bit prefix, no Huffman encoding
+ .Concat(Encoding.ASCII.GetBytes(string8193))
+ .ToArray();
+
+ for (int i = 0; i < encoded.Length; i++)
+ {
+ bool end = i + 1 == encoded.Length;
+
+ decoder.Decode(new byte[] { encoded[i] }, endHeaders: end, handler: _handler);
+ }
+
+ Assert.Equal(string8193, _handler.DecodedHeaders[string8193]);
+ }
+
+ [Fact]
+ public void DecodesHeaderNameAndValue_SeparateSegments()
+ {
+ HPackDecoder decoder = new HPackDecoder(DynamicTableInitialMaxSize, MaxHeaderFieldSize + 1);
+ string string8193 = new string('a', MaxHeaderFieldSize + 1);
+
+ byte[][] segments = new byte[][]
+ {
+ _literalHeaderFieldWithoutIndexingNewName,
+ new byte[] { 0x7f, 0x82, 0x3f }, // 8193 encoded with 7-bit prefix, no Huffman encoding
+ Encoding.ASCII.GetBytes(string8193),
+ new byte[] { 0x7f, 0x82, 0x3f }, // 8193 encoded with 7-bit prefix, no Huffman encoding
+ Encoding.ASCII.GetBytes(string8193)
+ };
+
+ for (int i = 0; i < segments.Length; i++)
+ {
+ bool end = i + 1 == segments.Length;
+
+ decoder.Decode(segments[i], endHeaders: end, handler: _handler);
+ }
+
+ Assert.Equal(string8193, _handler.DecodedHeaders[string8193]);
}
public static readonly TheoryData _incompleteHeaderBlockData = new TheoryData
@@ -567,9 +612,9 @@ namespace System.Net.Http.Unit.Tests.HPack
[MemberData(nameof(_incompleteHeaderBlockData))]
public void DecodesIncompleteHeaderBlock_Error(byte[] encoded)
{
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(encoded, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(encoded, endHeaders: true, handler: _handler));
Assert.Equal(SR.net_http_hpack_incomplete_header_block, exception.Message);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
public static readonly TheoryData _huffmanDecodingErrorData = new TheoryData
@@ -601,43 +646,89 @@ namespace System.Net.Http.Unit.Tests.HPack
[MemberData(nameof(_huffmanDecodingErrorData))]
public void WrapsHuffmanDecodingExceptionInHPackDecodingException(byte[] encoded)
{
- HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(encoded, endHeaders: true, handler: this));
+ HPackDecodingException exception = Assert.Throws(() => _decoder.Decode(encoded, endHeaders: true, handler: _handler));
Assert.Equal(SR.net_http_hpack_huffman_decode_failed, exception.Message);
Assert.IsType(exception.InnerException);
- Assert.Empty(_decodedHeaders);
+ Assert.Empty(_handler.DecodedHeaders);
}
- private void TestDecodeWithIndexing(byte[] encoded, string expectedHeaderName, string expectedHeaderValue)
+ private static void TestDecodeWithIndexing(byte[] encoded, string expectedHeaderName, string expectedHeaderValue)
{
- TestDecode(encoded, expectedHeaderName, expectedHeaderValue, expectDynamicTableEntry: true);
+ TestDecode(encoded, expectedHeaderName, expectedHeaderValue, expectDynamicTableEntry: true, byteAtATime: false);
+ TestDecode(encoded, expectedHeaderName, expectedHeaderValue, expectDynamicTableEntry: true, byteAtATime: true);
}
- private void TestDecodeWithoutIndexing(byte[] encoded, string expectedHeaderName, string expectedHeaderValue)
+ private static void TestDecodeWithoutIndexing(byte[] encoded, string expectedHeaderName, string expectedHeaderValue)
{
- TestDecode(encoded, expectedHeaderName, expectedHeaderValue, expectDynamicTableEntry: false);
+ TestDecode(encoded, expectedHeaderName, expectedHeaderValue, expectDynamicTableEntry: false, byteAtATime: false);
+ TestDecode(encoded, expectedHeaderName, expectedHeaderValue, expectDynamicTableEntry: false, byteAtATime: true);
}
- private void TestDecode(byte[] encoded, string expectedHeaderName, string expectedHeaderValue, bool expectDynamicTableEntry)
+ private static void TestDecode(byte[] encoded, string expectedHeaderName, string expectedHeaderValue, bool expectDynamicTableEntry, bool byteAtATime)
{
- Assert.Equal(0, _dynamicTable.Count);
- Assert.Equal(0, _dynamicTable.Size);
+ var (dynamicTable, decoder) = CreateDecoderAndTable();
+ var handler = new TestHttpHeadersHandler();
- _decoder.Decode(encoded, endHeaders: true, handler: this);
+ Assert.Equal(0, dynamicTable.Count);
+ Assert.Equal(0, dynamicTable.Size);
- Assert.Equal(expectedHeaderValue, _decodedHeaders[expectedHeaderName]);
-
- if (expectDynamicTableEntry)
+ if (!byteAtATime)
{
- Assert.Equal(1, _dynamicTable.Count);
- Assert.Equal(expectedHeaderName, Encoding.ASCII.GetString(_dynamicTable[0].Name));
- Assert.Equal(expectedHeaderValue, Encoding.ASCII.GetString(_dynamicTable[0].Value));
- Assert.Equal(expectedHeaderName.Length + expectedHeaderValue.Length + 32, _dynamicTable.Size);
+ decoder.Decode(encoded, endHeaders: true, handler: handler);
}
else
{
- Assert.Equal(0, _dynamicTable.Count);
- Assert.Equal(0, _dynamicTable.Size);
+ // Parse data in 1 byte chunks, separated by empty chunks
+ for (int i = 0; i < encoded.Length; i++)
+ {
+ bool end = i + 1 == encoded.Length;
+
+ decoder.Decode(Array.Empty(), endHeaders: false, handler: handler);
+ decoder.Decode(new byte[] { encoded[i] }, endHeaders: end, handler: handler);
+ }
+ }
+
+ Assert.Equal(expectedHeaderValue, handler.DecodedHeaders[expectedHeaderName]);
+
+ if (expectDynamicTableEntry)
+ {
+ Assert.Equal(1, dynamicTable.Count);
+ Assert.Equal(expectedHeaderName, Encoding.ASCII.GetString(dynamicTable[0].Name));
+ Assert.Equal(expectedHeaderValue, Encoding.ASCII.GetString(dynamicTable[0].Value));
+ Assert.Equal(expectedHeaderName.Length + expectedHeaderValue.Length + 32, dynamicTable.Size);
+ }
+ else
+ {
+ Assert.Equal(0, dynamicTable.Count);
+ Assert.Equal(0, dynamicTable.Size);
}
}
}
+
+ public class TestHttpHeadersHandler : IHttpHeadersHandler
+ {
+ public Dictionary DecodedHeaders { get; } = new Dictionary();
+
+ void IHttpHeadersHandler.OnHeader(ReadOnlySpan name, ReadOnlySpan value)
+ {
+ string headerName = Encoding.ASCII.GetString(name);
+ string headerValue = Encoding.ASCII.GetString(value);
+
+ DecodedHeaders[headerName] = headerValue;
+ }
+
+ void IHttpHeadersHandler.OnStaticIndexedHeader(int index)
+ {
+ // Not yet implemented for HPACK.
+ throw new NotImplementedException();
+ }
+
+ void IHttpHeadersHandler.OnStaticIndexedHeader(int index, ReadOnlySpan value)
+ {
+ // Not yet implemented for HPACK.
+ throw new NotImplementedException();
+ }
+
+ void IHttpHeadersHandler.OnHeadersComplete(bool endStream) { }
+ }
}
diff --git a/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs b/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs
index 39f99f7ff0..1e1de9abe4 100644
--- a/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs
+++ b/src/SignalR/clients/csharp/Client/test/FunctionalTests/HubConnectionTests.cs
@@ -86,7 +86,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CheckFixedMessage(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connectionBuilder = new HubConnectionBuilder()
.WithLoggerFactory(LoggerFactory)
@@ -125,7 +125,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
}
var protocol = HubProtocols["json"];
- using (var server = await StartServer(ExpectedError))
+ await using (var server = await StartServer(ExpectedError))
{
var connectionBuilder = new HubConnectionBuilder()
.WithLoggerFactory(LoggerFactory)
@@ -155,7 +155,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ClientCanConnectToServerWithLowerMinimumProtocol()
{
var protocol = HubProtocols["json"];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connectionBuilder = new HubConnectionBuilder()
.WithLoggerFactory(LoggerFactory)
@@ -185,7 +185,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanSendAndReceiveMessage(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
const string originalMessage = "SignalR";
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
@@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanSendNull(string protocolName)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, "/default", HttpTransportType.LongPolling, protocol, LoggerFactory);
try
@@ -243,7 +243,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanStopAndStartConnection(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
const string originalMessage = "SignalR";
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
@@ -275,7 +275,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanAccessConnectionIdFromHubConnection(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -310,7 +310,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanStartConnectionFromClosedEvent(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var logger = LoggerFactory.CreateLogger();
const string originalMessage = "SignalR";
@@ -372,7 +372,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task MethodsAreCaseInsensitive(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
const string originalMessage = "SignalR";
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
@@ -402,7 +402,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanInvokeFromOnHandler(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
const string originalMessage = "SignalR";
@@ -442,7 +442,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task StreamAsyncCoreTest(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -477,7 +477,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanStreamToHubWithIAsyncEnumerableMethodArg(string protocolName)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, "/default", HttpTransportType.WebSockets, protocol, LoggerFactory);
try
@@ -523,7 +523,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task StreamAsyncTest(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -558,7 +558,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task StreamAsyncDoesNotStartIfTokenAlreadyCanceled(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -595,7 +595,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task StreamAsyncCanBeCanceled(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -643,7 +643,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
}
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer(ExpectedErrors))
+ await using (var server = await StartServer(ExpectedErrors))
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -679,7 +679,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanInvokeClientMethodFromServer(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
const string originalMessage = "SignalR";
@@ -713,7 +713,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task InvokeNonExistantClientMethodFromServer(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
var closeTcs = new TaskCompletionSource();
@@ -755,7 +755,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanStreamClientMethodFromServer(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -785,7 +785,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanStreamToAndFromClientInSameInvocation(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -822,7 +822,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanStreamToServerWithIAsyncEnumerable(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -869,7 +869,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanCancelIAsyncEnumerableClientToServerUpload(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -922,7 +922,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task StreamAsyncCanBeCanceledThroughGetAsyncEnumerator(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -963,7 +963,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task CanCloseStreamMethodEarly(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -1004,7 +1004,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task StreamDoesNotStartIfTokenAlreadyCanceled(string protocolName, HttpTransportType transportType, string path)
{
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -1039,7 +1039,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
}
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer(ExpectedErrors))
+ await using (var server = await StartServer(ExpectedErrors))
{
var connection = CreateHubConnection(server.Url, path, transportType, protocol, LoggerFactory);
try
@@ -1067,7 +1067,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionIfHubMethodCannotBeResolved(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1094,7 +1094,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionIfHubMethodCannotBeResolvedAndArgumentsPassedIn(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1121,7 +1121,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionOnHubMethodArgumentCountMismatch(string hubProtocolName)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, "/default", HttpTransportType.LongPolling, hubProtocol, LoggerFactory);
try
@@ -1148,7 +1148,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionOnHubMethodArgumentTypeMismatch(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1175,7 +1175,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionIfStreamingHubMethodCannotBeResolved(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1203,7 +1203,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionOnStreamingHubMethodArgumentCountMismatch(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1231,7 +1231,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionOnStreamingHubMethodArgumentTypeMismatch(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1259,7 +1259,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionIfNonStreamMethodInvokedWithStreamAsync(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1286,7 +1286,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionIfStreamMethodInvokedWithInvoke(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1313,7 +1313,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
public async Task ServerThrowsHubExceptionIfBuildingAsyncEnumeratorIsNotPossible(string hubProtocolName, HttpTransportType transportType, string hubPath)
{
var hubProtocol = HubProtocols[hubProtocolName];
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
try
@@ -1349,7 +1349,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
};
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer(write => write.EventId.Name == "FailedWritingMessage"))
+ await using (var server = await StartServer(write => write.EventId.Name == "FailedWritingMessage"))
{
var connection = CreateHubConnection(server.Url, "/default", HttpTransportType.WebSockets, protocol, LoggerFactory);
var closedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -1396,7 +1396,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
};
var protocol = HubProtocols[protocolName];
- using (var server = await StartServer(write => write.EventId.Name == "FailedWritingMessage"))
+ await using (var server = await StartServer(write => write.EventId.Name == "FailedWritingMessage"))
{
var connection = CreateHubConnection(server.Url, "/default", HttpTransportType.LongPolling, protocol, LoggerFactory);
var closedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -1436,7 +1436,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
var hubProtocol = HubProtocols.First().Value;
var transportType = TransportTypes().First().Cast().First();
- using (var server = await StartServer())
+ await using (var server = await StartServer())
{
var connection = CreateHubConnection(server.Url, hubPath, transportType, hubProtocol, LoggerFactory);
await connection.StartAsync().OrTimeout();
@@ -1453,7 +1453,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
[MemberData(nameof(TransportTypes))]
public async Task ClientCanUseJwtBearerTokenForAuthentication(HttpTransportType transportType)
{
- using (var server = await StartServer