Jelajahi Sumber

Enable internal testing on Windows Previews (#29022)

Chris Ross 5 tahun lalu
induk
melakukan
2fb1f1d645

+ 24 - 23
.azure/pipelines/helix-matrix.yml

@@ -51,26 +51,27 @@ jobs:
       publishOnError: true
       publishOnError: true
 
 
 # Helix ARM64
 # Helix ARM64
-- template: jobs/default-build.yml
-  parameters:
-    jobName: Helix_matrix_arm64
-    jobDisplayName: "Tests: Helix ARM64 matrix"
-    agentOs: Linux
-    timeoutInMinutes: 480
-    steps:
-    - script: ./build.sh --ci --nobl --pack --arch arm64
-              /p:CrossgenOutput=false /p:ASPNETCORE_TEST_LOG_DIR=artifacts/log
-      displayName: Build shared Fx
-    - script: ./build.sh --ci --nobl --arch arm64 --noBuildRepoTasks --no-build-nodejs --no-restore --test --all
-              --projects $(Build.SourcesDirectory)/eng/helix/helix.proj /p:IsHelixJob=true /p:IsHelixDaily=true
-              /p:CrossgenOutput=false /p:ASPNETCORE_TEST_LOG_DIR=artifacts/log
-      displayName: Run build.sh helix arm64 target
-      env:
-        HelixApiAccessToken: $(HelixApiAccessToken) # Needed for internal queues
-        SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops
-    installNodeJs: false
-    artifacts:
-    - name: Helix_arm64_logs
-      path: artifacts/log/
-      publishOnError: true
-      includeForks: true
+- ${{ if ne(variables['System.TeamProject'], 'internal') }}:
+  - template: jobs/default-build.yml
+    parameters:
+      jobName: Helix_matrix_arm64
+      jobDisplayName: "Tests: Helix ARM64 matrix"
+      agentOs: Linux
+      timeoutInMinutes: 480
+      steps:
+      - script: ./build.sh --ci --nobl --pack --arch arm64
+                /p:CrossgenOutput=false /p:ASPNETCORE_TEST_LOG_DIR=artifacts/log
+        displayName: Build shared Fx
+      - script: ./build.sh --ci --nobl --arch arm64 --noBuildRepoTasks --no-build-nodejs --no-restore --test --all
+                --projects $(Build.SourcesDirectory)/eng/helix/helix.proj /p:IsHelixJob=true /p:IsHelixDaily=true
+                /p:CrossgenOutput=false /p:ASPNETCORE_TEST_LOG_DIR=artifacts/log
+        displayName: Run build.sh helix arm64 target
+        env:
+          HelixApiAccessToken: $(HelixApiAccessToken) # Needed for internal queues
+          SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops
+      installNodeJs: false
+      artifacts:
+      - name: Helix_arm64_logs
+        path: artifacts/log/
+        publishOnError: true
+        includeForks: true

+ 8 - 5
eng/targets/Helix.Common.props

@@ -19,14 +19,14 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <!-- PR(ci.yaml) required queues -->
   <!-- PR(ci.yaml) required queues -->
-  <ItemGroup Condition="'$(IsRequiredCheck)' == 'true' AND '$(TargetArchitecture)' == 'x64'">
+  <ItemGroup Condition="'$(IsRequiredCheck)' == 'true' AND '$(TargetArchitecture)' == 'x64' AND '$(_UseHelixOpenQueues)' == 'true'">
     <HelixAvailableTargetQueue Include="Ubuntu.1604.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="Ubuntu.1604.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="Windows.10.Amd64.Server20H2.Open" Platform="Windows" />
     <HelixAvailableTargetQueue Include="Windows.10.Amd64.Server20H2.Open" Platform="Windows" />
     <HelixAvailableTargetQueue Include="OSX.1014.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="OSX.1014.Amd64.Open" Platform="Linux" />
   </ItemGroup>
   </ItemGroup>
 
 
   <!-- queues for helix-matrix.yml pipeline -->
   <!-- queues for helix-matrix.yml pipeline -->
-  <ItemGroup Condition="'$(TargetArchitecture)' == 'x64' AND '$(IsHelixDaily)' == 'true' AND '$(IsWindowsOnlyTest)' != 'true'">
+  <ItemGroup Condition="'$(TargetArchitecture)' == 'x64' AND '$(IsHelixDaily)' == 'true' AND '$(_UseHelixOpenQueues)' == 'true' AND '$(IsWindowsOnlyTest)' != 'true'">
     <HelixAvailableTargetQueue Include="Ubuntu.1804.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="Ubuntu.1804.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="Ubuntu.2004.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="Ubuntu.2004.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="OSX.1100.Amd64.Open" Platform="Linux" />
     <HelixAvailableTargetQueue Include="OSX.1100.Amd64.Open" Platform="Linux" />
@@ -35,17 +35,20 @@
     <HelixAvailableTargetQueue Include="(Fedora.28.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:fedora-28-helix-09ca40b-20190508143249" Platform="Linux" />
     <HelixAvailableTargetQueue Include="(Fedora.28.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:fedora-28-helix-09ca40b-20190508143249" Platform="Linux" />
     <HelixAvailableTargetQueue Include="(Alpine.312.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:alpine-3.12-helix-20200908125345-56c6673" Platform="Linux" />
     <HelixAvailableTargetQueue Include="(Alpine.312.Amd64.Open)[email protected]/dotnet-buildtools/prereqs:alpine-3.12-helix-20200908125345-56c6673" Platform="Linux" />
   </ItemGroup>
   </ItemGroup>
-  <ItemGroup Condition="'$(TargetArchitecture)' == 'x64' AND '$(IsHelixDaily)' == 'true'">
+  <ItemGroup Condition="'$(TargetArchitecture)' == 'x64' AND '$(IsHelixDaily)' == 'true' AND '$(_UseHelixOpenQueues)' == 'true'">
     <HelixAvailableTargetQueue Include="Windows.7.Amd64.Open" Platform="Windows" />
     <HelixAvailableTargetQueue Include="Windows.7.Amd64.Open" Platform="Windows" />
     <HelixAvailableTargetQueue Include="Windows.81.Amd64.Open" Platform="Windows" />
     <HelixAvailableTargetQueue Include="Windows.81.Amd64.Open" Platform="Windows" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup Condition="'$(TargetArchitecture)' == 'x64' AND '$(IsHelixDaily)' == 'true' AND '$(_UseHelixOpenQueues)' != 'true'">
+    <HelixAvailableTargetQueue Include="Windows.10.Amd64.ClientPre.VS2019.Pre" Platform="Windows" />
+  </ItemGroup>
 
 
   <!-- arm64 queues for helix-matrix.yml pipeline -->
   <!-- arm64 queues for helix-matrix.yml pipeline -->
-  <ItemGroup Condition="'$(TargetArchitecture)' == 'arm64' AND '$(IsHelixDaily)' == 'true' AND '$(IsWindowsOnlyTest)' != 'true'">
+  <ItemGroup Condition="'$(TargetArchitecture)' == 'arm64' AND '$(IsHelixDaily)' == 'true' AND '$(_UseHelixOpenQueues)' == 'true' AND '$(IsWindowsOnlyTest)' != 'true'">
     <HelixAvailableTargetQueue Include="(Debian.9.Arm64.Open)[email protected]/dotnet-buildtools/prereqs:debian-9-helix-arm64v8-a12566d-20190807161036" Platform="Linux" />
     <HelixAvailableTargetQueue Include="(Debian.9.Arm64.Open)[email protected]/dotnet-buildtools/prereqs:debian-9-helix-arm64v8-a12566d-20190807161036" Platform="Linux" />
   </ItemGroup>
   </ItemGroup>
   <!-- IIS Express isn't supported on arm64 and most of the IsWindowsOnlyTests depend on it's setup scripts. -->
   <!-- IIS Express isn't supported on arm64 and most of the IsWindowsOnlyTests depend on it's setup scripts. -->
-  <ItemGroup Condition="'$(TargetArchitecture)' == 'arm64' AND '$(IsHelixDaily)' == 'true' AND '$(IsWindowsOnlyTest)' != 'true'">
+  <ItemGroup Condition="'$(TargetArchitecture)' == 'arm64' AND '$(IsHelixDaily)' == 'true' AND '$(_UseHelixOpenQueues)' == 'true' AND '$(IsWindowsOnlyTest)' != 'true'">
     <HelixAvailableTargetQueue Include="Windows.10.Arm64v8.Open" Platform="Windows" />
     <HelixAvailableTargetQueue Include="Windows.10.Arm64v8.Open" Platform="Windows" />
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 4 - 0
src/Servers/HttpSys/src/RequestProcessing/Request.cs

@@ -312,6 +312,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys
             {
             {
                 Protocol |= SslProtocols.Tls12;
                 Protocol |= SslProtocols.Tls12;
             }
             }
+            if ((Protocol & SslProtocols.Tls13) != 0)
+            {
+                Protocol |= SslProtocols.Tls13;
+            }
 
 
             CipherAlgorithm = handshake.CipherType;
             CipherAlgorithm = handshake.CipherType;
             CipherStrength = (int)handshake.CipherStrength;
             CipherStrength = (int)handshake.CipherStrength;

+ 11 - 10
src/Servers/HttpSys/test/FunctionalTests/Http2Tests.cs

@@ -4,7 +4,6 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
-using System.Linq;
 using System.Net;
 using System.Net;
 using System.Net.Http;
 using System.Net.Http;
 using System.Text;
 using System.Text;
@@ -23,6 +22,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
 {
 {
     public class Http2Tests
     public class Http2Tests
     {
     {
+        private const string VersionForReset = "10.0.19529";
+
         [ConditionalFact]
         [ConditionalFact]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
         public async Task EmptyResponse_200()
         public async Task EmptyResponse_200()
@@ -534,7 +535,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Custom Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task AppException_AfterHeaders_ResetInternalError()
         public async Task AppException_AfterHeaders_ResetInternalError()
         {
         {
             using var server = Utilities.CreateDynamicHttpsServer(out var address, async httpContext =>
             using var server = Utilities.CreateDynamicHttpsServer(out var address, async httpContext =>
@@ -586,7 +587,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
 
 
         [ConditionalFact]
         [ConditionalFact]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
-        [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_20H1, SkipReason = "This is last version without Reset support")]
+        [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_20H2, SkipReason = "This is last version without Reset support")]
         public async Task Reset_PriorOSVersions_NotSupported()
         public async Task Reset_PriorOSVersions_NotSupported()
         {
         {
             using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
             using var server = Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
@@ -606,7 +607,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task Reset_BeforeResponse_Resets()
         public async Task Reset_BeforeResponse_Resets()
         {
         {
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -648,7 +649,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task Reset_AfterResponseHeaders_Resets()
         public async Task Reset_AfterResponseHeaders_Resets()
         {
         {
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -695,7 +696,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task Reset_DurringResponseBody_Resets()
         public async Task Reset_DurringResponseBody_Resets()
         {
         {
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -745,7 +746,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task Reset_AfterCompleteAsync_NoReset()
         public async Task Reset_AfterCompleteAsync_NoReset()
         {
         {
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -797,7 +798,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task Reset_BeforeRequestBody_Resets()
         public async Task Reset_BeforeRequestBody_Resets()
         {
         {
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -843,7 +844,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task Reset_DurringRequestBody_Resets()
         public async Task Reset_DurringRequestBody_Resets()
         {
         {
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -892,7 +893,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests
         }
         }
 
 
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, "10.0.19529", SkipReason = "Reset support was added in Win10_20H2.")]
+        [MinimumOSVersion(OperatingSystems.Windows, VersionForReset)]
         public async Task Reset_CompleteAsyncDurringRequestBody_Resets()
         public async Task Reset_CompleteAsyncDurringRequestBody_Resets()
         {
         {
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);
             var appResult = new TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously);

+ 27 - 19
src/Servers/HttpSys/test/FunctionalTests/HttpsTests.cs

@@ -128,29 +128,37 @@ namespace Microsoft.AspNetCore.Server.HttpSys
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
         public async Task Https_SetsITlsHandshakeFeature()
         public async Task Https_SetsITlsHandshakeFeature()
         {
         {
-            using (Utilities.CreateDynamicHttpsServer(out var address, async httpContext =>
+            using (Utilities.CreateDynamicHttpsServer(out var address, httpContext =>
             {
             {
-                try
-                {
-                    var tlsFeature = httpContext.Features.Get<ITlsHandshakeFeature>();
-                    Assert.NotNull(tlsFeature);
-                    Assert.True(tlsFeature.Protocol > SslProtocols.None, "Protocol");
-                    Assert.True(Enum.IsDefined(typeof(SslProtocols), tlsFeature.Protocol), "Defined"); // Mapping is required, make sure it's current
-                    Assert.True(tlsFeature.CipherAlgorithm > CipherAlgorithmType.Null, "Cipher");
-                    Assert.True(tlsFeature.CipherStrength > 0, "CipherStrength");
-                    Assert.True(tlsFeature.HashAlgorithm > HashAlgorithmType.None, "HashAlgorithm");
-                    Assert.True(tlsFeature.HashStrength >= 0, "HashStrength"); // May be 0 for some algorithms
-                    Assert.True(tlsFeature.KeyExchangeAlgorithm > ExchangeAlgorithmType.None, "KeyExchangeAlgorithm");
-                    Assert.True(tlsFeature.KeyExchangeStrength > 0, "KeyExchangeStrength");
-                }
-                catch (Exception ex)
-                {
-                    await httpContext.Response.WriteAsync(ex.ToString());
-                }
+                var tlsFeature = httpContext.Features.Get<ITlsHandshakeFeature>();
+                Assert.NotNull(tlsFeature);
+                return httpContext.Response.WriteAsJsonAsync(tlsFeature);
             }))
             }))
             {
             {
                 string response = await SendRequestAsync(address);
                 string response = await SendRequestAsync(address);
-                Assert.Equal(string.Empty, response);
+                var result = System.Text.Json.JsonDocument.Parse(response).RootElement;
+
+                var protocol = (SslProtocols)result.GetProperty("protocol").GetInt32();
+                Assert.True(protocol > SslProtocols.None, "Protocol: " + protocol);
+                Assert.True(Enum.IsDefined(typeof(SslProtocols), protocol), "Defined: " + protocol); // Mapping is required, make sure it's current
+
+                var cipherAlgorithm = (CipherAlgorithmType)result.GetProperty("cipherAlgorithm").GetInt32();
+                Assert.True(cipherAlgorithm > CipherAlgorithmType.Null, "Cipher: " + cipherAlgorithm);
+
+                var cipherStrength = result.GetProperty("cipherStrength").GetInt32();
+                Assert.True(cipherStrength > 0, "CipherStrength: " + cipherStrength);
+
+                var hashAlgorithm = (HashAlgorithmType)result.GetProperty("hashAlgorithm").GetInt32();
+                Assert.True(hashAlgorithm >= HashAlgorithmType.None, "HashAlgorithm: " + hashAlgorithm);
+
+                var hashStrength = result.GetProperty("hashStrength").GetInt32();
+                Assert.True(hashStrength >= 0, "HashStrength: " + hashStrength); // May be 0 for some algorithms
+
+                var keyExchangeAlgorithm = (ExchangeAlgorithmType)result.GetProperty("keyExchangeAlgorithm").GetInt32();
+                Assert.True(keyExchangeAlgorithm >= ExchangeAlgorithmType.None, "KeyExchangeAlgorithm: " + keyExchangeAlgorithm);
+
+                var keyExchangeStrength = result.GetProperty("keyExchangeStrength").GetInt32();
+                Assert.True(keyExchangeStrength >= 0, "KeyExchangeStrength: " + keyExchangeStrength);
             }
             }
         }
         }
 
 

+ 5 - 439
src/Servers/IIS/IIS/test/Common.FunctionalTests/Http2Tests.cs

@@ -3,14 +3,12 @@
 
 
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
-using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Net;
 using System.Net;
 using System.Net.Http;
 using System.Net.Http;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Http2Cat;
 using Microsoft.AspNetCore.Http2Cat;
-using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
 using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
 using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
 using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
 using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
@@ -22,11 +20,13 @@ using Xunit;
 
 
 namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
 namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
 {
 {
+    /// <summary>
+    /// These are HTTP/2 tests that work on both IIS and Express. See Http2TrailerResetTests for IIS specific tests
+    /// with newer functionality.
+    /// </summary>
     [Collection(IISHttpsTestSiteCollection.Name)]
     [Collection(IISHttpsTestSiteCollection.Name)]
     public class Http2Tests
     public class Http2Tests
     {
     {
-        private const string WindowsVersionForTrailers = "10.0.20238";
-
         public Http2Tests(IISTestSiteFixture fixture)
         public Http2Tests(IISTestSiteFixture fixture)
         {
         {
             var port = TestPortHelper.GetNextSSLPort();
             var port = TestPortHelper.GetNextSSLPort();
@@ -301,31 +301,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
                 .Build().RunAsync();
                 .Build().RunAsync();
         }
         }
 
 
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_HTTP2_TrailersAvailable()
-        {
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_HTTP2_TrailersAvailable");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.Empty(response.TrailingHeaders);
-        }
-
         [ConditionalFact]
         [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_ProhibitedTrailers_Blocked()
-        {
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_ProhibitedTrailers_Blocked");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.Empty(response.TrailingHeaders);
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
         public async Task ResponseTrailers_HTTP1_TrailersNotAvailable()
         public async Task ResponseTrailers_HTTP1_TrailersNotAvailable()
         {
         {
             var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_HTTP1_TrailersNotAvailable", http2: false);
             var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_HTTP1_TrailersNotAvailable", http2: false);
@@ -335,129 +311,6 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
             Assert.Empty(response.TrailingHeaders);
             Assert.Empty(response.TrailingHeaders);
         }
         }
 
 
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_NoBody_TrailersSent()
-        {
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_NoBody_TrailersSent");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.NotEmpty(response.TrailingHeaders);
-            Assert.Equal("TrailerValue", response.TrailingHeaders.GetValues("TrailerName").Single());
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_WithBody_TrailersSent()
-        {
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithBody_TrailersSent");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.Equal("Hello World", await response.Content.ReadAsStringAsync());
-            Assert.NotEmpty(response.TrailingHeaders);
-            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_WithContentLengthBody_TrailersSent()
-        {
-            var body = "Hello World";
-
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithContentLengthBody_TrailersSent");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.Equal(body, await response.Content.ReadAsStringAsync());
-            Assert.NotEmpty(response.TrailingHeaders);
-            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_WithTrailersBeforeContentLengthBody_TrailersSent()
-        {
-            var body = "Hello World";
-
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithTrailersBeforeContentLengthBody_TrailersSent");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            // Avoid HttpContent's automatic content-length calculation.
-            Assert.True(response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out var contentLength), HeaderNames.ContentLength);
-            Assert.Equal((2 * body.Length).ToString(CultureInfo.InvariantCulture), contentLength.First());
-            Assert.Equal(body + body, await response.Content.ReadAsStringAsync());
-            Assert.NotEmpty(response.TrailingHeaders);
-            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_WithContentLengthBodyAndDeclared_TrailersSent()
-        {
-            var body = "Hello World";
-
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithContentLengthBodyAndDeclared_TrailersSent");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            // Avoid HttpContent's automatic content-length calculation.
-            Assert.True(response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out var contentLength), HeaderNames.ContentLength);
-            Assert.Equal(body.Length.ToString(CultureInfo.InvariantCulture), contentLength.First());
-            Assert.Equal("TrailerName", response.Headers.Trailer.Single());
-            Assert.Equal(body, await response.Content.ReadAsStringAsync());
-            Assert.NotEmpty(response.TrailingHeaders);
-            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_MultipleValues_SentAsSeparateHeaders()
-        {
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_MultipleValues_SentAsSeparateHeaders");
-
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.NotEmpty(response.TrailingHeaders);
-
-            Assert.Equal(new[] { "TrailerValue0", "TrailerValue1" }, response.TrailingHeaders.GetValues("TrailerName"));
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_CompleteAsyncNoBody_TrailersSent()
-        {
-            // The app func for CompleteAsync will not finish until CompleteAsync_Completed is sent.
-            // This verifies that the response is sent to the client with CompleteAsync
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncNoBody_TrailersSent");
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.NotEmpty(response.TrailingHeaders);
-            Assert.Equal("TrailerValue", response.TrailingHeaders.GetValues("TrailerName").Single());
-
-            var response2 = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncNoBody_TrailersSent_Completed");
-            Assert.True(response2.IsSuccessStatusCode);
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task ResponseTrailers_CompleteAsyncWithBody_TrailersSent()
-        {
-            // The app func for CompleteAsync will not finish until CompleteAsync_Completed is sent.
-            // This verifies that the response is sent to the client with CompleteAsync
-            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncWithBody_TrailersSent");
-            response.EnsureSuccessStatusCode();
-            Assert.Equal(HttpVersion.Version20, response.Version);
-            Assert.Equal("Hello World", await response.Content.ReadAsStringAsync());
-            Assert.NotEmpty(response.TrailingHeaders);
-            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
-
-            var response2 = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncWithBody_TrailersSent_Completed");
-            Assert.True(response2.IsSuccessStatusCode);
-        }
-
         [ConditionalFact]
         [ConditionalFact]
         [RequiresNewHandler]
         [RequiresNewHandler]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
@@ -485,34 +338,6 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
                 .Build().RunAsync();
                 .Build().RunAsync();
         }
         }
 
 
-        [ConditionalFact]
-        [RequiresNewHandler]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task AppException_AfterHeaders_ResetInternalError()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetHeaders("/AppException_AfterHeaders_ResetInternalError"), endStream: true);
-
-                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
-                    {
-                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
-                    });
-
-                    var frame = await h2Connection.ReceiveFrameAsync();
-
-                    Http2Utilities.VerifyResetFrame(frame, expectedStreamId: 1, Http2ErrorCode.INTERNAL_ERROR);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
         [ConditionalFact]
         [ConditionalFact]
         [RequiresNewHandler]
         [RequiresNewHandler]
         public async Task Reset_Http1_NotSupported()
         public async Task Reset_Http1_NotSupported()
@@ -528,7 +353,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
         [ConditionalFact]
         [ConditionalFact]
         [RequiresNewHandler]
         [RequiresNewHandler]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10, SkipReason = "Http2 requires Win10")]
-        [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_20H1, SkipReason = "This is last version without Reset support")]
+        [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_20H2, SkipReason = "This is last version without Reset support")]
         public async Task Reset_PriorOSVersions_NotSupported()
         public async Task Reset_PriorOSVersions_NotSupported()
         {
         {
             var handler = new HttpClientHandler();
             var handler = new HttpClientHandler();
@@ -539,240 +364,6 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
             Assert.Equal("Hello World", response);
             Assert.Equal("Hello World", response);
         }
         }
 
 
-        [ConditionalFact]
-        [RequiresNewHandler]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_BeforeResponse_Resets()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_BeforeResponse_Resets"), endStream: true);
-
-                    var resetFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
-
-                    // Any app errors?
-                    var client = CreateClient();
-                    var response = await client.GetAsync(Fixture.Client.BaseAddress + "/Reset_BeforeResponse_Resets_Complete");
-                    Assert.True(response.IsSuccessStatusCode);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
-        [ConditionalFact]
-        [RequiresNewHandler]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_BeforeResponse_Zero_Resets()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_BeforeResponse_Zero_Resets"), endStream: true);
-
-                    var resetFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)0);
-
-                    // Any app errors?
-                    var client = CreateClient();
-                    var response = await client.GetAsync(Fixture.Client.BaseAddress + "/Reset_BeforeResponse_Zero_Resets_Complete");
-                    Assert.True(response.IsSuccessStatusCode);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
-        [ConditionalFact]
-        [RequiresNewHandler]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_AfterResponseHeaders_Resets()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_AfterResponseHeaders_Resets"), endStream: true);
-
-                    // Any app errors?
-                    var client = CreateClient();
-                    var response = await client.GetAsync(Fixture.Client.BaseAddress + "/Reset_AfterResponseHeaders_Resets_Complete");
-                    Assert.True(response.IsSuccessStatusCode);
-
-                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
-                    {
-                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
-                    });
-
-                    var resetFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
-        [ConditionalFact]
-        [RequiresNewHandler]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_DuringResponseBody_Resets()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_DuringResponseBody_Resets"), endStream: true);
-
-                    // This is currently flaky, can either receive header or reset at this point
-                    var headerOrResetFrame = await h2Connection.ReceiveFrameAsync();
-                    Assert.True(headerOrResetFrame.Type == Http2FrameType.HEADERS || headerOrResetFrame.Type == Http2FrameType.RST_STREAM);
-
-                    if (headerOrResetFrame.Type == Http2FrameType.HEADERS)
-                    {
-                        var dataFrame = await h2Connection.ReceiveFrameAsync();
-                        Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: false, length: 11);
-
-                        var resetFrame = await h2Connection.ReceiveFrameAsync();
-                        Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
-                    }
-                    else
-                    {
-                        Http2Utilities.VerifyResetFrame(headerOrResetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
-                    }
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
-
-        [ConditionalFact]
-        [RequiresNewHandler]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_BeforeRequestBody_Resets()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetPostHeaders("/Reset_BeforeRequestBody_Resets"), endStream: false);
-
-                    // Any app errors?
-                    //Assert.Equal(0, await appResult.Task.DefaultTimeout());
-
-                    var resetFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
-        [ConditionalFact]
-        [RequiresNewHandler]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_DuringRequestBody_Resets()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetPostHeaders("/Reset_DuringRequestBody_Resets"), endStream: false);
-                    await h2Connection.SendDataAsync(1, new byte[10], endStream: false);
-
-                    // Any app errors?
-                    //Assert.Equal(0, await appResult.Task.DefaultTimeout());
-
-                    var resetFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_AfterCompleteAsync_NoReset()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_AfterCompleteAsync_NoReset"), endStream: true);
-
-                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
-                    {
-                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
-                    });
-
-                    var dataFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: false, length: 11);
-
-                    dataFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: true, length: 0);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
-        [ConditionalFact]
-        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
-        public async Task Reset_CompleteAsyncDuringRequestBody_Resets()
-        {
-            await new HostBuilder()
-                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
-                {
-                    await h2Connection.InitializeConnectionAsync();
-
-                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
-
-                    await h2Connection.StartStreamAsync(1, GetPostHeaders("/Reset_CompleteAsyncDuringRequestBody_Resets"), endStream: false);
-                    await h2Connection.SendDataAsync(1, new byte[10], endStream: false);
-
-                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
-                    {
-                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
-                    });
-
-                    var dataFrame = await h2Connection.ReceiveFrameAsync();
-
-                    Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: true, length: 0);
-
-                    var resetFrame = await h2Connection.ReceiveFrameAsync();
-                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: Http2ErrorCode.NO_ERROR);
-
-                    h2Connection.Logger.LogInformation("Connection stopped.");
-                })
-                .Build().RunAsync();
-        }
-
         private static List<KeyValuePair<string, string>> GetHeaders(string path)
         private static List<KeyValuePair<string, string>> GetHeaders(string path)
         {
         {
             var headers = Headers.ToList();
             var headers = Headers.ToList();
@@ -782,24 +373,6 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
             return headers;
             return headers;
         }
         }
 
 
-        private static List<KeyValuePair<string, string>> GetPostHeaders(string path)
-        {
-            var headers = PostRequestHeaders.ToList();
-
-            var kvp = new KeyValuePair<string, string>(HeaderNames.Path, path);
-            headers.Add(kvp);
-            return headers;
-        }
-
-        private static HttpClient CreateClient()
-        {
-            var handler = new HttpClientHandler();
-            handler.MaxResponseHeadersLength = 128;
-            handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
-            var client = new HttpClient(handler);
-            return client;
-        }
-
         private async Task<HttpResponseMessage> SendRequestAsync(string uri, bool http2 = true)
         private async Task<HttpResponseMessage> SendRequestAsync(string uri, bool http2 = true)
         {
         {
             var handler = new HttpClientHandler();
             var handler = new HttpClientHandler();
@@ -821,12 +394,5 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
             new KeyValuePair<string, string>("accept-encoding", "gzip, deflate, br"),
             new KeyValuePair<string, string>("accept-encoding", "gzip, deflate, br"),
             new KeyValuePair<string, string>("upgrade-insecure-requests", "1"),
             new KeyValuePair<string, string>("upgrade-insecure-requests", "1"),
         };
         };
-
-        private static readonly IEnumerable<KeyValuePair<string, string>> PostRequestHeaders = new[]
-        {
-            new KeyValuePair<string, string>(HeaderNames.Method, "POST"),
-            new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
-            new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
-        };
     }
     }
 }
 }

+ 1 - 0
src/Servers/IIS/IIS/test/Common.FunctionalTests/HttpsTests.cs

@@ -44,6 +44,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
         [ConditionalTheory]
         [ConditionalTheory]
         [MemberData(nameof(TestVariants))]
         [MemberData(nameof(TestVariants))]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
         [MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
+        [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_20H2, SkipReason = "https://github.com/dotnet/aspnetcore/issues/29068")]
         public Task HttpsClientCert_GetCertInformation(TestVariant variant)
         public Task HttpsClientCert_GetCertInformation(TestVariant variant)
         {
         {
             return ClientCertTest(variant, sendClientCert: true);
             return ClientCertTest(variant, sendClientCert: true);

+ 506 - 0
src/Servers/IIS/IIS/test/IIS.FunctionalTests/Http2TrailersResetTests.cs

@@ -0,0 +1,506 @@
+// 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.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http2Cat;
+using Microsoft.AspNetCore.Server.IntegrationTesting.Common;
+using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
+using Microsoft.AspNetCore.Testing;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Microsoft.Net.Http.Headers;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests
+{
+    /// <summary>
+    /// These features/tests Are only supported on newer versions of Windows and IIS. They are not supported
+    /// on IIS Express even on the new Windows versions because IIS Express has its own outdated copy of IIS.
+    /// </summary>
+    [Collection(IISHttpsTestSiteCollection.Name)]
+    public class Http2TrailerResetTests
+    {
+        private const string WindowsVersionForTrailers = "10.0.20238";
+
+        public Http2TrailerResetTests(IISTestSiteFixture fixture)
+        {
+            var port = TestPortHelper.GetNextSSLPort();
+            fixture.DeploymentParameters.ApplicationBaseUriHint = $"https://localhost:{port}/";
+            fixture.DeploymentParameters.AddHttpsToServerConfig();
+            fixture.DeploymentParameters.SetWindowsAuth(false);
+            Fixture = fixture;
+        }
+
+        public IISTestSiteFixture Fixture { get; }
+
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_HTTP2_TrailersAvailable()
+        {
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_HTTP2_TrailersAvailable");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.Empty(response.TrailingHeaders);
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_ProhibitedTrailers_Blocked()
+        {
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_ProhibitedTrailers_Blocked");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.Empty(response.TrailingHeaders);
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_NoBody_TrailersSent()
+        {
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_NoBody_TrailersSent");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.NotEmpty(response.TrailingHeaders);
+            Assert.Equal("TrailerValue", response.TrailingHeaders.GetValues("TrailerName").Single());
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_WithBody_TrailersSent()
+        {
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithBody_TrailersSent");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.Equal("Hello World", await response.Content.ReadAsStringAsync());
+            Assert.NotEmpty(response.TrailingHeaders);
+            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_WithContentLengthBody_TrailersSent()
+        {
+            var body = "Hello World";
+
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithContentLengthBody_TrailersSent");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.Equal(body, await response.Content.ReadAsStringAsync());
+            Assert.NotEmpty(response.TrailingHeaders);
+            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_WithTrailersBeforeContentLengthBody_TrailersSent()
+        {
+            var body = "Hello World";
+
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithTrailersBeforeContentLengthBody_TrailersSent");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            // Avoid HttpContent's automatic content-length calculation.
+            Assert.True(response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out var contentLength), HeaderNames.ContentLength);
+            Assert.Equal((2 * body.Length).ToString(CultureInfo.InvariantCulture), contentLength.First());
+            Assert.Equal(body + body, await response.Content.ReadAsStringAsync());
+            Assert.NotEmpty(response.TrailingHeaders);
+            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_WithContentLengthBodyAndDeclared_TrailersSent()
+        {
+            var body = "Hello World";
+
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_WithContentLengthBodyAndDeclared_TrailersSent");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            // Avoid HttpContent's automatic content-length calculation.
+            Assert.True(response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out var contentLength), HeaderNames.ContentLength);
+            Assert.Equal(body.Length.ToString(CultureInfo.InvariantCulture), contentLength.First());
+            Assert.Equal("TrailerName", response.Headers.Trailer.Single());
+            Assert.Equal(body, await response.Content.ReadAsStringAsync());
+            Assert.NotEmpty(response.TrailingHeaders);
+            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_MultipleValues_SentAsSeparateHeaders()
+        {
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_MultipleValues_SentAsSeparateHeaders");
+
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.NotEmpty(response.TrailingHeaders);
+
+            Assert.Equal(new[] { "TrailerValue0", "TrailerValue1" }, response.TrailingHeaders.GetValues("TrailerName"));
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_CompleteAsyncNoBody_TrailersSent()
+        {
+            // The app func for CompleteAsync will not finish until CompleteAsync_Completed is sent.
+            // This verifies that the response is sent to the client with CompleteAsync
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncNoBody_TrailersSent");
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.NotEmpty(response.TrailingHeaders);
+            Assert.Equal("TrailerValue", response.TrailingHeaders.GetValues("TrailerName").Single());
+
+            var response2 = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncNoBody_TrailersSent_Completed");
+            Assert.True(response2.IsSuccessStatusCode);
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task ResponseTrailers_CompleteAsyncWithBody_TrailersSent()
+        {
+            // The app func for CompleteAsync will not finish until CompleteAsync_Completed is sent.
+            // This verifies that the response is sent to the client with CompleteAsync
+            var response = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncWithBody_TrailersSent");
+            response.EnsureSuccessStatusCode();
+            Assert.Equal(HttpVersion.Version20, response.Version);
+            Assert.Equal("Hello World", await response.Content.ReadAsStringAsync());
+            Assert.NotEmpty(response.TrailingHeaders);
+            Assert.Equal("Trailer Value", response.TrailingHeaders.GetValues("TrailerName").Single());
+
+            var response2 = await SendRequestAsync(Fixture.Client.BaseAddress.ToString() + "ResponseTrailers_CompleteAsyncWithBody_TrailersSent_Completed");
+            Assert.True(response2.IsSuccessStatusCode);
+        }
+
+        [ConditionalFact]
+        [RequiresNewHandler]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task AppException_AfterHeaders_ResetInternalError()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetHeaders("/AppException_AfterHeaders_ResetInternalError"), endStream: true);
+
+                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
+                    {
+                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
+                    });
+
+                    var frame = await h2Connection.ReceiveFrameAsync();
+
+                    Http2Utilities.VerifyResetFrame(frame, expectedStreamId: 1, Http2ErrorCode.INTERNAL_ERROR);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        [ConditionalFact]
+        [RequiresNewHandler]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_BeforeResponse_Resets()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_BeforeResponse_Resets"), endStream: true);
+
+                    var resetFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
+
+                    // Any app errors?
+                    var client = CreateClient();
+                    var response = await client.GetAsync(Fixture.Client.BaseAddress + "/Reset_BeforeResponse_Resets_Complete");
+                    Assert.True(response.IsSuccessStatusCode);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        [ConditionalFact]
+        [RequiresNewHandler]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_BeforeResponse_Zero_Resets()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_BeforeResponse_Zero_Resets"), endStream: true);
+
+                    var resetFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)0);
+
+                    // Any app errors?
+                    var client = CreateClient();
+                    var response = await client.GetAsync(Fixture.Client.BaseAddress + "/Reset_BeforeResponse_Zero_Resets_Complete");
+                    Assert.True(response.IsSuccessStatusCode);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        [ConditionalFact]
+        [RequiresNewHandler]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_AfterResponseHeaders_Resets()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_AfterResponseHeaders_Resets"), endStream: true);
+
+                    // Any app errors?
+                    var client = CreateClient();
+                    var response = await client.GetAsync(Fixture.Client.BaseAddress + "/Reset_AfterResponseHeaders_Resets_Complete");
+                    Assert.True(response.IsSuccessStatusCode);
+
+                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
+                    {
+                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
+                    });
+
+                    var resetFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        [ConditionalFact]
+        [RequiresNewHandler]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_DuringResponseBody_Resets()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_DuringResponseBody_Resets"), endStream: true);
+
+                    // This is currently flaky, can either receive header or reset at this point
+                    var headerOrResetFrame = await h2Connection.ReceiveFrameAsync();
+                    Assert.True(headerOrResetFrame.Type == Http2FrameType.HEADERS || headerOrResetFrame.Type == Http2FrameType.RST_STREAM);
+
+                    if (headerOrResetFrame.Type == Http2FrameType.HEADERS)
+                    {
+                        var dataFrame = await h2Connection.ReceiveFrameAsync();
+                        Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: false, length: 11);
+
+                        var resetFrame = await h2Connection.ReceiveFrameAsync();
+                        Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
+                    }
+                    else
+                    {
+                        Http2Utilities.VerifyResetFrame(headerOrResetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
+                    }
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+
+        [ConditionalFact]
+        [RequiresNewHandler]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_BeforeRequestBody_Resets()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetPostHeaders("/Reset_BeforeRequestBody_Resets"), endStream: false);
+
+                    // Any app errors?
+                    //Assert.Equal(0, await appResult.Task.DefaultTimeout());
+
+                    var resetFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        [ConditionalFact]
+        [RequiresNewHandler]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_DuringRequestBody_Resets()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetPostHeaders("/Reset_DuringRequestBody_Resets"), endStream: false);
+                    await h2Connection.SendDataAsync(1, new byte[10], endStream: false);
+
+                    // Any app errors?
+                    //Assert.Equal(0, await appResult.Task.DefaultTimeout());
+
+                    var resetFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: (Http2ErrorCode)1111);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_AfterCompleteAsync_NoReset()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetHeaders("/Reset_AfterCompleteAsync_NoReset"), endStream: true);
+
+                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
+                    {
+                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
+                    });
+
+                    var dataFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: false, length: 11);
+
+                    dataFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: true, length: 0);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        [ConditionalFact]
+        [MinimumOSVersion(OperatingSystems.Windows, WindowsVersionForTrailers)]
+        public async Task Reset_CompleteAsyncDuringRequestBody_Resets()
+        {
+            await new HostBuilder()
+                .UseHttp2Cat(Fixture.Client.BaseAddress.AbsoluteUri, async h2Connection =>
+                {
+                    await h2Connection.InitializeConnectionAsync();
+
+                    h2Connection.Logger.LogInformation("Initialized http2 connection. Starting stream 1.");
+
+                    await h2Connection.StartStreamAsync(1, GetPostHeaders("/Reset_CompleteAsyncDuringRequestBody_Resets"), endStream: false);
+                    await h2Connection.SendDataAsync(1, new byte[10], endStream: false);
+
+                    await h2Connection.ReceiveHeadersAsync(1, decodedHeaders =>
+                    {
+                        Assert.Equal("200", decodedHeaders[HeaderNames.Status]);
+                    });
+
+                    var dataFrame = await h2Connection.ReceiveFrameAsync();
+
+                    Http2Utilities.VerifyDataFrame(dataFrame, 1, endOfStream: true, length: 0);
+
+                    var resetFrame = await h2Connection.ReceiveFrameAsync();
+                    Http2Utilities.VerifyResetFrame(resetFrame, expectedStreamId: 1, expectedErrorCode: Http2ErrorCode.NO_ERROR);
+
+                    h2Connection.Logger.LogInformation("Connection stopped.");
+                })
+                .Build().RunAsync();
+        }
+
+        private static List<KeyValuePair<string, string>> GetHeaders(string path)
+        {
+            var headers = Headers.ToList();
+
+            var kvp = new KeyValuePair<string, string>(HeaderNames.Path, path);
+            headers.Add(kvp);
+            return headers;
+        }
+
+        private static List<KeyValuePair<string, string>> GetPostHeaders(string path)
+        {
+            var headers = PostRequestHeaders.ToList();
+
+            var kvp = new KeyValuePair<string, string>(HeaderNames.Path, path);
+            headers.Add(kvp);
+            return headers;
+        }
+
+        private static HttpClient CreateClient()
+        {
+            var handler = new HttpClientHandler();
+            handler.MaxResponseHeadersLength = 128;
+            handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
+            var client = new HttpClient(handler);
+            return client;
+        }
+
+        private async Task<HttpResponseMessage> SendRequestAsync(string uri, bool http2 = true)
+        {
+            var handler = new HttpClientHandler();
+            handler.MaxResponseHeadersLength = 128;
+            handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
+            using var client = new HttpClient(handler);
+            client.DefaultRequestVersion = http2 ? HttpVersion.Version20 : HttpVersion.Version11;
+            return await client.GetAsync(uri);
+        }
+
+        private static readonly IEnumerable<KeyValuePair<string, string>> Headers = new[]
+        {
+            new KeyValuePair<string, string>(HeaderNames.Method, "GET"),
+            new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
+            new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:443"),
+            new KeyValuePair<string, string>("user-agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0"),
+            new KeyValuePair<string, string>("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"),
+            new KeyValuePair<string, string>("accept-language", "en-US,en;q=0.5"),
+            new KeyValuePair<string, string>("accept-encoding", "gzip, deflate, br"),
+            new KeyValuePair<string, string>("upgrade-insecure-requests", "1"),
+        };
+
+        private static readonly IEnumerable<KeyValuePair<string, string>> PostRequestHeaders = new[]
+        {
+            new KeyValuePair<string, string>(HeaderNames.Method, "POST"),
+            new KeyValuePair<string, string>(HeaderNames.Scheme, "https"),
+            new KeyValuePair<string, string>(HeaderNames.Authority, "localhost:80"),
+        };
+    }
+}

+ 7 - 2
src/Testing/src/xunit/WindowsVersions.cs

@@ -42,8 +42,13 @@ namespace Microsoft.AspNetCore.Testing
         public const string Win10_19H2 = "10.0.18363";
         public const string Win10_19H2 = "10.0.18363";
 
 
         /// <summary>
         /// <summary>
-        /// 2004, 20H1, 19033
+        /// 2004, 20H1, 19041
         /// </summary>
         /// </summary>
-        public const string Win10_20H1 = "10.0.19033";
+        public const string Win10_20H1 = "10.0.19041";
+
+        /// <summary>
+        /// 20H2, 19042
+        /// </summary>
+        public const string Win10_20H2 = "10.0.19042";
     }
     }
 }
 }