diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index c4e6085b10..719f153297 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,18 +1,18 @@
# Users referenced in this file will automatically be requested as reviewers for PRs that modify the given paths.
# See https://help.github.com/articles/about-code-owners/
-/.azure/ @dougbu
-/.config/ @dougbu
-/build/ @dougbu
-/eng/ @dougbu
-/src/Components/ @SteveSandersonMS
-/src/DefaultBuilder/ @tratcher @anurse
-/src/Hosting/ @tratcher @anurse
-/src/Http/ @tratcher @jkotalik @anurse
-/src/Middleware/ @tratcher @anurse
-/src/ProjectTemplates/ @ryanbrandenburg
-/src/Security/ @tratcher @anurse
-/src/Servers/ @tratcher @jkotalik @anurse
-/src/Middleware/Rewrite @jkotalik @anurse
-/src/Middleware/HttpsPolicy @jkotalik @anurse
-/src/SignalR/ @mikaelm12 @BrennanConroy @halter73 @anurse
+/.azure/ @aspnet/build
+/.config/ @aspnet/build
+/build/ @aspnet/build
+/eng/ @aspnet/build
+/src/Components/ @SteveSandersonMS
+/src/DefaultBuilder/ @tratcher @anurse
+/src/Hosting/ @tratcher @anurse
+/src/Http/ @tratcher @jkotalik @anurse
+/src/Middleware/ @tratcher @anurse
+/src/ProjectTemplates/ @ryanbrandenburg
+/src/Security/ @tratcher @anurse
+/src/Servers/ @tratcher @jkotalik @anurse
+/src/Middleware/Rewrite @jkotalik @anurse
+/src/Middleware/HttpsPolicy @jkotalik @anurse
+/src/SignalR/ @mikaelm12 @BrennanConroy @halter73 @anurse
diff --git a/build/sources.props b/build/sources.props
index 717242fc60..29a3b61a6d 100644
--- a/build/sources.props
+++ b/build/sources.props
@@ -20,6 +20,7 @@
https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
https://dotnet.myget.org/F/blazor-dev/api/v3/index.json;
https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
+ https://dotnet.myget.org/F/nuget-build/api/v3/index.json;
https://dotnet.myget.org/F/roslyn-tools/api/v3/index.json;
https://dotnet.myget.org/F/roslyn/api/v3/index.json;
https://vside.myget.org/F/devcore/api/v3/index.json;
diff --git a/build/tasks/RepoTasks.csproj b/build/tasks/RepoTasks.csproj
index 8615952bb7..cee6fea25f 100644
--- a/build/tasks/RepoTasks.csproj
+++ b/build/tasks/RepoTasks.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 984ddf059b..1eee7ca945 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,384 +9,384 @@
-->
-
+
https://github.com/aspnet/AspNetCore-Tooling
- 699014190668f9d631583a771ecfa1be39183624
+ beebdf43f54ec82e06a48b99812d9740cb9f38cf
-
+
https://github.com/aspnet/AspNetCore-Tooling
- 699014190668f9d631583a771ecfa1be39183624
+ beebdf43f54ec82e06a48b99812d9740cb9f38cf
-
+
https://github.com/aspnet/AspNetCore-Tooling
- 699014190668f9d631583a771ecfa1be39183624
+ beebdf43f54ec82e06a48b99812d9740cb9f38cf
-
+
https://github.com/aspnet/AspNetCore-Tooling
- 699014190668f9d631583a771ecfa1be39183624
+ beebdf43f54ec82e06a48b99812d9740cb9f38cf
-
+
https://github.com/aspnet/EntityFrameworkCore
- c6daea74750e0d3b89f3aa8581ceef068f60373c
+ 243ea5080c4d7eefc96797134c9e10b2fa75f835
-
+
https://github.com/aspnet/EntityFrameworkCore
- c6daea74750e0d3b89f3aa8581ceef068f60373c
+ 243ea5080c4d7eefc96797134c9e10b2fa75f835
-
+
https://github.com/aspnet/EntityFrameworkCore
- c6daea74750e0d3b89f3aa8581ceef068f60373c
+ 243ea5080c4d7eefc96797134c9e10b2fa75f835
-
+
https://github.com/aspnet/EntityFrameworkCore
- c6daea74750e0d3b89f3aa8581ceef068f60373c
+ 243ea5080c4d7eefc96797134c9e10b2fa75f835
-
+
https://github.com/aspnet/EntityFrameworkCore
- c6daea74750e0d3b89f3aa8581ceef068f60373c
+ 243ea5080c4d7eefc96797134c9e10b2fa75f835
-
+
https://github.com/aspnet/EntityFrameworkCore
- c6daea74750e0d3b89f3aa8581ceef068f60373c
+ 243ea5080c4d7eefc96797134c9e10b2fa75f835
-
+
https://github.com/aspnet/EntityFrameworkCore
- c6daea74750e0d3b89f3aa8581ceef068f60373c
+ 243ea5080c4d7eefc96797134c9e10b2fa75f835
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/dotnet/core-setup
- 89ba5a781188bb95f7de3c2714fdddd19f341f32
+ 42a6743d709c3d74f1cb7a2af8740e3183a022f4
-
+
https://github.com/dotnet/core-setup
- 89ba5a781188bb95f7de3c2714fdddd19f341f32
+ 42a6743d709c3d74f1cb7a2af8740e3183a022f4
-
+
https://github.com/dotnet/corefx
- e0a01a12c2676d69cefa61aa2526a414d7f2dabb
+ 81fe62442228cb26bd0d95ceec3e0a3b74bde0a2
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
-
+
https://github.com/dotnet/arcade
- b1f9e12fe3ee71c48ea60b15968745850ac0a4a7
+ 9d7e665ecf2606094677524ecd5af0fc39c7bb49
-
+
https://github.com/aspnet/Extensions
- 0af12a60cf8f1c245b78488e50968907d5b5e671
+ 8749bf15c942cb1e4c9c01f3e7a9b2af84293d4b
diff --git a/eng/Versions.props b/eng/Versions.props
index 3450e1c0fc..e924927fd3 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -17,106 +17,106 @@
-->
- 1.0.0-beta.19207.1
+ 1.0.0-beta.19209.1
- 3.0.0-preview4-27609-12
- 3.0.0-preview4-27609-12
+ 3.0.0-preview5-27606-09
+ 3.0.0-preview5-27606-09
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.7.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 1.7.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
- 4.6.0-preview4.19208.6
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.7.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 1.7.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
+ 4.6.0-preview5.19206.5
- 3.0.0-preview4.19208.6
+ 3.0.0-preview5.19206.5
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
- 3.0.0-preview4.19209.10
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
+ 3.0.0-preview4.19207.2
- 3.0.0-preview4.19209.6
- 3.0.0-preview4.19209.6
- 3.0.0-preview4.19209.6
- 3.0.0-preview4.19209.6
- 3.0.0-preview4.19209.6
- 3.0.0-preview4.19209.6
- 3.0.0-preview4.19209.6
+ 3.0.0-preview5.19208.4
+ 3.0.0-preview5.19208.4
+ 3.0.0-preview5.19208.4
+ 3.0.0-preview5.19208.4
+ 3.0.0-preview5.19208.4
+ 3.0.0-preview5.19208.4
+ 3.0.0-preview5.19208.4
- 3.0.0-preview4.19209.3
- 3.0.0-preview4.19209.3
- 3.0.0-preview4.19209.3
- 3.0.0-preview4.19209.3
+ 3.0.0-preview5.19208.6
+ 3.0.0-preview5.19208.6
+ 3.0.0-preview5.19208.6
+ 3.0.0-preview5.19208.6
-
-
-
+ Value="[IISEXPRESS_APPHOST_CONFIG]"/>
+
+
+
+
-
-
-
-
+ Property="CA_REMOVE_CONFIGSECTION"
+ Value="[IISEXPRESS_APPHOST_CONFIG]"/>
+
+
+
+
-
-
-
-
-
-
+ Property="CA_ADD_CONFIGSECTION32"
+ Value="[IISEXPRESS_APPHOST_CONFIG32]"/>
+
+
+
+
-
-
-
-
+ Value="[IISEXPRESS_APPHOST_CONFIG32]"/>
+
+
+
+
@@ -600,7 +516,9 @@
-
+
+
+
@@ -610,6 +528,8 @@
+
+
@@ -640,7 +560,9 @@
-
+
+
+
@@ -650,6 +572,8 @@
+
+
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp
index 48d826f720..7727eeed5c 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.cpp
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#include
+#include
+#include
DECLARE_DEBUG_PRINT_OBJECT( "proxyCA.dll" );
@@ -40,6 +42,138 @@ struct COMPRESSION_MIME_TYPE
COMPRESSION_MIME_TYPE gMimeTypes[] =
{ { L"text/event-stream", FALSE} };
+#define _HR_RET(hr) __pragma(warning(push)) \
+ __pragma(warning(disable:26498)) /*disable constexpr warning */ \
+ const HRESULT __hrRet = hr; \
+ __pragma(warning(pop))
+
+#define _GOTO_FINISHED() __pragma(warning(push)) \
+ __pragma(warning(disable:26438)) /*disable avoid goto warning*/ \
+ goto Finished \
+ __pragma(warning(pop))
+
+#define RETURN_IF_FAILED(hrr) do { _HR_RET(hrr); if (FAILED(__hrRet)) { hr = __hrRet; IISLogWrite(SETUP_LOG_SEVERITY_INFORMATION, L"Exiting hr=0x%x", hr); return hr; }} while (0, 0)
+
+// Modifies the configSections to include the aspNetCore section
+UINT
+WINAPI
+AddConfigSection(
+ IN MSIHANDLE handle
+)
+{
+ HRESULT hr;
+ CComPtr pXMLDoc;
+ VARIANT_BOOL variantResult;
+ IXMLDOMNode* webServerNode;
+ IXMLDOMNode* aspNetCoreNode;
+ IXMLDOMNode* tempNode;
+ IXMLDOMElement* element;
+ STRU customActionData;
+
+ CComBSTR selectLanguage = SysAllocString(L"SelectionLanguage");
+ CComBSTR xPath = SysAllocString(L"XPath");
+ CComBSTR webServerPath = SysAllocString(L"//configuration/configSections/sectionGroup[@name=\"system.webServer\"]");
+ CComBSTR aspNetCorePath = SysAllocString(L"//configuration/configSections/sectionGroup[@name=\"system.webServer\"]/section[@name=\"aspNetCore\"]");
+ CComBSTR section = SysAllocString(L"section");
+ CComBSTR name = SysAllocString(L"name");
+ CComBSTR aspNetCore = SysAllocString(L"aspNetCore");
+ CComBSTR overrideMode = SysAllocString(L"overrideModeDefault");
+ CComBSTR allow = SysAllocString(L"Allow");
+
+ RETURN_IF_FAILED(CoInitialize(NULL));
+
+ hr = MsiUtilGetProperty(handle, TEXT("CustomActionData"), &customActionData);
+
+ RETURN_IF_FAILED(hr = pXMLDoc.CoCreateInstance(__uuidof(DOMDocument60)));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->put_async(false));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->load(CComVariant(customActionData.QueryStr()), &variantResult));
+
+ if (variantResult == VARIANT_FALSE)
+ {
+ return ERROR_SUCCESS;
+ }
+
+ RETURN_IF_FAILED(hr = pXMLDoc->setProperty(selectLanguage, CComVariant(xPath)));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->selectSingleNode(webServerPath, &webServerNode));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->selectSingleNode(aspNetCorePath, &aspNetCoreNode));
+
+ if (aspNetCoreNode == NULL)
+ {
+ RETURN_IF_FAILED(hr = pXMLDoc->createElement(section, &element));
+
+ RETURN_IF_FAILED(hr = element->setAttribute(name, CComVariant(aspNetCore)));
+
+ RETURN_IF_FAILED(hr = element->setAttribute(overrideMode, CComVariant(allow)));
+
+ RETURN_IF_FAILED(hr = webServerNode->appendChild(element, &tempNode));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->save(CComVariant(customActionData.QueryStr())));
+ }
+
+ return ERROR_SUCCESS;
+}
+
+// Modifies the configSections to remove the aspNetCore section
+UINT
+WINAPI
+RemoveConfigSection(
+ IN MSIHANDLE handle
+)
+{
+ HRESULT hr;
+ CComPtr pXMLDoc;
+ VARIANT_BOOL variantResult;
+ IXMLDOMNode* webServerNode;
+ IXMLDOMNode* aspNetCoreNode;
+ IXMLDOMNode* tempNode;
+ IXMLDOMElement* element;
+ STRU customActionData;
+
+ CComBSTR selectLanguage = SysAllocString(L"SelectionLanguage");
+ CComBSTR xPath = SysAllocString(L"XPath");
+ CComBSTR webServerPath = SysAllocString(L"//configuration/configSections/sectionGroup[@name=\"system.webServer\"]");
+ CComBSTR aspNetCorePath = SysAllocString(L"//configuration/configSections/sectionGroup[@name=\"system.webServer\"]/section[@name=\"aspNetCore\"]");
+ CComBSTR section = SysAllocString(L"section");
+ CComBSTR name = SysAllocString(L"name");
+ CComBSTR aspNetCore = SysAllocString(L"aspNetCore");
+ CComBSTR overrideMode = SysAllocString(L"overrideModeDefault");
+ CComBSTR allow = SysAllocString(L"Allow");
+
+ RETURN_IF_FAILED(CoInitialize(NULL));
+
+ hr = MsiUtilGetProperty(handle, TEXT("CustomActionData"), &customActionData);
+
+ RETURN_IF_FAILED(hr = pXMLDoc.CoCreateInstance(__uuidof(DOMDocument60)));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->put_async(false));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->load(CComVariant(customActionData.QueryStr()), &variantResult));
+
+ if (variantResult == VARIANT_FALSE)
+ {
+ return ERROR_SUCCESS;
+ }
+
+ RETURN_IF_FAILED(hr = pXMLDoc->setProperty(selectLanguage, CComVariant(xPath)));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->selectSingleNode(webServerPath, &webServerNode));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->selectSingleNode(aspNetCorePath, &aspNetCoreNode));
+
+ if (aspNetCoreNode != NULL)
+ {
+ RETURN_IF_FAILED(webServerNode->removeChild(aspNetCoreNode, &tempNode));
+
+ RETURN_IF_FAILED(hr = pXMLDoc->save(CComVariant(customActionData.QueryStr())));
+ }
+
+ return ERROR_SUCCESS;
+}
+
UINT
WINAPI
RegisterANCMCompressionCA(
diff --git a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def
index 3518cde35f..ed516a4392 100644
--- a/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def
+++ b/src/Installers/Windows/AspNetCoreModule-Setup/CustomAction/aspnetcoreCA.def
@@ -18,6 +18,8 @@ EXPORTS
ExecuteCleanUpWindowsHotfixCA
ScheduleRebootIfRequiredCA
+ AddConfigSection
+ RemoveConfigSection
RegisterANCMCompressionCA
CheckForServicesRunningCA
diff --git a/src/Installers/Windows/UpgradeLog.htm b/src/Installers/Windows/UpgradeLog.htm
new file mode 100644
index 0000000000..f327ebd6ec
Binary files /dev/null and b/src/Installers/Windows/UpgradeLog.htm differ
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/wwwroot/css/site.css b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/wwwroot/css/site.css
index c486131d5a..19dc5bf077 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/wwwroot/css/site.css
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorPagesWeb-CSharp/wwwroot/css/site.css
@@ -50,7 +50,5 @@ body {
bottom: 0;
width: 100%;
white-space: nowrap;
- /* Set the fixed height of the footer here */
- height: 60px;
line-height: 60px; /* Vertically center the text there */
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/wwwroot/css/site.css b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/wwwroot/css/site.css
index c486131d5a..19dc5bf077 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/wwwroot/css/site.css
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-CSharp/wwwroot/css/site.css
@@ -50,7 +50,5 @@ body {
bottom: 0;
width: 100%;
white-space: nowrap;
- /* Set the fixed height of the footer here */
- height: 60px;
line-height: 60px; /* Vertically center the text there */
}
diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/wwwroot/css/site.css b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/wwwroot/css/site.css
index c486131d5a..19dc5bf077 100644
--- a/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/wwwroot/css/site.css
+++ b/src/ProjectTemplates/Web.ProjectTemplates/content/StarterWeb-FSharp/wwwroot/css/site.css
@@ -50,7 +50,5 @@ body {
bottom: 0;
width: 100%;
white-space: nowrap;
- /* Set the fixed height of the footer here */
- height: 60px;
line-height: 60px; /* Vertically center the text there */
}
diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/LogFileTests.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/LogFileTests.cs
index 9ea84650d7..68ff8d44ac 100644
--- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/LogFileTests.cs
+++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/LogFileTests.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
+using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
@@ -170,6 +171,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
}
[ConditionalTheory]
+ [Flaky("https://github.com/aspnet/AspNetCore-Internal/issues/2200", FlakyOn.All)]
[MemberData(nameof(TestVariants))]
public async Task CheckUTF8File(TestVariant variant)
{
diff --git a/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs b/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs
index 494c58056d..62687bc800 100644
--- a/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs
+++ b/src/Servers/Kestrel/Core/ref/Microsoft.AspNetCore.Server.Kestrel.Core.netcoreapp3.0.cs
@@ -121,6 +121,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
public Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal.SchedulingMode ApplicationSchedulingMode { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public System.IServiceProvider ApplicationServices { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader ConfigurationLoader { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
+ public bool DisableStringReuse { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerLimits Limits { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader Configure() { throw null; }
public Microsoft.AspNetCore.Server.Kestrel.KestrelConfigurationLoader Configure(Microsoft.Extensions.Configuration.IConfiguration config) { throw null; }
@@ -251,6 +252,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public partial interface IHttpHeadersHandler
{
void OnHeader(System.Span name, System.Span value);
+ void OnHeadersComplete();
}
public partial interface IHttpParser where TRequestHandler : Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpHeadersHandler, Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.IHttpRequestLineHandler
{
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs
index d2cdb57382..7b23196794 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs
@@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
private const byte ByteAsterisk = (byte)'*';
private const byte ByteForwardSlash = (byte)'/';
private const string Asterisk = "*";
+ private const string ForwardSlash = "/";
private readonly HttpConnectionContext _context;
private readonly IHttpParser _parser;
@@ -268,16 +269,68 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_requestTargetForm = HttpRequestTarget.OriginForm;
+ if (target.Length == 1)
+ {
+ // If target.Length == 1 it can only be a forward slash (e.g. home page)
+ // and we know RawTarget and Path are the same and QueryString is Empty
+ RawTarget = ForwardSlash;
+ Path = ForwardSlash;
+ QueryString = string.Empty;
+ // Clear parsedData as we won't check it if we come via this path again,
+ // an setting to null is fast as it doesn't need to use a GC write barrier.
+ _parsedRawTarget = _parsedPath = _parsedQueryString = null;
+ return;
+ }
+
// URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11
// Multibyte Internationalized Resource Identifiers (IRIs) are first converted to utf8;
// then encoded/escaped to ASCII https://www.ietf.org/rfc/rfc3987.txt "Mapping of IRIs to URIs"
try
{
+ var disableStringReuse = ServerOptions.DisableStringReuse;
// Read raw target before mutating memory.
- RawTarget = target.GetAsciiStringNonNullCharacters();
- QueryString = query.GetAsciiStringNonNullCharacters();
- Path = PathNormalizer.DecodePath(path, pathEncoded, RawTarget, query.Length);
+ var previousValue = _parsedRawTarget;
+ if (disableStringReuse ||
+ previousValue == null || previousValue.Length != target.Length ||
+ !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target))
+ {
+ // The previous string does not match what the bytes would convert to,
+ // so we will need to generate a new string.
+ RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters();
+
+ previousValue = _parsedQueryString;
+ if (disableStringReuse ||
+ previousValue == null || previousValue.Length != query.Length ||
+ !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, query))
+ {
+ // The previous string does not match what the bytes would convert to,
+ // so we will need to generate a new string.
+ QueryString = _parsedQueryString = query.GetAsciiStringNonNullCharacters();
+ }
+ else
+ {
+ // Same as previous
+ QueryString = _parsedQueryString;
+ }
+
+ if (path.Length == 1)
+ {
+ // If path.Length == 1 it can only be a forward slash (e.g. home page)
+ Path = _parsedPath = ForwardSlash;
+ }
+ else
+ {
+ Path = _parsedPath = PathNormalizer.DecodePath(path, pathEncoded, RawTarget, query.Length);
+ }
+ }
+ else
+ {
+ // As RawTarget is the same we can reuse the previous parsed values.
+ RawTarget = _parsedRawTarget;
+ Path = _parsedPath;
+ QueryString = _parsedQueryString;
+ }
}
catch (InvalidOperationException)
{
@@ -312,9 +365,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
//
// Allowed characters in the 'host + port' section of authority.
// See https://tools.ietf.org/html/rfc3986#section-3.2
- RawTarget = target.GetAsciiStringNonNullCharacters();
+
+ var previousValue = _parsedRawTarget;
+ if (ServerOptions.DisableStringReuse ||
+ previousValue == null || previousValue.Length != target.Length ||
+ !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target))
+ {
+ // The previous string does not match what the bytes would convert to,
+ // so we will need to generate a new string.
+ RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters();
+ }
+ else
+ {
+ // Reuse previous value
+ RawTarget = _parsedRawTarget;
+ }
+
Path = string.Empty;
QueryString = string.Empty;
+ // Clear parsedData for path and queryString as we won't check it if we come via this path again,
+ // an setting to null is fast as it doesn't need to use a GC write barrier.
+ _parsedPath = _parsedQueryString = null;
}
private void OnAsteriskFormTarget(HttpMethod method)
@@ -331,6 +402,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
RawTarget = Asterisk;
Path = string.Empty;
QueryString = string.Empty;
+ // Clear parsedData as we won't check it if we come via this path again,
+ // an setting to null is fast as it doesn't need to use a GC write barrier.
+ _parsedRawTarget = _parsedPath = _parsedQueryString = null;
}
private void OnAbsoluteFormTarget(Span target, Span query)
@@ -346,21 +420,49 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
// a server MUST accept the absolute-form in requests, even though
// HTTP/1.1 clients will only send them in requests to proxies.
- RawTarget = target.GetAsciiStringNonNullCharacters();
-
- // Validation of absolute URIs is slow, but clients
- // should not be sending this form anyways, so perf optimization
- // not high priority
-
- if (!Uri.TryCreate(RawTarget, UriKind.Absolute, out var uri))
+ var disableStringReuse = ServerOptions.DisableStringReuse;
+ var previousValue = _parsedRawTarget;
+ if (disableStringReuse ||
+ previousValue == null || previousValue.Length != target.Length ||
+ !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, target))
{
- ThrowRequestTargetRejected(target);
- }
+ // The previous string does not match what the bytes would convert to,
+ // so we will need to generate a new string.
+ RawTarget = _parsedRawTarget = target.GetAsciiStringNonNullCharacters();
- _absoluteRequestTarget = uri;
- Path = uri.LocalPath;
- // don't use uri.Query because we need the unescaped version
- QueryString = query.GetAsciiStringNonNullCharacters();
+ // Validation of absolute URIs is slow, but clients
+ // should not be sending this form anyways, so perf optimization
+ // not high priority
+
+ if (!Uri.TryCreate(RawTarget, UriKind.Absolute, out var uri))
+ {
+ ThrowRequestTargetRejected(target);
+ }
+
+ _absoluteRequestTarget = uri;
+ Path = _parsedPath = uri.LocalPath;
+ // don't use uri.Query because we need the unescaped version
+ previousValue = _parsedQueryString;
+ if (disableStringReuse ||
+ previousValue == null || previousValue.Length != query.Length ||
+ !StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, query))
+ {
+ // The previous string does not match what the bytes would convert to,
+ // so we will need to generate a new string.
+ QueryString = _parsedQueryString = query.GetAsciiStringNonNullCharacters();
+ }
+ else
+ {
+ QueryString = _parsedQueryString;
+ }
+ }
+ else
+ {
+ // As RawTarget is the same we can reuse the previous values.
+ RawTarget = _parsedRawTarget;
+ Path = _parsedPath;
+ QueryString = _parsedQueryString;
+ }
}
internal void EnsureHostHeaderExists()
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1ParsingHandler.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1ParsingHandler.cs
index a7d6fdddc7..bcc905cab9 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1ParsingHandler.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1ParsingHandler.cs
@@ -17,6 +17,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public void OnHeader(Span name, Span value)
=> Connection.OnHeader(name, value);
+ public void OnHeadersComplete()
+ => Connection.OnHeadersComplete();
+
public void OnStartLine(HttpMethod method, HttpVersion version, Span target, Span path, Span query, Span customMethod, bool pathEncoded)
=> Connection.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
}
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs
index a69e738048..55882f905d 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs
@@ -6,16 +6,16 @@ using System.Collections.Generic;
using System.Buffers;
using System.IO.Pipelines;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
internal partial class HttpRequestHeaders
{
-
- private long _bits = 0;
private HeaderReferences _headers;
public bool HasConnection => (_bits & 0x2L) != 0;
@@ -703,12 +703,46 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_headers._UserAgent = value;
}
}
- public StringValues HeaderOrigin
+ public StringValues HeaderDNT
{
get
{
StringValues value = default;
if ((_bits & 0x10000000000L) != 0)
+ {
+ value = _headers._DNT;
+ }
+ return value;
+ }
+ set
+ {
+ _bits |= 0x10000000000L;
+ _headers._DNT = value;
+ }
+ }
+ public StringValues HeaderUpgradeInsecureRequests
+ {
+ get
+ {
+ StringValues value = default;
+ if ((_bits & 0x20000000000L) != 0)
+ {
+ value = _headers._UpgradeInsecureRequests;
+ }
+ return value;
+ }
+ set
+ {
+ _bits |= 0x20000000000L;
+ _headers._UpgradeInsecureRequests = value;
+ }
+ }
+ public StringValues HeaderOrigin
+ {
+ get
+ {
+ StringValues value = default;
+ if ((_bits & 0x40000000000L) != 0)
{
value = _headers._Origin;
}
@@ -716,7 +750,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
set
{
- _bits |= 0x10000000000L;
+ _bits |= 0x40000000000L;
_headers._Origin = value;
}
}
@@ -725,7 +759,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
get
{
StringValues value = default;
- if ((_bits & 0x20000000000L) != 0)
+ if ((_bits & 0x80000000000L) != 0)
{
value = _headers._AccessControlRequestMethod;
}
@@ -733,7 +767,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
set
{
- _bits |= 0x20000000000L;
+ _bits |= 0x80000000000L;
_headers._AccessControlRequestMethod = value;
}
}
@@ -742,7 +776,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
get
{
StringValues value = default;
- if ((_bits & 0x40000000000L) != 0)
+ if ((_bits & 0x100000000000L) != 0)
{
value = _headers._AccessControlRequestHeaders;
}
@@ -750,7 +784,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
set
{
- _bits |= 0x40000000000L;
+ _bits |= 0x100000000000L;
_headers._AccessControlRequestHeaders = value;
}
}
@@ -932,7 +966,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
if ("Origin".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- if ((_bits & 0x10000000000L) != 0)
+ if ((_bits & 0x40000000000L) != 0)
{
value = _headers._Origin;
return true;
@@ -1023,6 +1057,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
return false;
}
+ if ("DNT".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ if ((_bits & 0x10000000000L) != 0)
+ {
+ value = _headers._DNT;
+ return true;
+ }
+ return false;
+ }
}
break;
case 5:
@@ -1227,11 +1270,24 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
}
break;
+ case 25:
+ {
+ if ("Upgrade-Insecure-Requests".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ if ((_bits & 0x20000000000L) != 0)
+ {
+ value = _headers._UpgradeInsecureRequests;
+ return true;
+ }
+ return false;
+ }
+ }
+ break;
case 29:
{
if ("Access-Control-Request-Method".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- if ((_bits & 0x20000000000L) != 0)
+ if ((_bits & 0x80000000000L) != 0)
{
value = _headers._AccessControlRequestMethod;
return true;
@@ -1244,7 +1300,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
if ("Access-Control-Request-Headers".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- if ((_bits & 0x40000000000L) != 0)
+ if ((_bits & 0x100000000000L) != 0)
{
value = _headers._AccessControlRequestHeaders;
return true;
@@ -1368,7 +1424,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
if ("Origin".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- _bits |= 0x10000000000L;
+ _bits |= 0x40000000000L;
_headers._Origin = value;
return;
}
@@ -1432,6 +1488,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_headers._Via = value;
return;
}
+ if ("DNT".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ _bits |= 0x10000000000L;
+ _headers._DNT = value;
+ return;
+ }
}
break;
case 5:
@@ -1581,11 +1643,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
}
break;
+ case 25:
+ {
+ if ("Upgrade-Insecure-Requests".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ _bits |= 0x20000000000L;
+ _headers._UpgradeInsecureRequests = value;
+ return;
+ }
+ }
+ break;
case 29:
{
if ("Access-Control-Request-Method".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- _bits |= 0x20000000000L;
+ _bits |= 0x80000000000L;
_headers._AccessControlRequestMethod = value;
return;
}
@@ -1595,7 +1667,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
if ("Access-Control-Request-Headers".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- _bits |= 0x40000000000L;
+ _bits |= 0x100000000000L;
_headers._AccessControlRequestHeaders = value;
return;
}
@@ -1776,9 +1848,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
if ("Origin".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- if ((_bits & 0x10000000000L) == 0)
+ if ((_bits & 0x40000000000L) == 0)
{
- _bits |= 0x10000000000L;
+ _bits |= 0x40000000000L;
_headers._Origin = value;
return true;
}
@@ -1876,6 +1948,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
return false;
}
+ if ("DNT".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ if ((_bits & 0x10000000000L) == 0)
+ {
+ _bits |= 0x10000000000L;
+ _headers._DNT = value;
+ return true;
+ }
+ return false;
+ }
}
break;
case 5:
@@ -2097,13 +2179,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
}
break;
- case 29:
+ case 25:
{
- if ("Access-Control-Request-Method".Equals(key, StringComparison.OrdinalIgnoreCase))
+ if ("Upgrade-Insecure-Requests".Equals(key, StringComparison.OrdinalIgnoreCase))
{
if ((_bits & 0x20000000000L) == 0)
{
_bits |= 0x20000000000L;
+ _headers._UpgradeInsecureRequests = value;
+ return true;
+ }
+ return false;
+ }
+ }
+ break;
+ case 29:
+ {
+ if ("Access-Control-Request-Method".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ if ((_bits & 0x80000000000L) == 0)
+ {
+ _bits |= 0x80000000000L;
_headers._AccessControlRequestMethod = value;
return true;
}
@@ -2115,9 +2211,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
if ("Access-Control-Request-Headers".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- if ((_bits & 0x40000000000L) == 0)
+ if ((_bits & 0x100000000000L) == 0)
{
- _bits |= 0x40000000000L;
+ _bits |= 0x100000000000L;
_headers._AccessControlRequestHeaders = value;
return true;
}
@@ -2302,9 +2398,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
if ("Origin".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- if ((_bits & 0x10000000000L) != 0)
+ if ((_bits & 0x40000000000L) != 0)
{
- _bits &= ~0x10000000000L;
+ _bits &= ~0x40000000000L;
_headers._Origin = default(StringValues);
return true;
}
@@ -2402,6 +2498,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
return false;
}
+ if ("DNT".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ if ((_bits & 0x10000000000L) != 0)
+ {
+ _bits &= ~0x10000000000L;
+ _headers._DNT = default(StringValues);
+ return true;
+ }
+ return false;
+ }
}
break;
case 5:
@@ -2623,13 +2729,27 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
}
break;
- case 29:
+ case 25:
{
- if ("Access-Control-Request-Method".Equals(key, StringComparison.OrdinalIgnoreCase))
+ if ("Upgrade-Insecure-Requests".Equals(key, StringComparison.OrdinalIgnoreCase))
{
if ((_bits & 0x20000000000L) != 0)
{
_bits &= ~0x20000000000L;
+ _headers._UpgradeInsecureRequests = default(StringValues);
+ return true;
+ }
+ return false;
+ }
+ }
+ break;
+ case 29:
+ {
+ if ("Access-Control-Request-Method".Equals(key, StringComparison.OrdinalIgnoreCase))
+ {
+ if ((_bits & 0x80000000000L) != 0)
+ {
+ _bits &= ~0x80000000000L;
_headers._AccessControlRequestMethod = default(StringValues);
return true;
}
@@ -2641,9 +2761,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
if ("Access-Control-Request-Headers".Equals(key, StringComparison.OrdinalIgnoreCase))
{
- if ((_bits & 0x40000000000L) != 0)
+ if ((_bits & 0x100000000000L) != 0)
{
- _bits &= ~0x40000000000L;
+ _bits &= ~0x100000000000L;
_headers._AccessControlRequestHeaders = default(StringValues);
return true;
}
@@ -2655,18 +2775,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return MaybeUnknown?.Remove(key) ?? false;
}
-
- protected override void ClearFast()
+ private void Clear(long bitsToClear)
{
- MaybeUnknown?.Clear();
- _contentLength = null;
- var tempBits = _bits;
- _bits = 0;
- if(HttpHeaders.BitCount(tempBits) > 12)
- {
- _headers = default(HeaderReferences);
- return;
- }
+ var tempBits = bitsToClear;
if ((tempBits & 0x2L) != 0)
{
@@ -3070,7 +3181,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
if ((tempBits & 0x10000000000L) != 0)
{
- _headers._Origin = default(StringValues);
+ _headers._DNT = default(StringValues);
if((tempBits & ~0x10000000000L) == 0)
{
return;
@@ -3080,7 +3191,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
if ((tempBits & 0x20000000000L) != 0)
{
- _headers._AccessControlRequestMethod = default(StringValues);
+ _headers._UpgradeInsecureRequests = default(StringValues);
if((tempBits & ~0x20000000000L) == 0)
{
return;
@@ -3090,7 +3201,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
if ((tempBits & 0x40000000000L) != 0)
{
- _headers._AccessControlRequestHeaders = default(StringValues);
+ _headers._Origin = default(StringValues);
if((tempBits & ~0x40000000000L) == 0)
{
return;
@@ -3098,6 +3209,26 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
tempBits &= ~0x40000000000L;
}
+ if ((tempBits & 0x80000000000L) != 0)
+ {
+ _headers._AccessControlRequestMethod = default(StringValues);
+ if((tempBits & ~0x80000000000L) == 0)
+ {
+ return;
+ }
+ tempBits &= ~0x80000000000L;
+ }
+
+ if ((tempBits & 0x100000000000L) != 0)
+ {
+ _headers._AccessControlRequestHeaders = default(StringValues);
+ if((tempBits & ~0x100000000000L) == 0)
+ {
+ return;
+ }
+ tempBits &= ~0x100000000000L;
+ }
+
}
protected override bool CopyToFast(KeyValuePair[] array, int arrayIndex)
@@ -3473,7 +3604,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
return false;
}
- array[arrayIndex] = new KeyValuePair("Origin", _headers._Origin);
+ array[arrayIndex] = new KeyValuePair("DNT", _headers._DNT);
++arrayIndex;
}
if ((_bits & 0x20000000000L) != 0)
@@ -3482,10 +3613,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
return false;
}
- array[arrayIndex] = new KeyValuePair("Access-Control-Request-Method", _headers._AccessControlRequestMethod);
+ array[arrayIndex] = new KeyValuePair("Upgrade-Insecure-Requests", _headers._UpgradeInsecureRequests);
++arrayIndex;
}
if ((_bits & 0x40000000000L) != 0)
+ {
+ if (arrayIndex == array.Length)
+ {
+ return false;
+ }
+ array[arrayIndex] = new KeyValuePair("Origin", _headers._Origin);
+ ++arrayIndex;
+ }
+ if ((_bits & 0x80000000000L) != 0)
+ {
+ if (arrayIndex == array.Length)
+ {
+ return false;
+ }
+ array[arrayIndex] = new KeyValuePair("Access-Control-Request-Method", _headers._AccessControlRequestMethod);
+ ++arrayIndex;
+ }
+ if ((_bits & 0x100000000000L) != 0)
{
if (arrayIndex == array.Length)
{
@@ -3508,734 +3657,345 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return true;
}
-
- public unsafe void Append(byte* pKeyBytes, int keyLength, string value)
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
+ public unsafe void Append(Span name, Span value)
{
- var pUB = pKeyBytes;
- var pUL = (ulong*)pUB;
- var pUI = (uint*)pUB;
- var pUS = (ushort*)pUB;
- var stringValue = new StringValues(value);
- switch (keyLength)
+ ref byte nameStart = ref MemoryMarshal.GetReference(name);
+ ref StringValues values = ref Unsafe.AsRef(null);
+ var flag = 0L;
+
+ // Does the name matched any "known" headers
+ switch (name.Length)
+ {
+ case 2:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfu) == 0x4554u))
+ {
+ flag = 0x2000000000L;
+ values = ref _headers._TE;
+ }
+ break;
+ case 3:
+ var firstTerm3 = (Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfu);
+ if ((firstTerm3 == 0x4e44u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)2) & 0xdfu) == 0x54u))
+ {
+ flag = 0x10000000000L;
+ values = ref _headers._DNT;
+ }
+ else if ((firstTerm3 == 0x4956u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)2) & 0xdfu) == 0x41u))
+ {
+ flag = 0x100L;
+ values = ref _headers._Via;
+ }
+ break;
+ case 4:
+ var firstTerm4 = (Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfu);
+ if ((firstTerm4 == 0x54534f48u))
+ {
+ flag = 0x8000000L;
+ values = ref _headers._Host;
+ }
+ else if ((firstTerm4 == 0x45544144u))
+ {
+ flag = 0x4L;
+ values = ref _headers._Date;
+ }
+ else if ((firstTerm4 == 0x4d4f5246u))
+ {
+ flag = 0x4000000L;
+ values = ref _headers._From;
+ }
+ break;
+ case 5:
+ var firstTerm5 = (Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfu);
+ if ((firstTerm5 == 0x4f4c4c41u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)4) & 0xdfu) == 0x57u))
+ {
+ flag = 0x400L;
+ values = ref _headers._Allow;
+ }
+ else if ((firstTerm5 == 0x474e4152u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)4) & 0xdfu) == 0x45u))
+ {
+ flag = 0x1000000000L;
+ values = ref _headers._Range;
+ }
+ break;
+ case 6:
+ var firstTerm6 = (Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfu);
+ if ((firstTerm6 == 0x45434341u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x5450u))
+ {
+ flag = 0x80000L;
+ values = ref _headers._Accept;
+ }
+ else if ((firstTerm6 == 0x4b4f4f43u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4549u))
+ {
+ flag = 0x1000000L;
+ values = ref _headers._Cookie;
+ }
+ else if ((firstTerm6 == 0x45505845u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x5443u))
+ {
+ flag = 0x2000000L;
+ values = ref _headers._Expect;
+ }
+ else if ((firstTerm6 == 0x4749524fu) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4e49u))
+ {
+ flag = 0x40000000000L;
+ values = ref _headers._Origin;
+ }
+ else if ((firstTerm6 == 0x47415250u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x414du))
+ {
+ flag = 0x10L;
+ values = ref _headers._Pragma;
+ }
+ break;
+ case 7:
+ var firstTerm7 = (Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfu);
+ if ((firstTerm7 == 0x49505845u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4552u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x53u))
+ {
+ flag = 0x20000L;
+ values = ref _headers._Expires;
+ }
+ else if ((firstTerm7 == 0x45464552u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4552u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x52u))
+ {
+ flag = 0x800000000L;
+ values = ref _headers._Referer;
+ }
+ else if ((firstTerm7 == 0x49415254u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x454cu) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x52u))
+ {
+ flag = 0x20L;
+ values = ref _headers._Trailer;
+ }
+ else if ((firstTerm7 == 0x52475055u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4441u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x45u))
+ {
+ flag = 0x80L;
+ values = ref _headers._Upgrade;
+ }
+ else if ((firstTerm7 == 0x4e524157u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ushort)))) & 0xdfdfu) == 0x4e49u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)6) & 0xdfu) == 0x47u))
+ {
+ flag = 0x200L;
+ values = ref _headers._Warning;
+ }
+ break;
+ case 8:
+ var firstTerm8 = (Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfdfffdfdfuL);
+ if ((firstTerm8 == 0x484354414d2d4649uL))
+ {
+ flag = 0x10000000L;
+ values = ref _headers._IfMatch;
+ }
+ else if ((firstTerm8 == 0x45474e41522d4649uL))
+ {
+ flag = 0x80000000L;
+ values = ref _headers._IfRange;
+ }
+ break;
+ case 9:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x54414c534e415254uL) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)8) & 0xdfu) == 0x45u))
+ {
+ flag = 0x4000000000L;
+ values = ref _headers._Translate;
+ }
+ break;
+ case 10:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x495443454e4e4f43uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x4e4fu))
+ {
+ flag = 0x2L;
+ values = ref _headers._Connection;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfffdfdfdfdfuL) == 0x4547412d52455355uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x544eu))
+ {
+ flag = 0x8000000000L;
+ values = ref _headers._UserAgent;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfffdfdfdfdfuL) == 0x494c412d5045454buL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x4556u))
+ {
+ flag = 0x8L;
+ values = ref _headers._KeepAlive;
+ }
+ break;
+ case 11:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d544e45544e4f43uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(4 * sizeof(ushort)))) & 0xdfdfu) == 0x444du) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)10) & 0xffu) == 0x35u))
+ {
+ flag = 0x8000L;
+ values = ref _headers._ContentMD5;
+ }
+ break;
+ case 12:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d544e45544e4f43uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x45505954u))
+ {
+ flag = 0x800L;
+ values = ref _headers._ContentType;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfffdfdfdfuL) == 0x57524f462d58414duL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x53445241u))
+ {
+ flag = 0x200000000L;
+ values = ref _headers._MaxForwards;
+ }
+ break;
+ case 13:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x5a49524f48545541uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x4f495441u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x4eu))
+ {
+ flag = 0x800000L;
+ values = ref _headers._Authorization;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfffdfdfdfdfdfuL) == 0x4f432d4548434143uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x4f52544eu) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x4cu))
+ {
+ flag = 0x1L;
+ values = ref _headers._CacheControl;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d544e45544e4f43uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x474e4152u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x45u))
+ {
+ flag = 0x10000L;
+ values = ref _headers._ContentRange;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xffdfdfdfdfffdfdfuL) == 0x2d454e4f4e2d4649uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x4354414du) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x48u))
+ {
+ flag = 0x40000000L;
+ values = ref _headers._IfNoneMatch;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfffdfdfdfdfuL) == 0x444f4d2d5453414cuL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x45494649u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)12) & 0xdfu) == 0x44u))
+ {
+ flag = 0x40000L;
+ values = ref _headers._LastModified;
+ }
+ break;
+ case 14:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfffdfdfdfdfdfdfuL) == 0x432d545045434341uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x53524148u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(ushort)))) & 0xdfdfu) == 0x5445u))
+ {
+ flag = 0x100000L;
+ values = ref _headers._AcceptCharset;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d544e45544e4f43uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x474e454cu) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(ushort)))) & 0xdfdfu) == 0x4854u))
+ {
+ AppendContentLength(value);
+ return;
+ }
+ break;
+ case 15:
+ var firstTerm15 = (Unsafe.ReadUnaligned(ref nameStart) & 0xdfffdfdfdfdfdfdfuL);
+ if ((firstTerm15 == 0x452d545045434341uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x444f434eu) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(ushort)))) & 0xdfdfu) == 0x4e49u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)14) & 0xdfu) == 0x47u))
+ {
+ flag = 0x200000L;
+ values = ref _headers._AcceptEncoding;
+ }
+ else if ((firstTerm15 == 0x4c2d545045434341uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x55474e41u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(ushort)))) & 0xdfdfu) == 0x4741u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)14) & 0xdfu) == 0x45u))
+ {
+ flag = 0x400000L;
+ values = ref _headers._AcceptLanguage;
+ }
+ break;
+ case 16:
+ var firstTerm16 = (Unsafe.ReadUnaligned(ref nameStart) & 0xffdfdfdfdfdfdfdfuL);
+ if ((firstTerm16 == 0x2d544e45544e4f43uL))
+ {
+ if (((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x474e49444f434e45uL))
+ {
+ flag = 0x1000L;
+ values = ref _headers._ContentEncoding;
+ }
+ else if (((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x45474155474e414cuL))
+ {
+ flag = 0x2000L;
+ values = ref _headers._ContentLanguage;
+ }
+ else if (((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x4e4f495441434f4cuL))
+ {
+ flag = 0x4000L;
+ values = ref _headers._ContentLocation;
+ }
+ }
+ break;
+ case 17:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfdfffdfdfuL) == 0x4649444f4d2d4649uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfffdfdfdfuL) == 0x434e49532d444549uL) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)16) & 0xdfu) == 0x45u))
+ {
+ flag = 0x20000000L;
+ values = ref _headers._IfModifiedSince;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfdfdfdfdfuL) == 0x524546534e415254uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfffuL) == 0x4e49444f434e452duL) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)16) & 0xdfu) == 0x47u))
+ {
+ flag = 0x40L;
+ values = ref _headers._TransferEncoding;
+ }
+ break;
+ case 19:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfdfdfdfffdfdfuL) == 0x444f4d4e552d4649uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfffdfdfdfdfdfuL) == 0x49532d4445494649uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(8 * sizeof(ushort)))) & 0xdfdfu) == 0x434eu) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)18) & 0xdfu) == 0x45u))
+ {
+ flag = 0x100000000L;
+ values = ref _headers._IfUnmodifiedSince;
+ }
+ else if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfdfffdfdfdfdfdfuL) == 0x55412d59584f5250uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x54415a49524f4854uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(8 * sizeof(ushort)))) & 0xdfdfu) == 0x4f49u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)18) & 0xdfu) == 0x4eu))
+ {
+ flag = 0x400000000L;
+ values = ref _headers._ProxyAuthorization;
+ }
+ break;
+ case 25:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xffdfdfdfdfdfdfdfuL) == 0x2d45444152475055uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfdfdfdfdfdfdfdfuL) == 0x4552554345534e49uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ulong)))) & 0xdfdfdfdfdfdfdfffuL) == 0x545345555145522duL) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)24) & 0xdfu) == 0x53u))
+ {
+ flag = 0x20000000000L;
+ values = ref _headers._UpgradeInsecureRequests;
+ }
+ break;
+ case 29:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfffdfdfdfdfdfdfuL) == 0x432d535345434341uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfffdfdfdfdfdfdfuL) == 0x522d4c4f52544e4fuL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ulong)))) & 0xdfffdfdfdfdfdfdfuL) == 0x4d2d545345555145uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x4f485445u) && ((Unsafe.AddByteOffset(ref nameStart, (IntPtr)28) & 0xdfu) == 0x44u))
+ {
+ flag = 0x80000000000L;
+ values = ref _headers._AccessControlRequestMethod;
+ }
+ break;
+ case 30:
+ if (((Unsafe.ReadUnaligned(ref nameStart) & 0xdfffdfdfdfdfdfdfuL) == 0x432d535345434341uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)sizeof(ulong))) & 0xdfffdfdfdfdfdfdfuL) == 0x522d4c4f52544e4fuL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(2 * sizeof(ulong)))) & 0xdfffdfdfdfdfdfdfuL) == 0x482d545345555145uL) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(6 * sizeof(uint)))) & 0xdfdfdfdfu) == 0x45444145u) && ((Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref nameStart, (IntPtr)(14 * sizeof(ushort)))) & 0xdfdfu) == 0x5352u))
+ {
+ flag = 0x100000000000L;
+ values = ref _headers._AccessControlRequestHeaders;
+ }
+ break;
+ }
+
+ if (flag != 0)
+ {
+ // Matched a known header
+ if ((_previousBits & flag) != 0)
{
- case 10:
+ // Had a previous string for this header, mark it as used so we don't clear it OnHeadersComplete or consider it if we get a second header
+ _previousBits ^= flag;
+
+ // We will only reuse this header if there was only one previous header
+ if (values.Count == 1)
+ {
+ var previousValue = values.ToString();
+ // Check lengths are the same, then if the bytes were converted to an ascii string if they would be the same.
+ // We do not consider Utf8 headers for reuse.
+ if (previousValue.Length == value.Length &&
+ StringUtilities.BytesOrdinalEqualsStringAndAscii(previousValue, value))
{
- if ((((pUL[0] & 16131858542891098079uL) == 5283922227757993795uL) && ((pUS[4] & 57311u) == 20047u)))
- {
- if ((_bits & 0x2L) != 0)
- {
- _headers._Connection = AppendValue(_headers._Connection, value);
- }
- else
- {
- _bits |= 0x2L;
- _headers._Connection = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16131858680330051551uL) == 4992030374873092949uL) && ((pUS[4] & 57311u) == 21582u)))
- {
- if ((_bits & 0x8000000000L) != 0)
- {
- _headers._UserAgent = AppendValue(_headers._UserAgent, value);
- }
- else
- {
- _bits |= 0x8000000000L;
- _headers._UserAgent = stringValue;
- }
- return;
- }
+ // The previous string matches what the bytes would convert to, so we will just use that one.
+ _bits |= flag;
+ return;
}
- break;
-
- case 6:
- {
- if ((((pUI[0] & 3755991007u) == 1162036033u) && ((pUS[2] & 57311u) == 21584u)))
- {
- if ((_bits & 0x80000L) != 0)
- {
- _headers._Accept = AppendValue(_headers._Accept, value);
- }
- else
- {
- _bits |= 0x80000L;
- _headers._Accept = stringValue;
- }
- return;
- }
- }
- break;
-
- case 4:
- {
- if ((((pUI[0] & 3755991007u) == 1414745928u)))
- {
- if ((_bits & 0x8000000L) != 0)
- {
- _headers._Host = AppendValue(_headers._Host, value);
- }
- else
- {
- _bits |= 0x8000000L;
- _headers._Host = stringValue;
- }
- return;
- }
- }
- break;
+ }
}
- AppendNonPrimaryHeaders(pKeyBytes, keyLength, value);
- }
-
- private unsafe void AppendNonPrimaryHeaders(byte* pKeyBytes, int keyLength, string value)
- {
- var pUB = pKeyBytes;
- var pUL = (ulong*)pUB;
- var pUI = (uint*)pUB;
- var pUS = (ushort*)pUB;
- var stringValue = new StringValues(value);
- switch (keyLength)
+ // We didn't have a previous matching header value, or have already added a header, so get the string for this value.
+ var valueStr = value.GetAsciiOrUTF8StringNonNullCharacters();
+ if ((_bits & flag) == 0)
{
- case 13:
- {
- if ((((pUL[0] & 16131893727263186911uL) == 5711458528024281411uL) && ((pUI[2] & 3755991007u) == 1330795598u) && ((pUB[12] & 223u) == 76u)))
- {
- if ((_bits & 0x1L) != 0)
- {
- _headers._CacheControl = AppendValue(_headers._CacheControl, value);
- }
- else
- {
- _bits |= 0x1L;
- _headers._CacheControl = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1196310866u) && ((pUB[12] & 223u) == 69u)))
- {
- if ((_bits & 0x10000L) != 0)
- {
- _headers._ContentRange = AppendValue(_headers._ContentRange, value);
- }
- else
- {
- _bits |= 0x10000L;
- _headers._ContentRange = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16131858680330051551uL) == 4922237774822850892uL) && ((pUI[2] & 3755991007u) == 1162430025u) && ((pUB[12] & 223u) == 68u)))
- {
- if ((_bits & 0x40000L) != 0)
- {
- _headers._LastModified = AppendValue(_headers._LastModified, value);
- }
- else
- {
- _bits |= 0x40000L;
- _headers._LastModified = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16131858542891098079uL) == 6505821637182772545uL) && ((pUI[2] & 3755991007u) == 1330205761u) && ((pUB[12] & 223u) == 78u)))
- {
- if ((_bits & 0x800000L) != 0)
- {
- _headers._Authorization = AppendValue(_headers._Authorization, value);
- }
- else
- {
- _bits |= 0x800000L;
- _headers._Authorization = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 18437701552106889183uL) == 3262099607620765257uL) && ((pUI[2] & 3755991007u) == 1129595213u) && ((pUB[12] & 223u) == 72u)))
- {
- if ((_bits & 0x40000000L) != 0)
- {
- _headers._IfNoneMatch = AppendValue(_headers._IfNoneMatch, value);
- }
- else
- {
- _bits |= 0x40000000L;
- _headers._IfNoneMatch = stringValue;
- }
- return;
- }
- }
- break;
-
- case 4:
- {
- if ((((pUI[0] & 3755991007u) == 1163149636u)))
- {
- if ((_bits & 0x4L) != 0)
- {
- _headers._Date = AppendValue(_headers._Date, value);
- }
- else
- {
- _bits |= 0x4L;
- _headers._Date = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1297044038u)))
- {
- if ((_bits & 0x4000000L) != 0)
- {
- _headers._From = AppendValue(_headers._From, value);
- }
- else
- {
- _bits |= 0x4000000L;
- _headers._From = stringValue;
- }
- return;
- }
- }
- break;
-
- case 10:
- {
- if ((((pUL[0] & 16131858680330051551uL) == 5281668125874799947uL) && ((pUS[4] & 57311u) == 17750u)))
- {
- if ((_bits & 0x8L) != 0)
- {
- _headers._KeepAlive = AppendValue(_headers._KeepAlive, value);
- }
- else
- {
- _bits |= 0x8L;
- _headers._KeepAlive = stringValue;
- }
- return;
- }
- }
- break;
-
- case 6:
- {
- if ((((pUI[0] & 3755991007u) == 1195463248u) && ((pUS[2] & 57311u) == 16717u)))
- {
- if ((_bits & 0x10L) != 0)
- {
- _headers._Pragma = AppendValue(_headers._Pragma, value);
- }
- else
- {
- _bits |= 0x10L;
- _headers._Pragma = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1263488835u) && ((pUS[2] & 57311u) == 17737u)))
- {
- if ((_bits & 0x1000000L) != 0)
- {
- _headers._Cookie = AppendValue(_headers._Cookie, value);
- }
- else
- {
- _bits |= 0x1000000L;
- _headers._Cookie = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1162893381u) && ((pUS[2] & 57311u) == 21571u)))
- {
- if ((_bits & 0x2000000L) != 0)
- {
- _headers._Expect = AppendValue(_headers._Expect, value);
- }
- else
- {
- _bits |= 0x2000000L;
- _headers._Expect = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1195987535u) && ((pUS[2] & 57311u) == 20041u)))
- {
- if ((_bits & 0x10000000000L) != 0)
- {
- _headers._Origin = AppendValue(_headers._Origin, value);
- }
- else
- {
- _bits |= 0x10000000000L;
- _headers._Origin = stringValue;
- }
- return;
- }
- }
- break;
-
- case 7:
- {
- if ((((pUI[0] & 3755991007u) == 1229017684u) && ((pUS[2] & 57311u) == 17740u) && ((pUB[6] & 223u) == 82u)))
- {
- if ((_bits & 0x20L) != 0)
- {
- _headers._Trailer = AppendValue(_headers._Trailer, value);
- }
- else
- {
- _bits |= 0x20L;
- _headers._Trailer = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1380405333u) && ((pUS[2] & 57311u) == 17473u) && ((pUB[6] & 223u) == 69u)))
- {
- if ((_bits & 0x80L) != 0)
- {
- _headers._Upgrade = AppendValue(_headers._Upgrade, value);
- }
- else
- {
- _bits |= 0x80L;
- _headers._Upgrade = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1314013527u) && ((pUS[2] & 57311u) == 20041u) && ((pUB[6] & 223u) == 71u)))
- {
- if ((_bits & 0x200L) != 0)
- {
- _headers._Warning = AppendValue(_headers._Warning, value);
- }
- else
- {
- _bits |= 0x200L;
- _headers._Warning = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1230002245u) && ((pUS[2] & 57311u) == 17746u) && ((pUB[6] & 223u) == 83u)))
- {
- if ((_bits & 0x20000L) != 0)
- {
- _headers._Expires = AppendValue(_headers._Expires, value);
- }
- else
- {
- _bits |= 0x20000L;
- _headers._Expires = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1162233170u) && ((pUS[2] & 57311u) == 17746u) && ((pUB[6] & 223u) == 82u)))
- {
- if ((_bits & 0x800000000L) != 0)
- {
- _headers._Referer = AppendValue(_headers._Referer, value);
- }
- else
- {
- _bits |= 0x800000000L;
- _headers._Referer = stringValue;
- }
- return;
- }
- }
- break;
-
- case 17:
- {
- if ((((pUL[0] & 16131858542891098079uL) == 5928221808112259668uL) && ((pUL[1] & 16131858542891098111uL) == 5641115115480565037uL) && ((pUB[16] & 223u) == 71u)))
- {
- if ((_bits & 0x40L) != 0)
- {
- _headers._TransferEncoding = AppendValue(_headers._TransferEncoding, value);
- }
- else
- {
- _bits |= 0x40L;
- _headers._TransferEncoding = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16131858542893195231uL) == 5064654363342751305uL) && ((pUL[1] & 16131858543427968991uL) == 4849894470315165001uL) && ((pUB[16] & 223u) == 69u)))
- {
- if ((_bits & 0x20000000L) != 0)
- {
- _headers._IfModifiedSince = AppendValue(_headers._IfModifiedSince, value);
- }
- else
- {
- _bits |= 0x20000000L;
- _headers._IfModifiedSince = stringValue;
- }
- return;
- }
- }
- break;
-
- case 3:
- {
- if ((((pUS[0] & 57311u) == 18774u) && ((pUB[2] & 223u) == 65u)))
- {
- if ((_bits & 0x100L) != 0)
- {
- _headers._Via = AppendValue(_headers._Via, value);
- }
- else
- {
- _bits |= 0x100L;
- _headers._Via = stringValue;
- }
- return;
- }
- }
- break;
-
- case 5:
- {
- if ((((pUI[0] & 3755991007u) == 1330400321u) && ((pUB[4] & 223u) == 87u)))
- {
- if ((_bits & 0x400L) != 0)
- {
- _headers._Allow = AppendValue(_headers._Allow, value);
- }
- else
- {
- _bits |= 0x400L;
- _headers._Allow = stringValue;
- }
- return;
- }
-
- if ((((pUI[0] & 3755991007u) == 1196310866u) && ((pUB[4] & 223u) == 69u)))
- {
- if ((_bits & 0x1000000000L) != 0)
- {
- _headers._Range = AppendValue(_headers._Range, value);
- }
- else
- {
- _bits |= 0x1000000000L;
- _headers._Range = stringValue;
- }
- return;
- }
- }
- break;
-
- case 12:
- {
- if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1162893652u)))
- {
- if ((_bits & 0x800L) != 0)
- {
- _headers._ContentType = AppendValue(_headers._ContentType, value);
- }
- else
- {
- _bits |= 0x800L;
- _headers._ContentType = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16131858543427968991uL) == 6292178792217067853uL) && ((pUI[2] & 3755991007u) == 1396986433u)))
- {
- if ((_bits & 0x200000000L) != 0)
- {
- _headers._MaxForwards = AppendValue(_headers._MaxForwards, value);
- }
- else
- {
- _bits |= 0x200000000L;
- _headers._MaxForwards = stringValue;
- }
- return;
- }
- }
- break;
-
- case 16:
- {
- if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 5138124782612729413uL)))
- {
- if ((_bits & 0x1000L) != 0)
- {
- _headers._ContentEncoding = AppendValue(_headers._ContentEncoding, value);
- }
- else
- {
- _bits |= 0x1000L;
- _headers._ContentEncoding = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 4992030546487820620uL)))
- {
- if ((_bits & 0x2000L) != 0)
- {
- _headers._ContentLanguage = AppendValue(_headers._ContentLanguage, value);
- }
- else
- {
- _bits |= 0x2000L;
- _headers._ContentLanguage = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUL[1] & 16131858542891098079uL) == 5642809484339531596uL)))
- {
- if ((_bits & 0x4000L) != 0)
- {
- _headers._ContentLocation = AppendValue(_headers._ContentLocation, value);
- }
- else
- {
- _bits |= 0x4000L;
- _headers._ContentLocation = stringValue;
- }
- return;
- }
- }
- break;
-
- case 11:
- {
- if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUS[4] & 57311u) == 17485u) && ((pUB[10] & 255u) == 53u)))
- {
- if ((_bits & 0x8000L) != 0)
- {
- _headers._ContentMD5 = AppendValue(_headers._ContentMD5, value);
- }
- else
- {
- _bits |= 0x8000L;
- _headers._ContentMD5 = stringValue;
- }
- return;
- }
- }
- break;
-
- case 14:
- {
- if ((((pUL[0] & 16140865742145839071uL) == 4840617878229304129uL) && ((pUI[2] & 3755991007u) == 1397899592u) && ((pUS[6] & 57311u) == 21573u)))
- {
- if ((_bits & 0x100000L) != 0)
- {
- _headers._AcceptCharset = AppendValue(_headers._AcceptCharset, value);
- }
- else
- {
- _bits |= 0x100000L;
- _headers._AcceptCharset = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 18437701552104792031uL) == 3266321689424580419uL) && ((pUI[2] & 3755991007u) == 1196311884u) && ((pUS[6] & 57311u) == 18516u)))
- {
- if (_contentLength.HasValue)
- {
- BadHttpRequestException.Throw(RequestRejectionReason.MultipleContentLengths);
- }
- else
- {
- _contentLength = ParseContentLength(value);
- }
- return;
- }
- }
- break;
-
- case 15:
- {
- if ((((pUL[0] & 16140865742145839071uL) == 4984733066305160001uL) && ((pUI[2] & 3755991007u) == 1146045262u) && ((pUS[6] & 57311u) == 20041u) && ((pUB[14] & 223u) == 71u)))
- {
- if ((_bits & 0x200000L) != 0)
- {
- _headers._AcceptEncoding = AppendValue(_headers._AcceptEncoding, value);
- }
- else
- {
- _bits |= 0x200000L;
- _headers._AcceptEncoding = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16140865742145839071uL) == 5489136224570655553uL) && ((pUI[2] & 3755991007u) == 1430736449u) && ((pUS[6] & 57311u) == 18241u) && ((pUB[14] & 223u) == 69u)))
- {
- if ((_bits & 0x400000L) != 0)
- {
- _headers._AcceptLanguage = AppendValue(_headers._AcceptLanguage, value);
- }
- else
- {
- _bits |= 0x400000L;
- _headers._AcceptLanguage = stringValue;
- }
- return;
- }
- }
- break;
-
- case 8:
- {
- if ((((pUL[0] & 16131858542893195231uL) == 5207098233614845513uL)))
- {
- if ((_bits & 0x10000000L) != 0)
- {
- _headers._IfMatch = AppendValue(_headers._IfMatch, value);
- }
- else
- {
- _bits |= 0x10000000L;
- _headers._IfMatch = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16131858542893195231uL) == 4992044754422023753uL)))
- {
- if ((_bits & 0x80000000L) != 0)
- {
- _headers._IfRange = AppendValue(_headers._IfRange, value);
- }
- else
- {
- _bits |= 0x80000000L;
- _headers._IfRange = stringValue;
- }
- return;
- }
- }
- break;
-
- case 19:
- {
- if ((((pUL[0] & 16131858542893195231uL) == 4922237916571059785uL) && ((pUL[1] & 16131893727263186911uL) == 5283616559079179849uL) && ((pUS[8] & 57311u) == 17230u) && ((pUB[18] & 223u) == 69u)))
- {
- if ((_bits & 0x100000000L) != 0)
- {
- _headers._IfUnmodifiedSince = AppendValue(_headers._IfUnmodifiedSince, value);
- }
- else
- {
- _bits |= 0x100000000L;
- _headers._IfUnmodifiedSince = stringValue;
- }
- return;
- }
-
- if ((((pUL[0] & 16131893727263186911uL) == 6143241228466999888uL) && ((pUL[1] & 16131858542891098079uL) == 6071233043632179284uL) && ((pUS[8] & 57311u) == 20297u) && ((pUB[18] & 223u) == 78u)))
- {
- if ((_bits & 0x400000000L) != 0)
- {
- _headers._ProxyAuthorization = AppendValue(_headers._ProxyAuthorization, value);
- }
- else
- {
- _bits |= 0x400000000L;
- _headers._ProxyAuthorization = stringValue;
- }
- return;
- }
- }
- break;
-
- case 2:
- {
- if ((((pUS[0] & 57311u) == 17748u)))
- {
- if ((_bits & 0x2000000000L) != 0)
- {
- _headers._TE = AppendValue(_headers._TE, value);
- }
- else
- {
- _bits |= 0x2000000000L;
- _headers._TE = stringValue;
- }
- return;
- }
- }
- break;
-
- case 9:
- {
- if ((((pUL[0] & 16131858542891098079uL) == 6071217693351039572uL) && ((pUB[8] & 223u) == 69u)))
- {
- if ((_bits & 0x4000000000L) != 0)
- {
- _headers._Translate = AppendValue(_headers._Translate, value);
- }
- else
- {
- _bits |= 0x4000000000L;
- _headers._Translate = stringValue;
- }
- return;
- }
- }
- break;
-
- case 29:
- {
- if ((((pUL[0] & 16140865742145839071uL) == 4840616791602578241uL) && ((pUL[1] & 16140865742145839071uL) == 5921472988629454415uL) && ((pUL[2] & 16140865742145839071uL) == 5561193831494668613uL) && ((pUI[6] & 3755991007u) == 1330140229u) && ((pUB[28] & 223u) == 68u)))
- {
- if ((_bits & 0x20000000000L) != 0)
- {
- _headers._AccessControlRequestMethod = AppendValue(_headers._AccessControlRequestMethod, value);
- }
- else
- {
- _bits |= 0x20000000000L;
- _headers._AccessControlRequestMethod = stringValue;
- }
- return;
- }
- }
- break;
-
- case 30:
- {
- if ((((pUL[0] & 16140865742145839071uL) == 4840616791602578241uL) && ((pUL[1] & 16140865742145839071uL) == 5921472988629454415uL) && ((pUL[2] & 16140865742145839071uL) == 5200905861305028933uL) && ((pUI[6] & 3755991007u) == 1162101061u) && ((pUS[14] & 57311u) == 21330u)))
- {
- if ((_bits & 0x40000000000L) != 0)
- {
- _headers._AccessControlRequestHeaders = AppendValue(_headers._AccessControlRequestHeaders, value);
- }
- else
- {
- _bits |= 0x40000000000L;
- _headers._AccessControlRequestHeaders = stringValue;
- }
- return;
- }
- }
- break;
+ // We didn't already have a header set, so add a new one.
+ _bits |= flag;
+ values = new StringValues(valueStr);
}
-
- AppendUnknownHeaders(pKeyBytes, keyLength, value);
+ else
+ {
+ // We already had a header set, so concatenate the new one.
+ values = AppendValue(values, valueStr);
+ }
+ }
+ else
+ {
+ // The header was not one of the "known" headers.
+ // Convert value to string first, because passing two spans causes 8 bytes stack zeroing in
+ // this method with rep stosd, which is slower than necessary.
+ var valueStr = value.GetAsciiOrUTF8StringNonNullCharacters();
+ AppendUnknownHeaders(name, valueStr);
+ }
}
private struct HeaderReferences
@@ -4280,6 +4040,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public StringValues _TE;
public StringValues _Translate;
public StringValues _UserAgent;
+ public StringValues _DNT;
+ public StringValues _UpgradeInsecureRequests;
public StringValues _Origin;
public StringValues _AccessControlRequestMethod;
public StringValues _AccessControlRequestHeaders;
@@ -4374,12 +4136,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
case 39:
goto HeaderUserAgent;
case 40:
- goto HeaderOrigin;
+ goto HeaderDNT;
case 41:
- goto HeaderAccessControlRequestMethod;
+ goto HeaderUpgradeInsecureRequests;
case 42:
- goto HeaderAccessControlRequestHeaders;
+ goto HeaderOrigin;
case 43:
+ goto HeaderAccessControlRequestMethod;
+ case 44:
+ goto HeaderAccessControlRequestHeaders;
+ case 45:
goto HeaderContentLength;
default:
goto ExtraHeaders;
@@ -4665,32 +4431,46 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_next = 40;
return true;
}
- HeaderOrigin: // case 40
+ HeaderDNT: // case 40
if ((_bits & 0x10000000000L) != 0)
{
- _current = new KeyValuePair("Origin", _collection._headers._Origin);
+ _current = new KeyValuePair("DNT", _collection._headers._DNT);
_next = 41;
return true;
}
- HeaderAccessControlRequestMethod: // case 41
+ HeaderUpgradeInsecureRequests: // case 41
if ((_bits & 0x20000000000L) != 0)
{
- _current = new KeyValuePair("Access-Control-Request-Method", _collection._headers._AccessControlRequestMethod);
+ _current = new KeyValuePair("Upgrade-Insecure-Requests", _collection._headers._UpgradeInsecureRequests);
_next = 42;
return true;
}
- HeaderAccessControlRequestHeaders: // case 42
+ HeaderOrigin: // case 42
if ((_bits & 0x40000000000L) != 0)
{
- _current = new KeyValuePair("Access-Control-Request-Headers", _collection._headers._AccessControlRequestHeaders);
+ _current = new KeyValuePair("Origin", _collection._headers._Origin);
_next = 43;
return true;
}
- HeaderContentLength: // case 43
+ HeaderAccessControlRequestMethod: // case 43
+ if ((_bits & 0x80000000000L) != 0)
+ {
+ _current = new KeyValuePair("Access-Control-Request-Method", _collection._headers._AccessControlRequestMethod);
+ _next = 44;
+ return true;
+ }
+ HeaderAccessControlRequestHeaders: // case 44
+ if ((_bits & 0x100000000000L) != 0)
+ {
+ _current = new KeyValuePair("Access-Control-Request-Headers", _collection._headers._AccessControlRequestHeaders);
+ _next = 45;
+ return true;
+ }
+ HeaderContentLength: // case 45
if (_collection._contentLength.HasValue)
{
_current = new KeyValuePair("Content-Length", HeaderUtilities.FormatNonNegativeInt64(_collection._contentLength.Value));
- _next = 44;
+ _next = 46;
return true;
}
ExtraHeaders:
@@ -4711,8 +4491,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
13,10,67,97,99,104,101,45,67,111,110,116,114,111,108,58,32,13,10,67,111,110,110,101,99,116,105,111,110,58,32,13,10,68,97,116,101,58,32,13,10,75,101,101,112,45,65,108,105,118,101,58,32,13,10,80,114,97,103,109,97,58,32,13,10,84,114,97,105,108,101,114,58,32,13,10,84,114,97,110,115,102,101,114,45,69,110,99,111,100,105,110,103,58,32,13,10,85,112,103,114,97,100,101,58,32,13,10,86,105,97,58,32,13,10,87,97,114,110,105,110,103,58,32,13,10,65,108,108,111,119,58,32,13,10,67,111,110,116,101,110,116,45,84,121,112,101,58,32,13,10,67,111,110,116,101,110,116,45,69,110,99,111,100,105,110,103,58,32,13,10,67,111,110,116,101,110,116,45,76,97,110,103,117,97,103,101,58,32,13,10,67,111,110,116,101,110,116,45,76,111,99,97,116,105,111,110,58,32,13,10,67,111,110,116,101,110,116,45,77,68,53,58,32,13,10,67,111,110,116,101,110,116,45,82,97,110,103,101,58,32,13,10,69,120,112,105,114,101,115,58,32,13,10,76,97,115,116,45,77,111,100,105,102,105,101,100,58,32,13,10,65,99,99,101,112,116,45,82,97,110,103,101,115,58,32,13,10,65,103,101,58,32,13,10,69,84,97,103,58,32,13,10,76,111,99,97,116,105,111,110,58,32,13,10,80,114,111,120,121,45,65,117,116,104,101,110,116,105,99,97,116,101,58,32,13,10,82,101,116,114,121,45,65,102,116,101,114,58,32,13,10,83,101,114,118,101,114,58,32,13,10,83,101,116,45,67,111,111,107,105,101,58,32,13,10,86,97,114,121,58,32,13,10,87,87,87,45,65,117,116,104,101,110,116,105,99,97,116,101,58,32,13,10,65,99,99,101,115,115,45,67,111,110,116,114,111,108,45,65,108,108,111,119,45,67,114,101,100,101,110,116,105,97,108,115,58,32,13,10,65,99,99,101,115,115,45,67,111,110,116,114,111,108,45,65,108,108,111,119,45,72,101,97,100,101,114,115,58,32,13,10,65,99,99,101,115,115,45,67,111,110,116,114,111,108,45,65,108,108,111,119,45,77,101,116,104,111,100,115,58,32,13,10,65,99,99,101,115,115,45,67,111,110,116,114,111,108,45,65,108,108,111,119,45,79,114,105,103,105,110,58,32,13,10,65,99,99,101,115,115,45,67,111,110,116,114,111,108,45,69,120,112,111,115,101,45,72,101,97,100,101,114,115,58,32,13,10,65,99,99,101,115,115,45,67,111,110,116,114,111,108,45,77,97,120,45,65,103,101,58,32,13,10,67,111,110,116,101,110,116,45,76,101,110,103,116,104,58,32,
};
-
- private long _bits = 0;
private HeaderReferences _headers;
public bool HasConnection => (_bits & 0x2L) != 0;
@@ -6980,7 +6758,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return MaybeUnknown?.Remove(key) ?? false;
}
-
protected override void ClearFast()
{
MaybeUnknown?.Clear();
@@ -8138,7 +7915,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
} while (tempBits != 0);
}
-
private struct HeaderReferences
{
@@ -8537,8 +8313,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
13,10,69,84,97,103,58,32,
};
-
- private long _bits = 0;
private HeaderReferences _headers;
@@ -8657,7 +8431,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return MaybeUnknown?.Remove(key) ?? false;
}
-
protected override void ClearFast()
{
MaybeUnknown?.Clear();
@@ -8712,7 +8485,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return true;
}
-
private struct HeaderReferences
{
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.cs
index f907c81d88..b6944d8021 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.cs
@@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
internal abstract class HttpHeaders : IHeaderDictionary
{
+ protected long _bits = 0;
protected long? _contentLength;
protected bool _isReadOnly;
protected Dictionary MaybeUnknown;
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs
index 3010aecc61..d55706d827 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs
@@ -241,6 +241,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
}
done = true;
+ handler.OnHeadersComplete();
return true;
}
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs
index 8fec2adc03..0503c54930 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs
@@ -74,6 +74,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
_context = context;
ServerOptions = ServiceContext.ServerOptions;
+ HttpRequestHeaders = new HttpRequestHeaders(reuseHeaderValues: !ServerOptions.DisableStringReuse);
HttpResponseControl = this;
}
@@ -124,8 +125,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public string Scheme { get; set; }
public HttpMethod Method { get; set; }
public string PathBase { get; set; }
+
+ protected string _parsedPath = null;
public string Path { get; set; }
+
+ protected string _parsedQueryString = null;
public string QueryString { get; set; }
+
+ protected string _parsedRawTarget = null;
public string RawTarget { get; set; }
public string HttpVersion
@@ -275,7 +282,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public bool HasFlushedHeaders => _requestProcessingStatus == RequestProcessingStatus.HeadersFlushed;
- protected HttpRequestHeaders HttpRequestHeaders { get; } = new HttpRequestHeaders();
+ protected HttpRequestHeaders HttpRequestHeaders { get; }
protected HttpResponseHeaders HttpResponseHeaders { get; } = new HttpResponseHeaders();
@@ -492,9 +499,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
BadHttpRequestException.Throw(RequestRejectionReason.TooManyHeaders);
}
- var valueString = value.GetAsciiOrUTF8StringNonNullCharacters();
- HttpRequestHeaders.Append(name, valueString);
+ HttpRequestHeaders.Append(name, value);
+ }
+
+ public void OnHeadersComplete()
+ {
+ HttpRequestHeaders.OnHeadersComplete();
}
public async Task ProcessRequestsAsync(IHttpApplication application)
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs
index 823cf6d126..586987ebdf 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Buffers.Text;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
@@ -13,6 +14,50 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
{
internal sealed partial class HttpRequestHeaders : HttpHeaders
{
+ private readonly bool _reuseHeaderValues;
+ private long _previousBits = 0;
+
+ public HttpRequestHeaders(bool reuseHeaderValues = true)
+ {
+ _reuseHeaderValues = reuseHeaderValues;
+ }
+
+ public void OnHeadersComplete()
+ {
+ var bitsToClear = _previousBits & ~_bits;
+ _previousBits = 0;
+
+ if (bitsToClear != 0)
+ {
+ // Some previous headers were not reused or overwritten.
+
+ // While they cannot be accessed by the current request (as they were not supplied by it)
+ // there is no point in holding on to them, so clear them now,
+ // to allow them to get collected by the GC.
+ Clear(bitsToClear);
+ }
+ }
+
+ protected override void ClearFast()
+ {
+ if (!_reuseHeaderValues)
+ {
+ // If we aren't reusing headers clear them all
+ Clear(_bits);
+ }
+ else
+ {
+ // If we are reusing headers, store the currently set headers for comparison later
+ _previousBits = _bits;
+ }
+
+ // Mark no headers as currently in use
+ _bits = 0;
+ // Clear ContentLength and any unknown headers as we will never reuse them
+ _contentLength = null;
+ MaybeUnknown?.Clear();
+ }
+
private static long ParseContentLength(string value)
{
if (!HeaderUtilities.TryParseNonNegativeInt64(value, out var parsed))
@@ -23,34 +68,45 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
return parsed;
}
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void AppendContentLength(Span value)
+ {
+ if (_contentLength.HasValue)
+ {
+ BadHttpRequestException.Throw(RequestRejectionReason.MultipleContentLengths);
+ }
+
+ if (!Utf8Parser.TryParse(value, out long parsed, out var consumed) ||
+ parsed < 0 ||
+ consumed != value.Length)
+ {
+ BadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value.GetAsciiOrUTF8StringNonNullCharacters());
+ }
+
+ _contentLength = parsed;
+ }
+
[MethodImpl(MethodImplOptions.NoInlining)]
private void SetValueUnknown(string key, StringValues value)
{
Unknown[key] = value;
}
- public unsafe void Append(Span name, string value)
- {
- fixed (byte* namePtr = name)
- {
- Append(namePtr, name.Length, value);
- }
- }
-
[MethodImpl(MethodImplOptions.NoInlining)]
- private unsafe void AppendUnknownHeaders(byte* pKeyBytes, int keyLength, string value)
+ private unsafe void AppendUnknownHeaders(Span name, string valueString)
{
- string key = new string('\0', keyLength);
+ string key = new string('\0', name.Length);
+ fixed (byte* pKeyBytes = name)
fixed (char* keyBuffer = key)
{
- if (!StringUtilities.TryGetAsciiString(pKeyBytes, keyBuffer, keyLength))
+ if (!StringUtilities.TryGetAsciiString(pKeyBytes, keyBuffer, name.Length))
{
BadHttpRequestException.Throw(RequestRejectionReason.InvalidCharactersInHeaderName);
}
}
Unknown.TryGetValue(key, out var existing);
- Unknown[key] = AppendValue(existing, value);
+ Unknown[key] = AppendValue(existing, valueString);
}
public Enumerator GetEnumerator()
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/IHttpHeadersHandler.cs b/src/Servers/Kestrel/Core/src/Internal/Http/IHttpHeadersHandler.cs
index 9a322f0da9..0ed16148b8 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http/IHttpHeadersHandler.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http/IHttpHeadersHandler.cs
@@ -8,5 +8,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
public interface IHttpHeadersHandler
{
void OnHeader(Span name, Span value);
+ void OnHeadersComplete();
}
}
\ No newline at end of file
diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs
index 9f42f5545f..fed15bdf83 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Connection.cs
@@ -1092,6 +1092,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2
}
}
+ public void OnHeadersComplete()
+ => _currentHeadersStream.OnHeadersComplete();
+
private void ValidateHeader(Span name, Span value)
{
// http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.1
diff --git a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/StringUtilities.cs b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/StringUtilities.cs
index edc3a8eeed..aea8290b66 100644
--- a/src/Servers/Kestrel/Core/src/Internal/Infrastructure/StringUtilities.cs
+++ b/src/Servers/Kestrel/Core/src/Internal/Infrastructure/StringUtilities.cs
@@ -2,13 +2,19 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Buffers.Binary;
+using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics.X86;
+using System.Text;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
{
internal class StringUtilities
{
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static unsafe bool TryGetAsciiString(byte* input, char* output, int count)
{
// Calculate end position
@@ -109,6 +115,261 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure
return isValid;
}
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
+ public unsafe static bool BytesOrdinalEqualsStringAndAscii(string previousValue, Span newValue)
+ {
+ // previousValue is a previously materialized string which *must* have already passed validation.
+ Debug.Assert(IsValidHeaderString(previousValue));
+
+ // Ascii bytes => Utf-16 chars will be the same length.
+ // The caller should have already compared lengths before calling this method.
+ // However; let's double check, and early exit if they are not the same length.
+ if (previousValue.Length != newValue.Length)
+ {
+ // Lengths don't match, so there cannot be an exact ascii conversion between the two.
+ goto NotEqual;
+ }
+
+ // Use IntPtr values rather than int, to avoid unnecessary 32 -> 64 movs on 64-bit.
+ // Unfortunately this means we also need to cast to byte* for comparisons as IntPtr doesn't
+ // support operator comparisons (e.g. <=, >, etc).
+ //
+ // Note: Pointer comparison is unsigned, so we use the compare pattern (offset + length <= count)
+ // rather than (offset <= count - length) which we'd do with signed comparison to avoid overflow.
+ // This isn't problematic as we know the maximum length is max string length (from test above)
+ // which is a signed value so half the size of the unsigned pointer value so we can safely add
+ // a Vector.Count to it without overflowing.
+ var count = (IntPtr)newValue.Length;
+ var offset = (IntPtr)0;
+
+ // Get references to the first byte in the span, and the first char in the string.
+ ref var bytes = ref MemoryMarshal.GetReference(newValue);
+ ref var str = ref MemoryMarshal.GetReference(previousValue.AsSpan());
+
+ do
+ {
+ // If Vector not-accelerated or remaining less than vector size
+ if (!Vector.IsHardwareAccelerated || (byte*)(offset + Vector.Count) > (byte*)count)
+ {
+ if (IntPtr.Size == 8) // Use Intrinsic switch for branch elimination
+ {
+ // 64-bit: Loop longs by default
+ while ((byte*)(offset + sizeof(long)) <= (byte*)count)
+ {
+ if (!WidenFourAsciiBytesToUtf16AndCompareToChars(
+ ref Unsafe.Add(ref str, offset),
+ Unsafe.ReadUnaligned(ref Unsafe.Add(ref bytes, offset))) ||
+ !WidenFourAsciiBytesToUtf16AndCompareToChars(
+ ref Unsafe.Add(ref str, offset + 4),
+ Unsafe.ReadUnaligned(ref Unsafe.Add(ref bytes, offset + 4))))
+ {
+ goto NotEqual;
+ }
+
+ offset += sizeof(long);
+ }
+ if ((byte*)(offset + sizeof(int)) <= (byte*)count)
+ {
+ if (!WidenFourAsciiBytesToUtf16AndCompareToChars(
+ ref Unsafe.Add(ref str, offset),
+ Unsafe.ReadUnaligned(ref Unsafe.Add(ref bytes, offset))))
+ {
+ goto NotEqual;
+ }
+
+ offset += sizeof(int);
+ }
+ }
+ else
+ {
+ // 32-bit: Loop ints by default
+ while ((byte*)(offset + sizeof(int)) <= (byte*)count)
+ {
+ if (!WidenFourAsciiBytesToUtf16AndCompareToChars(
+ ref Unsafe.Add(ref str, offset),
+ Unsafe.ReadUnaligned(ref Unsafe.Add(ref bytes, offset))))
+ {
+ goto NotEqual;
+ }
+
+ offset += sizeof(int);
+ }
+ }
+ if ((byte*)(offset + sizeof(short)) <= (byte*)count)
+ {
+ if (!WidenTwoAsciiBytesToUtf16AndCompareToChars(
+ ref Unsafe.Add(ref str, offset),
+ Unsafe.ReadUnaligned(ref Unsafe.Add(ref bytes, offset))))
+ {
+ goto NotEqual;
+ }
+
+ offset += sizeof(short);
+ }
+ if ((byte*)offset < (byte*)count)
+ {
+ var ch = (char)Unsafe.Add(ref bytes, offset);
+ if (((ch & 0x80) != 0) || Unsafe.Add(ref str, offset) != ch)
+ {
+ goto NotEqual;
+ }
+ }
+
+ // End of input reached, there are no inequalities via widening; so the input bytes are both ascii
+ // and a match to the string if it was converted via Encoding.ASCII.GetString(...)
+ return true;
+ }
+
+ // Create a comparision vector for all bits being equal
+ var AllTrue = new Vector(-1);
+ // do/while as entry condition already checked, remaining length must be Vector.Count or larger.
+ do
+ {
+ // Read a Vector length from the input as bytes
+ var vector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref bytes, offset));
+ if (!CheckBytesInAsciiRange(vector))
+ {
+ goto NotEqual;
+ }
+ // Widen the bytes directly to chars (ushort) as if they were ascii.
+ // As widening doubles the size we get two vectors back.
+ Vector.Widen(vector, out var vector0, out var vector1);
+ // Read two char vectors from the string to perform the match.
+ var compare0 = Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref str, offset)));
+ var compare1 = Unsafe.ReadUnaligned>(ref Unsafe.As(ref Unsafe.Add(ref str, offset + Vector.Count)));
+
+ // If the string is not ascii, then the widened bytes cannot match
+ // as each widened byte element as chars will be in the range 0-255
+ // so cannot match any higher unicode values.
+
+ // Compare to our all bits true comparision vector
+ if (!AllTrue.Equals(
+ // BitwiseAnd the two equals together
+ Vector.BitwiseAnd(
+ // Check equality for the two widened vectors
+ Vector.Equals(compare0, vector0),
+ Vector.Equals(compare1, vector1))))
+ {
+ goto NotEqual;
+ }
+
+ offset += Vector.Count;
+ } while ((byte*)(offset + Vector.Count) <= (byte*)count);
+
+ // Vector path done, loop back to do non-Vector
+ // If is a exact multiple of vector size, bail now
+ } while ((byte*)offset < (byte*)count);
+
+ // If we get here (input is exactly a multiple of Vector length) then there are no inequalities via widening;
+ // so the input bytes are both ascii and a match to the string if it was converted via Encoding.ASCII.GetString(...)
+ return true;
+ NotEqual:
+ return false;
+ }
+
+ ///
+ /// Given a DWORD which represents a buffer of 4 bytes, widens the buffer into 4 WORDs and
+ /// compares them to the WORD buffer with machine endianness.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ private static bool WidenFourAsciiBytesToUtf16AndCompareToChars(ref char charStart, uint value)
+ {
+ if (!AllBytesInUInt32AreAscii(value))
+ {
+ return false;
+ }
+
+ if (Bmi2.X64.IsSupported)
+ {
+ // BMI2 will work regardless of the processor's endianness.
+ return Unsafe.ReadUnaligned(ref Unsafe.As(ref charStart)) ==
+ Bmi2.X64.ParallelBitDeposit(value, 0x00FF00FF_00FF00FFul);
+ }
+ else
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return charStart == (char)(byte)value &&
+ Unsafe.Add(ref charStart, 1) == (char)(byte)(value >> 8) &&
+ Unsafe.Add(ref charStart, 2) == (char)(byte)(value >> 16) &&
+ Unsafe.Add(ref charStart, 3) == (char)(value >> 24);
+ }
+ else
+ {
+ return Unsafe.Add(ref charStart, 3) == (char)(byte)value &&
+ Unsafe.Add(ref charStart, 2) == (char)(byte)(value >> 8) &&
+ Unsafe.Add(ref charStart, 1) == (char)(byte)(value >> 16) &&
+ charStart == (char)(value >> 24);
+ }
+ }
+ }
+
+ ///
+ /// Given a WORD which represents a buffer of 2 bytes, widens the buffer into 2 WORDs and
+ /// compares them to the WORD buffer with machine endianness.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+ private static bool WidenTwoAsciiBytesToUtf16AndCompareToChars(ref char charStart, ushort value)
+ {
+ if (!AllBytesInUInt16AreAscii(value))
+ {
+ return false;
+ }
+
+ if (Bmi2.IsSupported)
+ {
+ // BMI2 will work regardless of the processor's endianness.
+ return Unsafe.ReadUnaligned(ref Unsafe.As(ref charStart)) ==
+ Bmi2.ParallelBitDeposit(value, 0x00FF00FFu);
+ }
+ else
+ {
+ if (BitConverter.IsLittleEndian)
+ {
+ return charStart == (char)(byte)value &&
+ Unsafe.Add(ref charStart, 1) == (char)(byte)(value >> 8);
+ }
+ else
+ {
+ return Unsafe.Add(ref charStart, 1) == (char)(byte)value &&
+ charStart == (char)(byte)(value >> 8);
+ }
+ }
+ }
+
+ ///
+ /// Returns iff all bytes in are ASCII.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool AllBytesInUInt32AreAscii(uint value)
+ {
+ return ((value & 0x80808080u) == 0);
+ }
+
+ ///
+ /// Returns iff all bytes in are ASCII.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool AllBytesInUInt16AreAscii(ushort value)
+ {
+ return ((value & 0x8080u) == 0);
+ }
+
+ private unsafe static bool IsValidHeaderString(string value)
+ {
+ // Method for Debug.Assert to ensure BytesOrdinalEqualsStringAndAscii
+ // is not called with an unvalidated string comparitor.
+ try
+ {
+ if (value is null) return false;
+ new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetByteCount(value);
+ return !value.Contains('\0');
+ }
+ catch (DecoderFallbackException) {
+ return false;
+ }
+ }
+
private static readonly char[] s_encode16Chars = "0123456789ABCDEF".ToCharArray();
///
diff --git a/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs b/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs
index 3b29d1ee1a..bbe5d30b9a 100644
--- a/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs
+++ b/src/Servers/Kestrel/Core/src/KestrelServerOptions.cs
@@ -54,6 +54,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
///
public bool AllowSynchronousIO { get; set; } = false;
+ ///
+ /// Gets or sets a value that controls whether the string values materialized
+ /// will be reused across requests; if they match, or if the strings will always be reallocated.
+ ///
+ ///
+ /// Defaults to false.
+ ///
+ public bool DisableStringReuse { get; set; } = false;
+
///
/// Enables the Listen options callback to resolve and use services registered by the application during startup.
/// Typically initialized by UseKestrel()"/>.
diff --git a/src/Servers/Kestrel/Core/test/AsciiDecoding.cs b/src/Servers/Kestrel/Core/test/AsciiDecoding.cs
index 7fa45513d2..128b79fdd0 100644
--- a/src/Servers/Kestrel/Core/test/AsciiDecoding.cs
+++ b/src/Servers/Kestrel/Core/test/AsciiDecoding.cs
@@ -24,16 +24,28 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
.Concat(byteRange)
.ToArray();
- var s = new Span(byteArray).GetAsciiStringNonNullCharacters();
+ var span = new Span(byteArray);
- Assert.Equal(s.Length, byteArray.Length);
-
- for (var i = 1; i < byteArray.Length; i++)
+ for (var i = 0; i <= byteArray.Length; i++)
{
- var sb = (byte)s[i];
- var b = byteArray[i];
+ // Test all the lengths to hit all the different length paths e.g. Vector, long, short, char
+ Test(span.Slice(i));
+ }
- Assert.Equal(sb, b);
+ static void Test(Span asciiBytes)
+ {
+ var s = asciiBytes.GetAsciiStringNonNullCharacters();
+
+ Assert.True(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, asciiBytes));
+ Assert.Equal(s.Length, asciiBytes.Length);
+
+ for (var i = 0; i < asciiBytes.Length; i++)
+ {
+ var sb = (byte)s[i];
+ var b = asciiBytes[i];
+
+ Assert.Equal(sb, b);
+ }
}
}
@@ -59,8 +71,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
var byteRange = Enumerable.Range(0, 16384 + 64).Select(x => (byte)((x & 0x7f) | 0x01)).ToArray();
var expectedByteRange = byteRange.Concat(byteRange).ToArray();
-
- var s = new Span(expectedByteRange).GetAsciiStringNonNullCharacters();
+
+ var span = new Span(expectedByteRange);
+ var s = span.GetAsciiStringNonNullCharacters();
Assert.Equal(expectedByteRange.Length, s.Length);
@@ -68,8 +81,74 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
var sb = (byte)((s[i] & 0x7f) | 0x01);
var b = expectedByteRange[i];
+ }
- Assert.Equal(sb, b);
+ Assert.True(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, span));
+ }
+
+ [Fact]
+ private void DifferentLengthsAreNotEqual()
+ {
+ var byteRange = Enumerable.Range(0, 4096).Select(x => (byte)((x & 0x7f) | 0x01)).ToArray();
+ var expectedByteRange = byteRange.Concat(byteRange).ToArray();
+
+ for (var i = 1; i < byteRange.Length; i++)
+ {
+ var span = new Span(expectedByteRange);
+ var s = span.GetAsciiStringNonNullCharacters();
+
+ Assert.True(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, span));
+
+ // One off end
+ Assert.False(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, span.Slice(0, span.Length - 1)));
+ Assert.False(StringUtilities.BytesOrdinalEqualsStringAndAscii(s.Substring(0, s.Length - 1), span));
+
+ // One off start
+ Assert.False(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, span.Slice(1, span.Length - 1)));
+ Assert.False(StringUtilities.BytesOrdinalEqualsStringAndAscii(s.Substring(1, s.Length - 1), span));
+ }
+ }
+
+ [Fact]
+ private void AsciiBytesEqualAsciiStrings()
+ {
+ var byteRange = Enumerable.Range(1, 127).Select(x => (byte)x);
+
+ var byteArray = byteRange
+ .Concat(byteRange)
+ .Concat(byteRange)
+ .Concat(byteRange)
+ .Concat(byteRange)
+ .Concat(byteRange)
+ .ToArray();
+
+ var span = new Span(byteArray);
+
+ for (var i = 0; i <= byteArray.Length; i++)
+ {
+ // Test all the lengths to hit all the different length paths e.g. Vector, long, short, char
+ Test(span.Slice(i));
+ }
+
+ static void Test(Span asciiBytes)
+ {
+ var s = asciiBytes.GetAsciiStringNonNullCharacters();
+
+ // Should start as equal
+ Assert.True(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, asciiBytes));
+
+ for (var i = 0; i < asciiBytes.Length; i++)
+ {
+ var b = asciiBytes[i];
+
+ // Change one byte, ensure is not equal
+ asciiBytes[i] = (byte)(b + 1);
+ Assert.False(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, asciiBytes));
+
+ // Change byte back for next iteration, ensure is equal again
+ asciiBytes[i] = b;
+ Assert.True(StringUtilities.BytesOrdinalEqualsStringAndAscii(s, asciiBytes));
+ }
}
}
}
diff --git a/src/Servers/Kestrel/Core/test/HPackDecoderTests.cs b/src/Servers/Kestrel/Core/test/HPackDecoderTests.cs
index 598a7a6ed5..d9318e01e9 100644
--- a/src/Servers/Kestrel/Core/test/HPackDecoderTests.cs
+++ b/src/Servers/Kestrel/Core/test/HPackDecoderTests.cs
@@ -103,6 +103,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
_decodedHeaders[name.GetAsciiStringNonNullCharacters()] = value.GetAsciiStringNonNullCharacters();
}
+ void IHttpHeadersHandler.OnHeadersComplete() { }
+
[Fact]
public void DecodesIndexedHeaderField_StaticTable()
{
diff --git a/src/Servers/Kestrel/Core/test/HttpParserTests.cs b/src/Servers/Kestrel/Core/test/HttpParserTests.cs
index 825ee085de..0c7abe1b60 100644
--- a/src/Servers/Kestrel/Core/test/HttpParserTests.cs
+++ b/src/Servers/Kestrel/Core/test/HttpParserTests.cs
@@ -483,6 +483,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
Headers[name.GetAsciiStringNonNullCharacters()] = value.GetAsciiStringNonNullCharacters();
}
+ void IHttpHeadersHandler.OnHeadersComplete() { }
+
public void OnStartLine(HttpMethod method, HttpVersion version, Span target, Span path, Span query, Span customMethod, bool pathEncoded)
{
Method = method != HttpMethod.Custom ? HttpUtilities.MethodToString(method) : customMethod.GetAsciiStringNonNullCharacters();
diff --git a/src/Servers/Kestrel/Core/test/HttpRequestHeadersTests.cs b/src/Servers/Kestrel/Core/test/HttpRequestHeadersTests.cs
index 1eef7c792c..a7603b9190 100644
--- a/src/Servers/Kestrel/Core/test/HttpRequestHeadersTests.cs
+++ b/src/Servers/Kestrel/Core/test/HttpRequestHeadersTests.cs
@@ -3,11 +3,13 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.Extensions.Primitives;
using Xunit;
+using static CodeGenerator.KnownHeaders;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
@@ -307,8 +309,347 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var encoding = Encoding.GetEncoding("iso-8859-1");
var exception = Assert.Throws(
- () => headers.Append(encoding.GetBytes(key), "value"));
+ () => headers.Append(encoding.GetBytes(key), Encoding.ASCII.GetBytes("value")));
Assert.Equal(StatusCodes.Status400BadRequest, exception.StatusCode);
}
+
+ [Theory]
+ [MemberData(nameof(KnownRequestHeaders))]
+ public void ValueReuseOnlyWhenAllowed(bool reuseValue, KnownHeader header)
+ {
+ const string HeaderValue = "Hello";
+ var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
+
+ for (var i = 0; i < 6; i++)
+ {
+ var prevName = ChangeNameCase(header.Name, variant: i);
+ var nextName = ChangeNameCase(header.Name, variant: i + 1);
+
+ var values = GetHeaderValues(headers, prevName, nextName, HeaderValue, HeaderValue);
+
+ Assert.Equal(HeaderValue, values.PrevHeaderValue);
+ Assert.NotSame(HeaderValue, values.PrevHeaderValue);
+
+ Assert.Equal(HeaderValue, values.NextHeaderValue);
+ Assert.NotSame(HeaderValue, values.NextHeaderValue);
+
+ Assert.Equal(values.PrevHeaderValue, values.NextHeaderValue);
+ if (reuseValue)
+ {
+ // When materalized string is reused previous and new should be the same object
+ Assert.Same(values.PrevHeaderValue, values.NextHeaderValue);
+ }
+ else
+ {
+ // When materalized string is not reused previous and new should be the different objects
+ Assert.NotSame(values.PrevHeaderValue, values.NextHeaderValue);
+ }
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(KnownRequestHeaders))]
+ public void ValueReuseChangedValuesOverwrite(bool reuseValue, KnownHeader header)
+ {
+ const string HeaderValue1 = "Hello1";
+ const string HeaderValue2 = "Hello2";
+ var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
+
+ for (var i = 0; i < 6; i++)
+ {
+ var prevName = ChangeNameCase(header.Name, variant: i);
+ var nextName = ChangeNameCase(header.Name, variant: i + 1);
+
+ var values = GetHeaderValues(headers, prevName, nextName, HeaderValue1, HeaderValue2);
+
+ Assert.Equal(HeaderValue1, values.PrevHeaderValue);
+ Assert.NotSame(HeaderValue1, values.PrevHeaderValue);
+
+ Assert.Equal(HeaderValue2, values.NextHeaderValue);
+ Assert.NotSame(HeaderValue2, values.NextHeaderValue);
+
+ Assert.NotEqual(values.PrevHeaderValue, values.NextHeaderValue);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(KnownRequestHeaders))]
+ public void ValueReuseMissingValuesClear(bool reuseValue, KnownHeader header)
+ {
+ const string HeaderValue1 = "Hello1";
+ var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
+
+ for (var i = 0; i < 6; i++)
+ {
+ var prevName = ChangeNameCase(header.Name, variant: i);
+ var nextName = ChangeNameCase(header.Name, variant: i + 1);
+
+ var values = GetHeaderValues(headers, prevName, nextName, HeaderValue1, nextValue: null);
+
+ Assert.Equal(HeaderValue1, values.PrevHeaderValue);
+ Assert.NotSame(HeaderValue1, values.PrevHeaderValue);
+
+ Assert.Equal(string.Empty, values.NextHeaderValue);
+
+ Assert.NotEqual(values.PrevHeaderValue, values.NextHeaderValue);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(KnownRequestHeaders))]
+ public void ValueReuseNeverWhenNotAscii(bool reuseValue, KnownHeader header)
+ {
+ const string HeaderValue = "Hello \u03a0";
+
+ var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
+
+ for (var i = 0; i < 6; i++)
+ {
+ var prevName = ChangeNameCase(header.Name, variant: i);
+ var nextName = ChangeNameCase(header.Name, variant: i + 1);
+
+ var values = GetHeaderValues(headers, prevName, nextName, HeaderValue, HeaderValue);
+
+ Assert.Equal(HeaderValue, values.PrevHeaderValue);
+ Assert.NotSame(HeaderValue, values.PrevHeaderValue);
+
+ Assert.Equal(HeaderValue, values.NextHeaderValue);
+ Assert.NotSame(HeaderValue, values.NextHeaderValue);
+
+ Assert.Equal(values.PrevHeaderValue, values.NextHeaderValue);
+
+ Assert.NotSame(values.PrevHeaderValue, values.NextHeaderValue);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(KnownRequestHeaders))]
+ public void ValueReuseLatin1NotConfusedForUtf16AndStillRejected(bool reuseValue, KnownHeader header)
+ {
+ var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
+
+ var headerValue = new char[127]; // 64 + 32 + 16 + 8 + 4 + 2 + 1
+ for (var i = 0; i < headerValue.Length; i++)
+ {
+ headerValue[i] = 'a';
+ }
+
+ for (var i = 0; i < headerValue.Length; i++)
+ {
+ // Set non-ascii Latin char that is valid Utf16 when widened; but not a valid utf8 -> utf16 conversion.
+ headerValue[i] = '\u00a3';
+
+ for (var mode = 0; mode <= 1; mode++)
+ {
+ string headerValueUtf16Latin1CrossOver;
+ if (mode == 0)
+ {
+ // Full length
+ headerValueUtf16Latin1CrossOver = new string(headerValue);
+ }
+ else
+ {
+ // Truncated length (to ensure different paths from changing lengths in matching)
+ headerValueUtf16Latin1CrossOver = new string(headerValue.AsSpan().Slice(0, i + 1));
+ }
+
+ headers.Reset();
+
+ var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
+ var prevSpan = Encoding.UTF8.GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();
+
+ headers.Append(headerName, prevSpan);
+ headers.OnHeadersComplete();
+ var prevHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();
+
+ Assert.Equal(headerValueUtf16Latin1CrossOver, prevHeaderValue);
+ Assert.NotSame(headerValueUtf16Latin1CrossOver, prevHeaderValue);
+
+ headers.Reset();
+
+ Assert.Throws(() =>
+ {
+ var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
+ var nextSpan = Encoding.GetEncoding("iso-8859-1").GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();
+
+ Assert.False(nextSpan.SequenceEqual(Encoding.ASCII.GetBytes(headerValueUtf16Latin1CrossOver)));
+
+ headers.Append(headerName, nextSpan);
+ });
+ }
+
+ // Reset back to Ascii
+ headerValue[i] = 'a';
+ }
+ }
+
+ [Fact]
+ public void ValueReuseNeverWhenUnknownHeader()
+ {
+ const string HeaderName = "An-Unknown-Header";
+ const string HeaderValue = "Hello";
+
+ var headers = new HttpRequestHeaders(reuseHeaderValues: true);
+
+ for (var i = 0; i < 6; i++)
+ {
+ var prevName = ChangeNameCase(HeaderName, variant: i);
+ var nextName = ChangeNameCase(HeaderName, variant: i + 1);
+
+ var values = GetHeaderValues(headers, prevName, nextName, HeaderValue, HeaderValue);
+
+ Assert.Equal(HeaderValue, values.PrevHeaderValue);
+ Assert.NotSame(HeaderValue, values.PrevHeaderValue);
+
+ Assert.Equal(HeaderValue, values.NextHeaderValue);
+ Assert.NotSame(HeaderValue, values.NextHeaderValue);
+
+ Assert.Equal(values.PrevHeaderValue, values.NextHeaderValue);
+
+ Assert.NotSame(values.PrevHeaderValue, values.NextHeaderValue);
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(KnownRequestHeaders))]
+ public void ValueReuseEmptyAfterReset(bool reuseValue, KnownHeader header)
+ {
+ const string HeaderValue = "Hello";
+
+ var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
+ var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
+ var prevSpan = Encoding.UTF8.GetBytes(HeaderValue).AsSpan();
+
+ headers.Append(headerName, prevSpan);
+ headers.OnHeadersComplete();
+ var prevHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();
+
+ Assert.NotNull(prevHeaderValue);
+ Assert.NotEqual(string.Empty, prevHeaderValue);
+ Assert.Equal(HeaderValue, prevHeaderValue);
+ Assert.NotSame(HeaderValue, prevHeaderValue);
+ Assert.Single(headers);
+ var count = headers.Count;
+ Assert.Equal(1, count);
+
+ headers.Reset();
+
+ // Empty after reset
+ var nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();
+
+ Assert.NotNull(nextHeaderValue);
+ Assert.Equal(string.Empty, nextHeaderValue);
+ Assert.NotEqual(HeaderValue, nextHeaderValue);
+ Assert.Empty(headers);
+ count = headers.Count;
+ Assert.Equal(0, count);
+
+ headers.OnHeadersComplete();
+
+ // Still empty after complete
+ nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();
+
+ Assert.NotNull(nextHeaderValue);
+ Assert.Equal(string.Empty, nextHeaderValue);
+ Assert.NotEqual(HeaderValue, nextHeaderValue);
+ Assert.Empty(headers);
+ count = headers.Count;
+ Assert.Equal(0, count);
+ }
+
+ [Theory]
+ [MemberData(nameof(KnownRequestHeaders))]
+ public void MultiValueReuseEmptyAfterReset(bool reuseValue, KnownHeader header)
+ {
+ const string HeaderValue1 = "Hello1";
+ const string HeaderValue2 = "Hello2";
+
+ var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
+ var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
+ var prevSpan1 = Encoding.UTF8.GetBytes(HeaderValue1).AsSpan();
+ var prevSpan2 = Encoding.UTF8.GetBytes(HeaderValue2).AsSpan();
+
+ headers.Append(headerName, prevSpan1);
+ headers.Append(headerName, prevSpan2);
+ headers.OnHeadersComplete();
+ var prevHeaderValue = ((IHeaderDictionary)headers)[header.Name];
+
+ Assert.Equal(2, prevHeaderValue.Count);
+
+ Assert.NotEqual(string.Empty, prevHeaderValue.ToString());
+ Assert.Single(headers);
+ var count = headers.Count;
+ Assert.Equal(1, count);
+
+ headers.Reset();
+
+ // Empty after reset
+ var nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();
+
+ Assert.NotNull(nextHeaderValue);
+ Assert.Equal(string.Empty, nextHeaderValue);
+ Assert.Empty(headers);
+ count = headers.Count;
+ Assert.Equal(0, count);
+
+ headers.OnHeadersComplete();
+
+ // Still empty after complete
+ nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();
+
+ Assert.NotNull(nextHeaderValue);
+ Assert.Equal(string.Empty, nextHeaderValue);
+ Assert.Empty(headers);
+ count = headers.Count;
+ Assert.Equal(0, count);
+ }
+
+ private static (string PrevHeaderValue, string NextHeaderValue) GetHeaderValues(HttpRequestHeaders headers, string prevName, string nextName, string prevValue, string nextValue)
+ {
+ headers.Reset();
+ var headerName = Encoding.ASCII.GetBytes(prevName).AsSpan();
+ var prevSpan = Encoding.UTF8.GetBytes(prevValue).AsSpan();
+
+ headers.Append(headerName, prevSpan);
+ headers.OnHeadersComplete();
+ var prevHeaderValue = ((IHeaderDictionary)headers)[prevName].ToString();
+
+ headers.Reset();
+
+ if (nextValue != null)
+ {
+ headerName = Encoding.ASCII.GetBytes(prevName).AsSpan();
+ var nextSpan = Encoding.UTF8.GetBytes(nextValue).AsSpan();
+ headers.Append(headerName, nextSpan);
+ }
+
+ headers.OnHeadersComplete();
+
+ var newHeaderValue = ((IHeaderDictionary)headers)[nextName].ToString();
+
+ return (prevHeaderValue, newHeaderValue);
+ }
+
+ private static string ChangeNameCase(string name, int variant)
+ {
+ switch ((variant / 2) % 3)
+ {
+ case 0:
+ return name;
+ case 1:
+ return name.ToLowerInvariant();
+ case 2:
+ return name.ToUpperInvariant();
+ }
+
+ // Never reached
+ Assert.False(true);
+ return name;
+ }
+
+ // Content-Length is numeric not a string, so we exclude it from the string reuse tests
+ public static IEnumerable