diff --git a/.azure/pipelines/ci.yml b/.azure/pipelines/ci.yml
index 0395418fe330..886ccb870b45 100644
--- a/.azure/pipelines/ci.yml
+++ b/.azure/pipelines/ci.yml
@@ -138,6 +138,10 @@ extends:
os: windows
spotBugs:
enabled: false
+ policheck:
+ enabled: true
+ tsa:
+ enabled: true
containers:
alpine319WithNode:
image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.19-WithNode
diff --git a/NuGet.config b/NuGet.config
index 1ccd39949f02..bad334e8c9b3 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -6,10 +6,11 @@
-
+
-
+
+
@@ -36,7 +37,7 @@
-
+
@@ -45,7 +46,8 @@
-
+
+
diff --git a/eng/Baseline.Designer.props b/eng/Baseline.Designer.props
index fdced6323d23..d0138a65e8de 100644
--- a/eng/Baseline.Designer.props
+++ b/eng/Baseline.Designer.props
@@ -2,117 +2,117 @@
$(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
@@ -120,281 +120,281 @@
- 8.0.8
+ 8.0.10
-
-
+
+
-
-
+
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
+
-
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
-
-
-
-
+
+
+
+
- 8.0.8
+ 8.0.10
-
-
+
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
-
+
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
-
-
+
+
-
-
+
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
@@ -403,79 +403,79 @@
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
-
+
+
-
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
-
-
+
+
- 8.0.8
+ 8.0.10
@@ -491,192 +491,192 @@
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
-
-
+
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
-
+
+
-
-
+
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
-
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
-
-
-
+
+
+
+
- 8.0.8
+ 8.0.10
@@ -685,64 +685,64 @@
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
@@ -764,29 +764,29 @@
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
@@ -802,48 +802,48 @@
- 8.0.8
+ 8.0.10
-
+
-
-
+
+
-
-
-
+
+
+
-
+
-
-
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
-
-
+
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
@@ -853,144 +853,144 @@
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
-
-
+
+
-
-
+
+
-
-
+
+
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
-
+
-
+
- 8.0.8
+ 8.0.10
- 8.0.8
+ 8.0.10
-
+
- 8.0.8
+ 8.0.10
diff --git a/eng/Baseline.xml b/eng/Baseline.xml
index 199a62d5c74a..b69677446aba 100644
--- a/eng/Baseline.xml
+++ b/eng/Baseline.xml
@@ -4,110 +4,110 @@ This file contains a list of all the packages and their versions which were rele
Update this list when preparing for a new patch.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 830dd83228e5..08f471a66db1 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,37 +9,37 @@
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- 4315fa43c9573671f8f5be21497d59f9c99cd829
+ 5d020e763f00511c102f94fdf5bf525512d7daaf
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -121,9 +121,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -185,13 +185,13 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
-
+
https://github.com/dotnet/source-build-externals
- fb970eccb0a9cae3092464e29cbabda0d4115049
+ d4feb7e49067fc9bbf7dfb9fa76a326c33fa0595
@@ -275,17 +275,17 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
81cabf2857a01351e5ab578947c7403a5b128ad1
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -316,22 +316,22 @@
Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime.
All Runtime.$rid packages should have the same version.
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
https://github.com/dotnet/xdt
@@ -368,34 +368,34 @@
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 81cabf2857a01351e5ab578947c7403a5b128ad1
+ 9cb3b725e3ad2b57ddc9fb2dd48d2d170563a8f5
https://github.com/dotnet/winforms
abda8e3bfa78319363526b5a5f86863ec979940e
-
+
https://github.com/dotnet/arcade
- 80264e60280e2815e7d65871081ccac04a32445c
+ f7fb1fec01b91be69e4dcc5290a0bff3f28e214f
-
+
https://github.com/dotnet/arcade
- 80264e60280e2815e7d65871081ccac04a32445c
+ f7fb1fec01b91be69e4dcc5290a0bff3f28e214f
-
+
https://github.com/dotnet/arcade
- 80264e60280e2815e7d65871081ccac04a32445c
+ f7fb1fec01b91be69e4dcc5290a0bff3f28e214f
-
+
https://github.com/dotnet/arcade
- 80264e60280e2815e7d65871081ccac04a32445c
+ f7fb1fec01b91be69e4dcc5290a0bff3f28e214f
-
+
https://github.com/dotnet/arcade
- 80264e60280e2815e7d65871081ccac04a32445c
+ f7fb1fec01b91be69e4dcc5290a0bff3f28e214f
https://github.com/dotnet/extensions
diff --git a/eng/Versions.props b/eng/Versions.props
index 02c0d42b1a5d..f89dc61bace1 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,10 +8,10 @@
8
0
- 10
+ 11
- false
+ true
7.1.2
7.*
8.0.2
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10-servicing.24466.10
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11-servicing.24517.7
8.0.0
8.0.1
8.0.0
@@ -93,7 +93,7 @@
8.0.0
8.0.0
8.0.0
- 8.0.10-servicing.24466.10
+ 8.0.11-servicing.24517.7
8.0.1
8.0.1
8.0.1
@@ -109,7 +109,7 @@
8.0.0
8.0.2
8.0.0
- 8.0.10-servicing.24466.10
+ 8.0.11-servicing.24517.7
8.0.1
8.0.1
8.0.1
@@ -129,9 +129,9 @@
8.0.0
8.0.0
8.0.0
- 8.0.10-servicing.24466.10
+ 8.0.11-servicing.24517.7
- 8.0.10-servicing.24466.10
+ 8.0.11-servicing.24517.7
8.0.0
8.0.1
@@ -143,14 +143,14 @@
8.1.0-preview.23604.1
8.1.0-preview.23604.1
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10
- 8.0.10
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11
+ 8.0.11
4.8.0-3.23518.7
4.8.0-3.23518.7
@@ -162,11 +162,11 @@
6.2.4
6.2.4
- 8.0.0-beta.24426.2
- 8.0.0-beta.24426.2
- 8.0.0-beta.24426.2
+ 8.0.0-beta.24516.1
+ 8.0.0-beta.24516.1
+ 8.0.0-beta.24516.1
- 8.0.0-alpha.1.24379.1
+ 8.0.0-alpha.1.24510.2
8.0.0-alpha.1.24415.1
@@ -300,10 +300,10 @@
2.57.0
2.57.0
2.5.108
- 2.15.2
- 2.15.2
- 2.15.2
- 2.15.2
+ 3.2.0
+ 3.2.0
+ 3.2.0
+ 3.2.0
6.0.1
$(MessagePackVersion)
4.10.0
diff --git a/eng/common/templates-official/steps/get-delegation-sas.yml b/eng/common/templates-official/steps/get-delegation-sas.yml
index c0e8f91317f0..c690cc0a070c 100644
--- a/eng/common/templates-official/steps/get-delegation-sas.yml
+++ b/eng/common/templates-official/steps/get-delegation-sas.yml
@@ -28,7 +28,16 @@ steps:
# Calculate the expiration of the SAS token and convert to UTC
$expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
- $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv
+ # Temporarily work around a helix issue where SAS tokens with / in them will cause incorrect downloads
+ # of correlation payloads. https://github.com/dotnet/dnceng/issues/3484
+ $sas = ""
+ do {
+ $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error "Failed to generate SAS token."
+ exit 1
+ }
+ } while($sas.IndexOf('/') -ne -1)
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to generate SAS token."
diff --git a/eng/common/templates/steps/get-delegation-sas.yml b/eng/common/templates/steps/get-delegation-sas.yml
index c0e8f91317f0..c690cc0a070c 100644
--- a/eng/common/templates/steps/get-delegation-sas.yml
+++ b/eng/common/templates/steps/get-delegation-sas.yml
@@ -28,7 +28,16 @@ steps:
# Calculate the expiration of the SAS token and convert to UTC
$expiry = (Get-Date).AddHours(${{ parameters.expiryInHours }}).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
- $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv
+ # Temporarily work around a helix issue where SAS tokens with / in them will cause incorrect downloads
+ # of correlation payloads. https://github.com/dotnet/dnceng/issues/3484
+ $sas = ""
+ do {
+ $sas = az storage container generate-sas --account-name ${{ parameters.storageAccount }} --name ${{ parameters.container }} --permissions ${{ parameters.permissions }} --expiry $expiry --auth-mode login --as-user -o tsv
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error "Failed to generate SAS token."
+ exit 1
+ }
+ } while($sas.IndexOf('/') -ne -1)
if ($LASTEXITCODE -ne 0) {
Write-Error "Failed to generate SAS token."
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index eb188cfda415..a2dedaa5297a 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -892,7 +892,7 @@ function IsWindowsPlatform() {
}
function Get-Darc($version) {
- $darcPath = "$TempDir\darc\$(New-Guid)"
+ $darcPath = "$TempDir\darc\$([guid]::NewGuid())"
if ($version -ne $null) {
& $PSScriptRoot\darc-init.ps1 -toolpath $darcPath -darcVersion $version | Out-Host
} else {
diff --git a/eng/targets/Helix.Common.props b/eng/targets/Helix.Common.props
index 426386e98ebf..452702d612b0 100644
--- a/eng/targets/Helix.Common.props
+++ b/eng/targets/Helix.Common.props
@@ -49,7 +49,7 @@
-
+
diff --git a/global.json b/global.json
index a9a6de59b508..cbc2adc9d22b 100644
--- a/global.json
+++ b/global.json
@@ -1,9 +1,9 @@
{
"sdk": {
- "version": "8.0.108"
+ "version": "8.0.110"
},
"tools": {
- "dotnet": "8.0.108",
+ "dotnet": "8.0.110",
"runtimes": {
"dotnet/x86": [
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
@@ -27,7 +27,7 @@
},
"msbuild-sdks": {
"Yarn.MSBuild": "1.22.19",
- "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24426.2",
- "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24426.2"
+ "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24516.1",
+ "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24516.1"
}
}
diff --git a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
index 82a882f7025a..8d928403297c 100644
--- a/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
+++ b/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
@@ -533,6 +533,11 @@ private static Expression MapHandlerReturnTypeToValueTask(Expression methodCall,
}
else
{
+ if (returnType.IsValueType)
+ {
+ return Expression.Call(WrapObjectAsValueTaskMethod, Expression.Convert(methodCall, typeof(object)));
+ }
+
return Expression.Call(WrapObjectAsValueTaskMethod, methodCall);
}
}
diff --git a/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.EndpointFilters.cs b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.EndpointFilters.cs
new file mode 100644
index 000000000000..b2a223b345e3
--- /dev/null
+++ b/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.EndpointFilters.cs
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Testing;
+
+namespace Microsoft.AspNetCore.Routing.Internal;
+
+public partial class RequestDelegateFactoryTests : LoggedTest
+{
+ public static object[][] ValueTypeReturningDelegates =>
+ [
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 'b')],
+ [(Func)((HttpContext httpContext) => true)],
+ [(Func)((HttpContext httpContext) => 4.2f)],
+ [(Func)((HttpContext httpContext) => 4.2)],
+ [(Func)((HttpContext httpContext) => 4.2m)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)]
+ ];
+
+ [Theory]
+ [MemberData(nameof(ValueTypeReturningDelegates))]
+ public void Create_WithEndpointFilterOnBuiltInValueTypeReturningDelegate_Works(Delegate @delegate)
+ {
+ var invokeCount = 0;
+
+ RequestDelegateFactoryOptions options = new()
+ {
+ EndpointBuilder = CreateEndpointBuilderFromFilterFactories(
+ [
+ (routeHandlerContext, next) =>
+ {
+ invokeCount++;
+ return next;
+ },
+ (routeHandlerContext, next) =>
+ {
+ invokeCount++;
+ return next;
+ },
+ ]),
+ };
+
+ var result = RequestDelegateFactory.Create(@delegate, options);
+ Assert.Equal(2, invokeCount);
+ }
+
+ public static object[][] NullableValueTypeReturningDelegates =>
+ [
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 'b')],
+ [(Func)((HttpContext httpContext) => true)],
+ [(Func)((HttpContext httpContext) => 4.2f)],
+ [(Func)((HttpContext httpContext) => 4.2)],
+ [(Func)((HttpContext httpContext) => 4.2m)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)],
+ [(Func)((HttpContext httpContext) => 42)]
+ ];
+
+ [Theory]
+ [MemberData(nameof(NullableValueTypeReturningDelegates))]
+ public void Create_WithEndpointFilterOnNullableBuiltInValueTypeReturningDelegate_Works(Delegate @delegate)
+ {
+ var invokeCount = 0;
+
+ RequestDelegateFactoryOptions options = new()
+ {
+ EndpointBuilder = CreateEndpointBuilderFromFilterFactories(
+ [
+ (routeHandlerContext, next) =>
+ {
+ invokeCount++;
+ return next;
+ },
+ (routeHandlerContext, next) =>
+ {
+ invokeCount++;
+ return next;
+ },
+ ]),
+ };
+
+ var result = RequestDelegateFactory.Create(@delegate, options);
+ Assert.Equal(2, invokeCount);
+ }
+}
diff --git a/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
index f0508bc3b611..52e85b9a96ce 100644
--- a/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
+++ b/src/Installers/Windows/SharedFrameworkBundle/Bundle.wxs
@@ -1,5 +1,6 @@
-
+
+
+
+
+
diff --git a/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj b/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
index e7c93b5ecba8..5f47072f1fee 100644
--- a/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
+++ b/src/Installers/Windows/SharedFrameworkBundle/SharedFrameworkBundle.wixproj
@@ -13,6 +13,10 @@
+
+ $(WixExtDir)\WixUtilExtension.dll
+ WixUtilExtension
+
$(WixExtDir)\WixDependencyExtension.dll
WixDependencyExtension
@@ -25,6 +29,7 @@
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/Bundle.wxs b/src/Installers/Windows/WindowsHostingBundle/Bundle.wxs
index 429c66c241a3..dd23ad4ee5d4 100644
--- a/src/Installers/Windows/WindowsHostingBundle/Bundle.wxs
+++ b/src/Installers/Windows/WindowsHostingBundle/Bundle.wxs
@@ -1,8 +1,7 @@
-
+
+
+
+
+
+
diff --git a/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj b/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj
index cfb32de2dc5d..2e5c010ed0e7 100644
--- a/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj
+++ b/src/Installers/Windows/WindowsHostingBundle/WindowsHostingBundle.wixproj
@@ -36,6 +36,7 @@
+
diff --git a/src/Installers/Windows/Wix.targets b/src/Installers/Windows/Wix.targets
index 0eff14c4f883..6cab47f1059a 100644
--- a/src/Installers/Windows/Wix.targets
+++ b/src/Installers/Windows/Wix.targets
@@ -110,7 +110,7 @@
NoLogo="true"
Cultures="en-us"
InstallerFile="%(WixInstallerFilesToProcess.Identity)"
- AdditionalBasePaths="$(MSBuildProjectDirectory)"
+ AdditionalBasePaths="$(MSBuildProjectDirectory);$(PkgMicrosoft_DotNet_Build_Tasks_Installers)\build\wix\bundle"
WixExtensions="@(WixExtension)"
Loc="@(EmbeddedResource)"
Sice="$(SuppressIces)"
diff --git a/src/Servers/HttpSys/src/LoggerEventIds.cs b/src/Servers/HttpSys/src/LoggerEventIds.cs
index 87f8ea56ee9f..5bc0b6b65ed6 100644
--- a/src/Servers/HttpSys/src/LoggerEventIds.cs
+++ b/src/Servers/HttpSys/src/LoggerEventIds.cs
@@ -58,4 +58,5 @@ internal static class LoggerEventIds
public const int AcceptSetExpectationMismatch = 51;
public const int AcceptCancelExpectationMismatch = 52;
public const int AcceptObserveExpectationMismatch = 53;
+ public const int RequestParsingError = 54;
}
diff --git a/src/Servers/HttpSys/src/RequestProcessing/Request.cs b/src/Servers/HttpSys/src/RequestProcessing/Request.cs
index 0b9418cbcac6..6029f8269f53 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/Request.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/Request.cs
@@ -37,145 +37,152 @@ internal Request(RequestContext requestContext)
{
// TODO: Verbose log
RequestContext = requestContext;
- _contentBoundaryType = BoundaryType.None;
- RequestId = requestContext.RequestId;
- // For HTTP/2 Http.Sys assigns each request a unique connection id for use with API calls, but the RawConnectionId represents the real connection.
- UConnectionId = requestContext.ConnectionId;
- RawConnectionId = requestContext.RawConnectionId;
- SslStatus = requestContext.SslStatus;
+ try
+ {
+ _contentBoundaryType = BoundaryType.None;
- KnownMethod = requestContext.VerbId;
- Method = requestContext.GetVerb()!;
+ RequestId = requestContext.RequestId;
+ // For HTTP/2 Http.Sys assigns each request a unique connection id for use with API calls, but the RawConnectionId represents the real connection.
+ UConnectionId = requestContext.ConnectionId;
+ RawConnectionId = requestContext.RawConnectionId;
+ SslStatus = requestContext.SslStatus;
- RawUrl = requestContext.GetRawUrl()!;
+ KnownMethod = requestContext.VerbId;
+ Method = requestContext.GetVerb()!;
- var cookedUrl = requestContext.GetCookedUrl();
- QueryString = cookedUrl.GetQueryString() ?? string.Empty;
+ RawUrl = requestContext.GetRawUrl()!;
- var rawUrlInBytes = requestContext.GetRawUrlInBytes();
- var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes);
+ var cookedUrl = requestContext.GetCookedUrl();
+ QueryString = cookedUrl.GetQueryString() ?? string.Empty;
- PathBase = string.Empty;
- Path = originalPath;
- var prefix = requestContext.Server.Options.UrlPrefixes.GetPrefix((int)requestContext.UrlContext);
+ var rawUrlInBytes = requestContext.GetRawUrlInBytes();
+ var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes);
- // 'OPTIONS * HTTP/1.1'
- if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal))
- {
PathBase = string.Empty;
- Path = string.Empty;
- }
- // Prefix may be null if the requested has been transfered to our queue
- else if (prefix is not null)
- {
- var pathBase = prefix.PathWithoutTrailingSlash;
+ Path = originalPath;
+ var prefix = requestContext.Server.Options.UrlPrefixes.GetPrefix((int)requestContext.UrlContext);
- // url: /base/path, prefix: /base/, base: /base, path: /path
- // url: /, prefix: /, base: , path: /
- if (originalPath.Equals(pathBase, StringComparison.Ordinal))
- {
- // Exact match, no need to preserve the casing
- PathBase = pathBase;
- Path = string.Empty;
- }
- else if (originalPath.Equals(pathBase, StringComparison.OrdinalIgnoreCase))
+ // 'OPTIONS * HTTP/1.1'
+ if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal))
{
- // Preserve the user input casing
- PathBase = originalPath;
+ PathBase = string.Empty;
Path = string.Empty;
}
- else if (originalPath.StartsWith(prefix.Path, StringComparison.Ordinal))
- {
- // Exact match, no need to preserve the casing
- PathBase = pathBase;
- Path = originalPath[pathBase.Length..];
- }
- else if (originalPath.StartsWith(prefix.Path, StringComparison.OrdinalIgnoreCase))
+ // Prefix may be null if the requested has been transferred to our queue
+ else if (prefix is not null)
{
- // Preserve the user input casing
- PathBase = originalPath[..pathBase.Length];
- Path = originalPath[pathBase.Length..];
- }
- else
- {
- // Http.Sys path base matching is based on the cooked url which applies some non-standard normalizations that we don't use
- // like collapsing duplicate slashes "//", converting '\' to '/', and un-escaping "%2F" to '/'. Find the right split and
- // ignore the normalizations.
- var originalOffset = 0;
- var baseOffset = 0;
- while (originalOffset < originalPath.Length && baseOffset < pathBase.Length)
+ var pathBase = prefix.PathWithoutTrailingSlash;
+
+ // url: /base/path, prefix: /base/, base: /base, path: /path
+ // url: /, prefix: /, base: , path: /
+ if (originalPath.Equals(pathBase, StringComparison.Ordinal))
{
- var baseValue = pathBase[baseOffset];
- var offsetValue = originalPath[originalOffset];
- if (baseValue == offsetValue
- || char.ToUpperInvariant(baseValue) == char.ToUpperInvariant(offsetValue))
- {
- // case-insensitive match, continue
- originalOffset++;
- baseOffset++;
- }
- else if (baseValue == '/' && offsetValue == '\\')
- {
- // Http.Sys considers these equivalent
- originalOffset++;
- baseOffset++;
- }
- else if (baseValue == '/' && originalPath.AsSpan(originalOffset).StartsWith("%2F", StringComparison.OrdinalIgnoreCase))
- {
- // Http.Sys un-escapes this
- originalOffset += 3;
- baseOffset++;
- }
- else if (baseOffset > 0 && pathBase[baseOffset - 1] == '/'
- && (offsetValue == '/' || offsetValue == '\\'))
- {
- // Duplicate slash, skip
- originalOffset++;
- }
- else if (baseOffset > 0 && pathBase[baseOffset - 1] == '/'
- && originalPath.AsSpan(originalOffset).StartsWith("%2F", StringComparison.OrdinalIgnoreCase))
- {
- // Duplicate slash equivalent, skip
- originalOffset += 3;
- }
- else
+ // Exact match, no need to preserve the casing
+ PathBase = pathBase;
+ Path = string.Empty;
+ }
+ else if (originalPath.Equals(pathBase, StringComparison.OrdinalIgnoreCase))
+ {
+ // Preserve the user input casing
+ PathBase = originalPath;
+ Path = string.Empty;
+ }
+ else if (originalPath.StartsWith(prefix.Path, StringComparison.Ordinal))
+ {
+ // Exact match, no need to preserve the casing
+ PathBase = pathBase;
+ Path = originalPath[pathBase.Length..];
+ }
+ else if (originalPath.StartsWith(prefix.Path, StringComparison.OrdinalIgnoreCase))
+ {
+ // Preserve the user input casing
+ PathBase = originalPath[..pathBase.Length];
+ Path = originalPath[pathBase.Length..];
+ }
+ else
+ {
+ // Http.Sys path base matching is based on the cooked url which applies some non-standard normalizations that we don't use
+ // like collapsing duplicate slashes "//", converting '\' to '/', and un-escaping "%2F" to '/'. Find the right split and
+ // ignore the normalizations.
+ var originalOffset = 0;
+ var baseOffset = 0;
+ while (originalOffset < originalPath.Length && baseOffset < pathBase.Length)
{
- // Mismatch, fall back
- // The failing test case here is "/base/call//../bat//path1//path2", reduced to "/base/call/bat//path1//path2",
- // where http.sys collapses "//" before "../", but we do "../" first. We've lost the context that there were dot segments,
- // or duplicate slashes, how do we figure out that "call/" can be eliminated?
- originalOffset = 0;
- break;
+ var baseValue = pathBase[baseOffset];
+ var offsetValue = originalPath[originalOffset];
+ if (baseValue == offsetValue
+ || char.ToUpperInvariant(baseValue) == char.ToUpperInvariant(offsetValue))
+ {
+ // case-insensitive match, continue
+ originalOffset++;
+ baseOffset++;
+ }
+ else if (baseValue == '/' && offsetValue == '\\')
+ {
+ // Http.Sys considers these equivalent
+ originalOffset++;
+ baseOffset++;
+ }
+ else if (baseValue == '/' && originalPath.AsSpan(originalOffset).StartsWith("%2F", StringComparison.OrdinalIgnoreCase))
+ {
+ // Http.Sys un-escapes this
+ originalOffset += 3;
+ baseOffset++;
+ }
+ else if (baseOffset > 0 && pathBase[baseOffset - 1] == '/'
+ && (offsetValue == '/' || offsetValue == '\\'))
+ {
+ // Duplicate slash, skip
+ originalOffset++;
+ }
+ else if (baseOffset > 0 && pathBase[baseOffset - 1] == '/'
+ && originalPath.AsSpan(originalOffset).StartsWith("%2F", StringComparison.OrdinalIgnoreCase))
+ {
+ // Duplicate slash equivalent, skip
+ originalOffset += 3;
+ }
+ else
+ {
+ // Mismatch, fall back
+ // The failing test case here is "/base/call//../bat//path1//path2", reduced to "/base/call/bat//path1//path2",
+ // where http.sys collapses "//" before "../", but we do "../" first. We've lost the context that there were dot segments,
+ // or duplicate slashes, how do we figure out that "call/" can be eliminated?
+ originalOffset = 0;
+ break;
+ }
}
+ PathBase = originalPath[..originalOffset];
+ Path = originalPath[originalOffset..];
}
- PathBase = originalPath[..originalOffset];
- Path = originalPath[originalOffset..];
}
- }
- else if (requestContext.Server.Options.UrlPrefixes.TryMatchLongestPrefix(IsHttps, cookedUrl.GetHost()!, originalPath, out var pathBase, out var path))
- {
- PathBase = pathBase;
- Path = path;
- }
+ else if (requestContext.Server.Options.UrlPrefixes.TryMatchLongestPrefix(IsHttps, cookedUrl.GetHost()!, originalPath, out var pathBase, out var path))
+ {
+ PathBase = pathBase;
+ Path = path;
+ }
- ProtocolVersion = RequestContext.GetVersion();
+ ProtocolVersion = RequestContext.GetVersion();
- Headers = new RequestHeaders(RequestContext);
+ Headers = new RequestHeaders(RequestContext);
- User = RequestContext.GetUser();
+ User = RequestContext.GetUser();
- SniHostName = string.Empty;
- if (IsHttps)
- {
- GetTlsHandshakeResults();
- }
+ SniHostName = string.Empty;
+ if (IsHttps)
+ {
+ GetTlsHandshakeResults();
+ }
- // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/HttpSysServer/issues/231
+ // GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/HttpSysServer/issues/231
- // Finished directly accessing the HTTP_REQUEST structure.
- RequestContext.ReleasePins();
- // TODO: Verbose log parameters
+ }
+ finally
+ {
+ // Finished directly accessing the HTTP_REQUEST structure.
+ RequestContext.ReleasePins();
+ // TODO: Verbose log parameters
+ }
RemoveContentLengthIfTransferEncodingContainsChunked();
}
diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.FeatureCollection.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.FeatureCollection.cs
index 2671bc71c8bb..e1931dc0fc6b 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.FeatureCollection.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.FeatureCollection.cs
@@ -64,6 +64,7 @@ internal partial class RequestContext :
private bool _bodyCompleted;
private IHeaderDictionary _responseHeaders = default!;
private IHeaderDictionary? _responseTrailers;
+ private ulong? _requestId;
private Fields _initializedFields;
@@ -98,11 +99,26 @@ private enum Fields
TraceIdentifier = 0x200,
}
- protected internal void InitializeFeatures()
+ protected internal bool InitializeFeatures()
{
_initialized = true;
- Request = new Request(this);
+ // Get the ID before creating the Request object as the Request ctor releases the native memory
+ // We want the ID in case request processing fails and we need the ID to cancel the native request
+ _requestId = RequestId;
+ try
+ {
+ Request = new Request(this);
+ }
+ catch (Exception ex)
+ {
+ Log.RequestParsingError(Logger, ex);
+ // Synchronously calls Http.Sys and tells it to send an http response
+ // No one has written to the response yet (haven't even created the response object below)
+ Server.SendError(_requestId.Value, StatusCodes.Status400BadRequest, authChallenges: null);
+ return false;
+ }
+
Response = new Response(this);
_features = new FeatureCollection(new StandardFeatureCollection(this));
@@ -124,6 +140,7 @@ protected internal void InitializeFeatures()
_responseStream = new ResponseStream(Response.Body, OnResponseStart);
_responseHeaders = Response.Headers;
+ return true;
}
private bool IsNotInitialized(Fields field)
diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.Log.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.Log.cs
index 2c587b98a401..41b1cf480d5a 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.Log.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.Log.cs
@@ -17,5 +17,8 @@ private static partial class Log
[LoggerMessage(LoggerEventIds.ChannelBindingRetrieved, LogLevel.Debug, "Channel binding retrieved.", EventName = "ChannelBindingRetrieved")]
public static partial void ChannelBindingRetrieved(ILogger logger);
+
+ [LoggerMessage(LoggerEventIds.RequestParsingError, LogLevel.Debug, "Failed to parse request.", EventName = "RequestParsingError")]
+ public static partial void RequestParsingError(ILogger logger, Exception exception);
}
}
diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs
index 8da0c7a33e37..e9f277b6a990 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/RequestContext.cs
@@ -187,9 +187,11 @@ public void Abort()
_disconnectToken = new CancellationToken(canceled: true);
}
ForceCancelRequest();
- Request.Dispose();
+ // Request and/or Response can be null (even though the property doesn't say it can)
+ // if the constructor throws (can happen for invalid path format)
+ Request?.Dispose();
// Only Abort, Response.Dispose() tries a graceful flush
- Response.Abort();
+ Response?.Abort();
}
private static void Abort(object? state)
@@ -208,15 +210,22 @@ internal void ForceCancelRequest()
{
try
{
+ // Shouldn't be able to get here when this is null, but just in case we'll noop
+ if (_requestId is null)
+ {
+ return;
+ }
+
var statusCode = HttpApi.HttpCancelHttpRequest(Server.RequestQueue.Handle,
- Request.RequestId, IntPtr.Zero);
+ _requestId.Value, default);
// Either the connection has already dropped, or the last write is in progress.
// The requestId becomes invalid as soon as the last Content-Length write starts.
// The only way to cancel now is with CancelIoEx.
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID)
{
- Response.CancelLastWrite();
+ // Can be null if processing the request threw and the response object was never created.
+ Response?.CancelLastWrite();
}
}
catch (ObjectDisposedException)
diff --git a/src/Servers/HttpSys/src/RequestProcessing/RequestContextOfT.cs b/src/Servers/HttpSys/src/RequestProcessing/RequestContextOfT.cs
index f661bf1fd018..2a1d06a06d26 100644
--- a/src/Servers/HttpSys/src/RequestProcessing/RequestContextOfT.cs
+++ b/src/Servers/HttpSys/src/RequestProcessing/RequestContextOfT.cs
@@ -27,7 +27,11 @@ public override async Task ExecuteAsync()
try
{
- InitializeFeatures();
+ if (!InitializeFeatures())
+ {
+ Abort();
+ return;
+ }
if (messagePump.Stopping)
{
diff --git a/src/Servers/HttpSys/test/FunctionalTests/Listener/RequestTests.cs b/src/Servers/HttpSys/test/FunctionalTests/Listener/RequestTests.cs
index 79e1c361380d..0cd4b08086a6 100644
--- a/src/Servers/HttpSys/test/FunctionalTests/Listener/RequestTests.cs
+++ b/src/Servers/HttpSys/test/FunctionalTests/Listener/RequestTests.cs
@@ -1,15 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.IO;
-using System.Net.Http;
using System.Net.Sockets;
using System.Text;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Testing;
-using Microsoft.Extensions.Logging;
-using Xunit;
namespace Microsoft.AspNetCore.Server.HttpSys.Listener;
@@ -142,6 +136,7 @@ public async Task Request_OverlongUTF8Path(string requestPath, string expectedPa
[InlineData("/", "/", "", "/")]
[InlineData("/base", "/base", "/base", "")]
[InlineData("/base", "/baSe", "/baSe", "")]
+ [InlineData("/base", "/baSe/", "/baSe", "/")]
[InlineData("/base", "/base/path", "/base", "/path")]
[InlineData("/base", "///base/path1/path2", "///base", "/path1/path2")]
[InlineData("/base/ball", @"/baSe\ball//path1//path2", @"/baSe\ball", "//path1//path2")]
diff --git a/src/Servers/HttpSys/test/FunctionalTests/RequestTests.cs b/src/Servers/HttpSys/test/FunctionalTests/RequestTests.cs
index 51eed9b46948..e3f86544e89f 100644
--- a/src/Servers/HttpSys/test/FunctionalTests/RequestTests.cs
+++ b/src/Servers/HttpSys/test/FunctionalTests/RequestTests.cs
@@ -1,24 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.Globalization;
-using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.HttpSys.Internal;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
-using Xunit;
namespace Microsoft.AspNetCore.Server.HttpSys;
@@ -368,6 +361,43 @@ public async Task Request_UrlUnescaping()
}
}
+ [Fact]
+ public async Task Latin1UrlIsRejected()
+ {
+ string root;
+ using (var server = Utilities.CreateHttpServerReturnRoot("/", out root, httpContext =>
+ {
+ Assert.Fail("Request should not reach here");
+ return Task.FromResult(0);
+ }, LoggerFactory))
+ {
+ var uri = new Uri(root);
+ StringBuilder builder = new StringBuilder();
+ builder.AppendLine(FormattableString.Invariant($"GET /a HTTP/1.1"));
+ builder.AppendLine("Connection: close");
+ builder.Append("HOST: ");
+ builder.AppendLine(uri.Authority);
+ builder.AppendLine();
+ byte[] request = Encoding.ASCII.GetBytes(builder.ToString());
+ // Replace the 'a' in the path with a Latin1 value
+ request[5] = 0xe1;
+
+ using (var socket = new Socket(SocketType.Stream, ProtocolType.Tcp))
+ {
+ socket.Connect(uri.Host, uri.Port);
+ socket.Send(request);
+ var response = new byte[12];
+ await Task.Run(() => socket.Receive(response));
+
+ var statusCode = Encoding.UTF8.GetString(response).Substring(9);
+ Assert.Equal("400", statusCode);
+ }
+ }
+
+ var errorLogs = TestSink.Writes.Where(w => w.LogLevel >= LogLevel.Error).Select(w => w.Exception);
+ Assert.False(errorLogs.Any(), string.Join(" ", errorLogs));
+ }
+
[ConditionalFact]
public async Task Request_WithDoubleSlashes_LeftAlone()
{
diff --git a/src/Servers/HttpSys/test/FunctionalTests/ResponseCachingTests.cs b/src/Servers/HttpSys/test/FunctionalTests/ResponseCachingTests.cs
index e0947d2099e6..821d1e86ef18 100644
--- a/src/Servers/HttpSys/test/FunctionalTests/ResponseCachingTests.cs
+++ b/src/Servers/HttpSys/test/FunctionalTests/ResponseCachingTests.cs
@@ -22,8 +22,23 @@ public class ResponseCachingTests : LoggedTest
public ResponseCachingTests()
{
- _absoluteFilePath = Path.Combine(Directory.GetCurrentDirectory(), "Microsoft.AspNetCore.Server.HttpSys.dll");
- _fileLength = new FileInfo(_absoluteFilePath).Length;
+ _absoluteFilePath = Path.Combine(Directory.GetCurrentDirectory(), Path.GetRandomFileName());
+ using var file = File.Create(_absoluteFilePath);
+ // HttpSys will cache responses up to ~260k, keep this value below that
+ // 30k is an arbitrary choice
+ file.Write(new byte[30000]);
+ _fileLength = 30000;
+ }
+
+ public override void Dispose()
+ {
+ try
+ {
+ File.Delete(_absoluteFilePath);
+ }
+ catch { }
+
+ base.Dispose();
}
[ConditionalFact]
diff --git a/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs b/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs
index 7e0c03f9c37f..ce82eddfc5bb 100644
--- a/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs
+++ b/src/Servers/HttpSys/test/FunctionalTests/ResponseSendFileTests.cs
@@ -30,6 +30,7 @@ public ResponseSendFileTests()
AbsoluteFilePath = Directory.GetFiles(Directory.GetCurrentDirectory()).First();
RelativeFilePath = Path.GetFileName(AbsoluteFilePath);
FileLength = new FileInfo(AbsoluteFilePath).Length;
+ Assert.True(FileLength > 0, "FileLength is 0");
}
[ConditionalFact]
diff --git a/src/Shared/CertificateGeneration/CertificateManager.cs b/src/Shared/CertificateGeneration/CertificateManager.cs
index 96e5630c43f1..491eb5adb974 100644
--- a/src/Shared/CertificateGeneration/CertificateManager.cs
+++ b/src/Shared/CertificateGeneration/CertificateManager.cs
@@ -328,6 +328,7 @@ public EnsureCertificateResult EnsureAspNetCoreHttpsDevelopmentCertificate(
var exportDir = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(exportDir) && !Directory.Exists(exportDir))
{
+ result = EnsureCertificateResult.ErrorExportingTheCertificateToNonExistentDirectory;
throw new InvalidOperationException($"The directory '{exportDir}' does not exist. Choose permissions carefully when creating it.");
}
diff --git a/src/Shared/CertificateGeneration/EnsureCertificateResult.cs b/src/Shared/CertificateGeneration/EnsureCertificateResult.cs
index cb6b7e145428..5c28eaca3063 100644
--- a/src/Shared/CertificateGeneration/EnsureCertificateResult.cs
+++ b/src/Shared/CertificateGeneration/EnsureCertificateResult.cs
@@ -10,6 +10,7 @@ internal enum EnsureCertificateResult
ErrorCreatingTheCertificate,
ErrorSavingTheCertificateIntoTheCurrentUserPersonalStore,
ErrorExportingTheCertificate,
+ ErrorExportingTheCertificateToNonExistentDirectory,
FailedToTrustTheCertificate,
PartiallyFailedToTrustTheCertificate,
UserCancelledTrustStep,
diff --git a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs
index 4edd3897b652..f637ecbdc61a 100644
--- a/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs
+++ b/src/Tools/FirstRunCertGenerator/test/CertificateManagerTests.cs
@@ -373,7 +373,7 @@ public void EnsureCreateHttpsCertificate_CannotExportToNonExistentDirectory()
.EnsureAspNetCoreHttpsDevelopmentCertificate(now, now.AddYears(1), Path.Combine("NoSuchDirectory", CertificateName));
// Assert
- Assert.Equal(EnsureCertificateResult.ErrorExportingTheCertificate, result);
+ Assert.Equal(EnsureCertificateResult.ErrorExportingTheCertificateToNonExistentDirectory, result);
}
[Fact]
diff --git a/src/Tools/dotnet-dev-certs/src/Program.cs b/src/Tools/dotnet-dev-certs/src/Program.cs
index 9f5407d9d3e4..9b195dbcd9fa 100644
--- a/src/Tools/dotnet-dev-certs/src/Program.cs
+++ b/src/Tools/dotnet-dev-certs/src/Program.cs
@@ -425,6 +425,10 @@ private static int EnsureHttpsCertificate(CommandOption exportPath, CommandOptio
case EnsureCertificateResult.ErrorExportingTheCertificate:
reporter.Warn("There was an error exporting the HTTPS developer certificate to a file.");
return ErrorExportingTheCertificate;
+ case EnsureCertificateResult.ErrorExportingTheCertificateToNonExistentDirectory:
+ // A distinct warning is useful, but a distinct error code is probably not.
+ reporter.Warn("There was an error exporting the HTTPS developer certificate to a file. Please create the target directory before exporting. Choose permissions carefully when creating it.");
+ return ErrorExportingTheCertificate;
case EnsureCertificateResult.PartiallyFailedToTrustTheCertificate:
// A distinct warning is useful, but a distinct error code is probably not.
reporter.Warn("There was an error trusting the HTTPS developer certificate. It will be trusted by some clients but not by others.");
diff --git a/src/submodules/MessagePack-CSharp b/src/submodules/MessagePack-CSharp
index ecc4e18ad7a0..95119056ee8f 160000
--- a/src/submodules/MessagePack-CSharp
+++ b/src/submodules/MessagePack-CSharp
@@ -1 +1 @@
-Subproject commit ecc4e18ad7a0c7db51cd7e3d2997a291ed01444d
+Subproject commit 95119056ee8f4da1714b055a4f16893afaa73af7
diff --git a/src/submodules/googletest b/src/submodules/googletest
index ff233bdd4cac..6dae7eb4a5c3 160000
--- a/src/submodules/googletest
+++ b/src/submodules/googletest
@@ -1 +1 @@
-Subproject commit ff233bdd4cac0a0bf6e5cd45bda3406814cb2796
+Subproject commit 6dae7eb4a5c3a169f3e298392bff4680224aa94a