Browse Source

Merge aspnet/KestrelHttpServer release/2.2 and release/2.1

Nate McMaster 7 years ago
parent
commit
0271428dbe
100 changed files with 15923 additions and 137 deletions
  1. 1 0
      .gitignore
  2. 0 4
      .gitmodules
  3. 23 105
      README.md
  4. 0 2
      build/artifacts.props
  5. 0 1
      build/buildorder.props
  6. 2 0
      build/dependencies.props
  7. 2 0
      build/external-dependencies.props
  8. 6 0
      build/repo.props
  9. 0 6
      build/sources.props
  10. 0 1
      build/submodules.props
  11. 137 0
      docs/BuildFromSource.md
  12. 99 0
      docs/DailyBuilds.md
  13. 111 15
      eng/Baseline.props
  14. 12 0
      eng/Dependencies.props
  15. 9 0
      eng/ProjectReferences.props
  16. 15 0
      eng/dependencies.temp.props
  17. 1 1
      eng/targets/CSharp.Common.props
  18. 8 1
      eng/tools/BaselineGenerator/baseline.xml
  19. 0 1
      modules/KestrelHttpServer
  20. 43 0
      src/Servers/Connections.Abstractions/src/ConnectionBuilder.cs
  21. 43 0
      src/Servers/Connections.Abstractions/src/ConnectionBuilderExtensions.cs
  22. 31 0
      src/Servers/Connections.Abstractions/src/ConnectionContext.cs
  23. 6 0
      src/Servers/Connections.Abstractions/src/ConnectionDelegate.cs
  24. 20 0
      src/Servers/Connections.Abstractions/src/ConnectionHandler.cs
  25. 116 0
      src/Servers/Connections.Abstractions/src/ConnectionItems.cs
  26. 78 0
      src/Servers/Connections.Abstractions/src/DefaultConnectionContext.cs
  27. 18 0
      src/Servers/Connections.Abstractions/src/Exceptions/AddressInUseException.cs
  28. 21 0
      src/Servers/Connections.Abstractions/src/Exceptions/ConnectionAbortedException.cs
  29. 19 0
      src/Servers/Connections.Abstractions/src/Exceptions/ConnectionResetException.cs
  30. 12 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionHeartbeatFeature.cs
  31. 10 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionIdFeature.cs
  32. 20 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionInherentKeepAliveFeature.cs
  33. 12 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionItemsFeature.cs
  34. 14 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionLifetimeFeature.cs
  35. 14 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionLifetimeNotificationFeature.cs
  36. 12 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionTransportFeature.cs
  37. 9 0
      src/Servers/Connections.Abstractions/src/Features/IConnectionUserFeature.cs
  38. 12 0
      src/Servers/Connections.Abstractions/src/Features/IMemoryPoolFeature.cs
  39. 24 0
      src/Servers/Connections.Abstractions/src/Features/ITlsHandshakeFeature.cs
  40. 11 0
      src/Servers/Connections.Abstractions/src/Features/ITransferFormatFeature.cs
  41. 13 0
      src/Servers/Connections.Abstractions/src/IConnectionBuilder.cs
  42. 17 0
      src/Servers/Connections.Abstractions/src/Microsoft.AspNetCore.Connections.Abstractions.csproj
  43. 14 0
      src/Servers/Connections.Abstractions/src/TransferFormat.cs
  44. 1060 0
      src/Servers/Connections.Abstractions/src/baseline.netcore.json
  45. 7 0
      src/Servers/Connections.Abstractions/src/breakingchanges.netcore.json
  46. 12 0
      src/Servers/Directory.Build.props
  47. 375 0
      src/Servers/Kestrel.sln
  48. 172 0
      src/Servers/Kestrel/Core/src/Adapter/Internal/AdaptedPipeline.cs
  49. 26 0
      src/Servers/Kestrel/Core/src/Adapter/Internal/ConnectionAdapterContext.cs
  50. 13 0
      src/Servers/Kestrel/Core/src/Adapter/Internal/IAdaptedConnection.cs
  51. 13 0
      src/Servers/Kestrel/Core/src/Adapter/Internal/IConnectionAdapter.cs
  52. 47 0
      src/Servers/Kestrel/Core/src/Adapter/Internal/LoggingConnectionAdapter.cs
  53. 266 0
      src/Servers/Kestrel/Core/src/Adapter/Internal/LoggingStream.cs
  54. 223 0
      src/Servers/Kestrel/Core/src/Adapter/Internal/RawStream.cs
  55. 38 0
      src/Servers/Kestrel/Core/src/Adapter/ListenOptionsConnectionLoggingExtensions.cs
  56. 37 0
      src/Servers/Kestrel/Core/src/AnyIPListenOptions.cs
  57. 178 0
      src/Servers/Kestrel/Core/src/BadHttpRequestException.cs
  58. 26 0
      src/Servers/Kestrel/Core/src/ClientCertificateMode.cs
  59. 593 0
      src/Servers/Kestrel/Core/src/CoreStrings.resx
  60. 26 0
      src/Servers/Kestrel/Core/src/EndpointConfiguration.cs
  61. 31 0
      src/Servers/Kestrel/Core/src/Features/IConnectionTimeoutFeature.cs
  62. 17 0
      src/Servers/Kestrel/Core/src/Features/IDecrementConcurrentConnectionCountFeature.cs
  63. 10 0
      src/Servers/Kestrel/Core/src/Features/IHttp2StreamIdFeature.cs
  64. 22 0
      src/Servers/Kestrel/Core/src/Features/IHttpMinRequestBodyDataRateFeature.cs
  65. 22 0
      src/Servers/Kestrel/Core/src/Features/IHttpMinResponseDataRateFeature.cs
  66. 12 0
      src/Servers/Kestrel/Core/src/Features/ITlsApplicationProtocolFeature.cs
  67. 145 0
      src/Servers/Kestrel/Core/src/Http2Limits.cs
  68. 16 0
      src/Servers/Kestrel/Core/src/HttpProtocols.cs
  69. 97 0
      src/Servers/Kestrel/Core/src/HttpsConnectionAdapterOptions.cs
  70. 20 0
      src/Servers/Kestrel/Core/src/Internal/AddressBindContext.cs
  71. 268 0
      src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs
  72. 153 0
      src/Servers/Kestrel/Core/src/Internal/BufferReader.cs
  73. 96 0
      src/Servers/Kestrel/Core/src/Internal/BufferWriter.cs
  74. 97 0
      src/Servers/Kestrel/Core/src/Internal/CertificateLoader.cs
  75. 68 0
      src/Servers/Kestrel/Core/src/Internal/ClosedStream.cs
  76. 195 0
      src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs
  77. 154 0
      src/Servers/Kestrel/Core/src/Internal/ConnectionDispatcher.cs
  78. 74 0
      src/Servers/Kestrel/Core/src/Internal/ConnectionLimitMiddleware.cs
  79. 63 0
      src/Servers/Kestrel/Core/src/Internal/ConnectionLogScope.cs
  80. 39 0
      src/Servers/Kestrel/Core/src/Internal/DuplexPipe.cs
  81. 63 0
      src/Servers/Kestrel/Core/src/Internal/Http/ChunkWriter.cs
  82. 16 0
      src/Servers/Kestrel/Core/src/Internal/Http/ConnectionOptions.cs
  83. 59 0
      src/Servers/Kestrel/Core/src/Internal/Http/DateHeaderValueManager.cs
  84. 29 0
      src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.FeatureCollection.cs
  85. 545 0
      src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs
  86. 678 0
      src/Servers/Kestrel/Core/src/Internal/Http/Http1MessageBody.cs
  87. 184 0
      src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs
  88. 23 0
      src/Servers/Kestrel/Core/src/Internal/Http/Http1ParsingHandler.cs
  89. 4796 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs
  90. 461 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.cs
  91. 22 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpMethod.cs
  92. 475 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs
  93. 254 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.FeatureCollection.cs
  94. 645 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs
  95. 1326 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs
  96. 101 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs
  97. 224 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestStream.cs
  98. 15 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestTargetForm.cs
  99. 109 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseHeaders.cs
  100. 172 0
      src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseStream.cs

+ 1 - 0
.gitignore

@@ -25,3 +25,4 @@ scripts/tmp/
 .dotnet/
 .tools/
 src/**/global.json
+launchSettings.json

+ 0 - 4
.gitmodules

@@ -58,10 +58,6 @@
 	path = modules/JavaScriptServices
 	url = https://github.com/aspnet/JavaScriptServices.git
 	branch = release/2.2
-[submodule "modules/KestrelHttpServer"]
-	path = modules/KestrelHttpServer
-	url = https://github.com/aspnet/KestrelHttpServer.git
-	branch = release/2.2
 [submodule "modules/Localization"]
 	path = modules/Localization
 	url = https://github.com/aspnet/Localization.git

+ 23 - 105
README.md

@@ -1,120 +1,38 @@
 ASP.NET Core
-========
+============
 
-Build infrastructure used to produce the whole ASP.NET Core stack.
+ASP.NET Core is an open-source and cross-platform framework for building modern cloud based internet connected applications, such as web apps, IoT apps and mobile backends. ASP.NET Core apps can run on .NET Core or on the full .NET Framework. It was architected to provide an optimized development framework for apps that are deployed to the cloud or run on-premises. It consists of modular components with minimal overhead, so you retain flexibility while constructing your solutions. You can develop and run your ASP.NET Core apps cross-platform on Windows, Mac and Linux. [Learn more about ASP.NET Core](https://docs.microsoft.com/aspnet/core/).
 
-## Released Builds
+## Get Started
 
-### ASP.NET Core Runtime Store
+Follow the [Getting Started](https://docs.microsoft.com/aspnet/core/getting-started) instructions in the [ASP.NET Core docs](https://docs.microsoft.com/aspnet/index).
 
-The runtime store can be downloaded from [here](https://microsoft.com/net/download).
+Also check out the [.NET Homepage](https://www.microsoft.com/net) for released versions of .NET, getting started guides, and learning resources.
 
-### NuGet packages
+## How to Engage, Contribute, and Give Feedback
 
-All published ASP.NET Core packages can be found on <https://www.nuget.org/profiles/aspnet>.
+Some of the best ways to contribute are to try things out, file issues, join in design conversations,
+and make pull-requests.
 
-Commonly referenced packages:
+* [Download our latest daily builds](./docs/DailyBuilds.md)
+* Follow along with the development of ASP.NET Core:
+    * [Community Standup](http://live.asp.net): The community standup is held every week and streamed live to YouTube. You can view past standups in the linked playlist.
+    * [Roadmap](https://github.com/aspnet/AspNetCore/wiki/Roadmap): The schedule and milestone themes for ASP.NET Core.
+* [Build ASP.NET Core source code](./docs/BuildFromSource.md)
+* Check out the [contributing](CONTRIBUTING.md) page to see the best places to log issues and start discussions.
 
-[app-metapackage-nuget]:  https://nuget.org/packages/Microsoft.AspNetCore.App
-[app-metapackage-nuget-badge]: https://img.shields.io/nuget/v/Microsoft.AspNetCore.App.svg?style=flat-square&label=nuget
+## Reporting security issues and bugs
 
-[metapackage-nuget]:  https://nuget.org/packages/Microsoft.AspNetCore
-[metapackage-nuget-badge]: https://img.shields.io/nuget/v/Microsoft.AspNetCore.svg?style=flat-square&label=nuget
+Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC)  [email protected]. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the [Security TechCenter](https://technet.microsoft.com/en-us/security/ff852094.aspx).
 
-Package                           | NuGet.org
-:---------------------------------|:---------------------------------------------------------
-Microsoft.AspNetCore.App          | [![][app-metapackage-nuget-badge]][app-metapackage-nuget]
-Microsoft.AspNetCore              | [![][metapackage-nuget-badge]][metapackage-nuget]
+## Related projects
 
+These are some other repos for related projects:
 
-## Daily builds
+* [Documentation](https://github.com/aspnet/Docs) - documentation sources for https://docs.microsoft.com/aspnet/core/
+* [Entity Framework Core](https://github.com/aspnet/EntityFrameworkCore) - data access technology
+* [Extensions](https://github.com/aspnet/Extensions) - Logging, configuration, dependency injection, and more.
 
-### NuGet packages
+## Code of conduct
 
-Packages can be found on <https://dotnet.myget.org/gallery/dotnet-core>. This feed may include
-packages that will not be supported in a officially released build.
-
-Commonly referenced packages:
-
-[app-metapackage-myget]:  https://dotnet.myget.org/feed/dotnet-core/package/nuget/Microsoft.AspNetCore.App
-[app-metapackage-myget-badge]: https://img.shields.io/dotnet.myget/dotnet-core/v/Microsoft.AspNetCore.App.svg?style=flat-square&label=myget
-
-[metapackage-myget]:  https://dotnet.myget.org/feed/dotnet-core/package/nuget/Microsoft.AspNetCore
-[metapackage-myget-badge]: https://img.shields.io/dotnet.myget/dotnet-core/v/Microsoft.AspNetCore.svg?style=flat-square&label=myget
-
-Package                           | MyGet
-:---------------------------------|:---------------------------------------------------------
-Microsoft.AspNetCore.App          | [![][app-metapackage-myget-badge]][app-metapackage-myget]
-Microsoft.AspNetCore              | [![][metapackage-myget-badge]][metapackage-myget]
-
-### ASP.NET Core Shared Framework
-
-[badge-master]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-win-x64-version-badge.svg
-[win-x64-zip]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x64.zip
-[win-x64-exe]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x64.exe
-[win-x86-zip]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x86.zip
-[win-x86-exe]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x86.exe
-[linux-x64-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-linux-x64.tar.gz
-[linux-arm-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-linux-arm.tar.gz
-[osx-x64-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-osx-x64.tar.gz
-[debian-x64-deb]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-x64.deb
-[redhat-x64-rpm]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-x64.rpm
-[linux-musl-x64-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-linux-musl-x64.tar.gz
-
-[badge-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-win-x64-version-badge.svg
-[win-x64-zip-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x64.zip
-[win-x64-exe-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x64.exe
-[win-x86-zip-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x86.zip
-[win-x86-exe-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x86.exe
-[linux-x64-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-linux-x64.tar.gz
-[osx-x64-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-osx-x64.tar.gz
-[debian-x64-deb-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-x64.deb
-[redhat-x64-rpm-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-x64.rpm
-[linux-arm-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-linux-arm.tar.gz
-[linux-musl-x64-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-linux-musl-x64.tar.gz
-
-[badge-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-win-x64-version-badge.svg
-[win-x64-zip-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x64.zip
-[win-x64-exe-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x64.exe
-[win-x86-zip-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x86.zip
-[win-x86-exe-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x86.exe
-[linux-x64-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-linux-x64.tar.gz
-[osx-x64-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-osx-x64.tar.gz
-[debian-x64-deb-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-x64.deb
-[redhat-x64-rpm-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-x64.rpm
-[linux-arm-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-linux-arm.tar.gz
-[linux-musl-x64-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-linux-musl-x64.tar.gz
-
-Platform              | Latest (dev branch) <br> ![][badge-master]                      | release/2.2 <br> ![][badge-rel-22] | release/2.1 <br> ![][badge-rel-21]
-:---------------------|:----------------------------------------------------------------|:------------------------------------------------------------------------- |:-------------------------------------------------------------------------
-Channel name<sup>1</sup> | `master` | `release/2.2` | `release/2.1`
-Windows (x64)         | [Installer (exe)][win-x64-exe]<br>[Archive (zip)][win-x64-zip]   | [Installer (exe)][win-x64-exe-rel-22]<br>[Archive (zip)][win-x64-zip-rel-22] | [Installer (exe)][win-x64-exe-rel-21]<br>[Archive (zip)][win-x64-zip-rel-21]
-Windows (x86)         | [Installer (exe)][win-x86-exe]<br>[Archive (zip)][win-x86-zip]   | [Installer (exe)][win-x86-exe-rel-22]<br>[Archive (zip)][win-x86-zip-rel-22] | [Installer (exe)][win-x86-exe-rel-21]<br>[Archive (zip)][win-x86-zip-rel-21]
-macOS (x64)           | [Archive (tar.gz)][osx-x64-tar]                                  | [Archive (tar.gz)][osx-x64-tar-rel-22] | [Archive (tar.gz)][osx-x64-tar-rel-21]
-Linux (x64)<br>_(for glibc based OS - most common)_ | [Archive (tar.gz)][linux-x64-tar]                                | [Archive (tar.gz)][linux-x64-tar-rel-22] | [Archive (tar.gz)][linux-x64-tar-rel-21]
-Linux (x64 - musl)<br>_(for musl based OS, such as Alpine Linux)_ | [Archive (tar.gz)][linux-musl-x64-tar]                           | [Archive (tar.gz)][linux-musl-x64-tar-rel-22] | [Archive (tar.gz)][linux-musl-x64-tar-rel-21]
-Linux (arm32)         | [Archive (tar.gz)][linux-arm-tar]                                | [Archive (tar.gz)][linux-arm-tar-rel-22] | [Archive (tar.gz)][linux-arm-tar-rel-21]
-Debian/Ubuntu (x64)   | [Installer (deb)][debian-x64-deb]                                | [Installer (deb)][debian-x64-deb-rel-22] | [Installer (deb)][debian-x64-deb-rel-21]
-RedHat/Fedora (x64)   | [Installer (rpm)][redhat-x64-rpm]                                | [Installer (rpm)][redhat-x64-rpm-rel-22] | [Installer (rpm)][redhat-x64-rpm-rel-21]
-
-> <sup>1</sup> For use with the `-Channel` argument in [dotnet-install.ps1/sh](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script).
-
-## Building from source
-
-```
-git clone --recursive https://github.com/aspnet/AspNetCore.git
-cd AspNetCore
-./build.cmd
-```
-
-### Useful properties and targets
-Property                           | Purpose                                                                        | Example
------------------------------------|--------------------------------------------------------------------------------|--------
-`SkipTests`    | Only build repos, don't run the tests.                                         | `/p:SkipTests=true`
-`TestOnly`                      | Don't package or verify things.                                                | `/p:TestOnly=true`
-`KOREBUILD_REPOSITORY_INCLUDE` | A list of the repositories to include in build (instead of all of them).       | `$env:KOREBUILD_REPOSITORY_INCLUDE='Antiforgery;CORS'`
-`KOREBUILD_REPOSITORY_EXCLUDE` | A list of the repositories to exclude from build (all the rest will be built). | `$env:KOREBUILD_REPOSITORY_EXCLUDE='EntityFramework'`
-
-## More info
-
-This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).  For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.

+ 0 - 2
build/artifacts.props

@@ -186,8 +186,6 @@
     <PackageArtifact Include="Microsoft.EntityFrameworkCore" Category="ship" />
     <PackageArtifact Include="Microsoft.Extensions.ApiDescription.Design" Category="ship" />
     <PackageArtifact Include="Microsoft.Extensions.ApplicationModelDetection" Category="noship" />
-    <PackageArtifact Include="Microsoft.Extensions.Buffers.MemoryPool.Sources" Category="noship" />
-    <PackageArtifact Include="Microsoft.Extensions.Buffers.Testing.Sources" Category="noship" />
     <PackageArtifact Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" Category="ship" />
     <PackageArtifact Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Category="ship" />
     <PackageArtifact Include="Microsoft.Extensions.Diagnostics.HealthChecks" Category="ship"  />

+ 0 - 1
build/buildorder.props

@@ -11,7 +11,6 @@
     <RepositoryBuildOrder Include="HttpAbstractions" Order="6" />
     <RepositoryBuildOrder Include="HttpClientFactory" Order="6" />
     <RepositoryBuildOrder Include="Hosting" Order="7" />
-    <RepositoryBuildOrder Include="KestrelHttpServer" Order="8" />
     <RepositoryBuildOrder Include="EntityFrameworkCore" Order="8" />
     <RepositoryBuildOrder Include="HttpSysServer" Order="8" />
     <RepositoryBuildOrder Include="BrowserLink" Order="8" />

+ 2 - 0
build/dependencies.props

@@ -90,6 +90,8 @@
     <MicrosoftExtensionsValueStopwatchSourcesPackageVersion>2.2.0</MicrosoftExtensionsValueStopwatchSourcesPackageVersion>
     <MicrosoftExtensionsWebEncodersPackageVersion>2.2.0</MicrosoftExtensionsWebEncodersPackageVersion>
     <MicrosoftExtensionsWebEncodersSourcesPackageVersion>2.2.0</MicrosoftExtensionsWebEncodersSourcesPackageVersion>
+    <MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.2.0</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
+    <MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>2.2.0</MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion>
 
     <!-- 3rd party dependencies -->
     <AngleSharpPackageVersion>0.9.9</AngleSharpPackageVersion>

+ 2 - 0
build/external-dependencies.props

@@ -73,6 +73,8 @@
     <ExternalDependency Include="Microsoft.Extensions.ValueStopwatch.Sources" Version="$(MicrosoftExtensionsValueStopwatchSourcesPackageVersion)" />
     <ExternalDependency Include="Microsoft.Extensions.WebEncoders.Sources" Version="$(MicrosoftExtensionsWebEncodersSourcesPackageVersion)" />
     <ExternalDependency Include="Microsoft.Extensions.WebEncoders" Version="$(MicrosoftExtensionsWebEncodersPackageVersion)" />
+    <ExternalDependency Include="Microsoft.Extensions.Buffers.Testing.Sources" Version="$(MicrosoftExtensionsBuffersTestingSourcesPackageVersion)" />
+    <ExternalDependency Include="Microsoft.Extensions.Buffers.MemoryPool.Sources" Version="$(MicrosoftExtensionsBuffersMemoryPoolSourcesPackageVersion)" />
   </ItemGroup>
 
   <ItemGroup>

+ 6 - 0
build/repo.props

@@ -49,6 +49,11 @@
   </ItemGroup>
 
   <ItemGroup>
+    <SamplesProject Include="$(RepositoryRoot)src\samples\**\*.csproj;"/>
+
+    <ProjectToExclude Include="@(SamplesProject)" Condition="'$(BuildSamples)' == 'false' "/>
+
+    <!-- Exclude the websockets samples for now because they use classic .csproj, which is not yet supported in our build. -->
     <ProjectToExclude Include="
                        $(RepositoryRoot)src\Middleware\WebSockets\samples\**\*.csproj;
                        $(RepositoryRoot)src\Tools\dotnet-watch\test\TestProjects\**\*.csproj;
@@ -58,6 +63,7 @@
                       $(RepositoryRoot)src\Features\JsonPatch\**\*.*proj;
                       $(RepositoryRoot)src\DataProtection\**\*.*proj;
                       $(RepositoryRoot)src\Html\**\*.*proj;
+                      $(RepositoryRoot)src\Servers\**\*.*proj;
                       $(RepositoryRoot)src\Tools\**\*.*proj;
                       $(RepositoryRoot)src\Middleware\**\*.*proj;
                       "

+ 0 - 6
build/sources.props

@@ -8,12 +8,6 @@
       $(DotNetRestoreSources);
     </RestoreSources>
 
-    <!-- This is the 2.2.0 RTM feed. This is necessary until 2.2.0 ships to nuget.org -->
-    <RestoreSources>
-      $(RestoreSources);
-      https://dotnetfeed.blob.core.windows.net/orchestrated-release-2-2/20181110-02/final/index.json;
-    </RestoreSources>
-
     <RestoreSources Condition=" '$(DotNetBuildOffline)' != 'true' ">
       $(RestoreSources);
       https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json;

+ 0 - 1
build/submodules.props

@@ -61,7 +61,6 @@
     <ShippedRepository Include="HttpSysServer" />
     <ShippedRepository Include="Identity" />
     <ShippedRepository Include="JavaScriptServices" />
-    <ShippedRepository Include="KestrelHttpServer" />
     <ShippedRepository Include="Localization" />
     <ShippedRepository Include="MetaPackages" PatchPolicy="CascadeVersions" />
     <ShippedRepository Include="Mvc" />

+ 137 - 0
docs/BuildFromSource.md

@@ -0,0 +1,137 @@
+Build ASP.NET Core from Source
+==============================
+
+Building ASP.NET Core from source allows you tweak and customize ASP.NET Core, and
+to contribute your improvements back to the project.
+
+## :warning: Temporary instructions
+
+We are currently in the middle of restructing our repositories. While this work is being done, the following instructions will help you be more productive while working on this repo.
+
+1. Before opening a solution, run `build.cmd /p:_ProjectsOnly=true /p:SkipTests=true`. This will only build the projects which have merged into this repo, not the git submodules.
+2. Use (or create) a solution which is scoped to your project file. The build system does not use .sln files. These only exist for developer productivity in Visual Studio, so feel free to adjust the projects in .sln files to match your workload.
+3. Questions? Contact @aspnet for help.
+
+## Install pre-requistes
+
+### Windows
+
+Building ASP.NET Core on Windows requires:
+
+* Windows 7 or higher
+* At least 10 GB of disk space and a good internet connection (our build scripts download a lot of tools and dependencies)
+* Visual Studio 2017. <https://visualstudio.com>
+* Git. <https://git-scm.org>
+* (Optional) some optional components, like the SignalR Java client, may require
+    * NodeJS <https://nodejs.org>
+    * Java Development Kit 10 or newer. Either:
+        * OpenJDK <http://jdk.java.net/10/>
+        * Oracle's JDK <https://www.oracle.com/technetwork/java/javase/downloads/index.html>
+
+### macOS/Linux
+
+Building ASP.NET Core on macOS or Linux requires:
+
+* If using macOS, you need macOS Sierra or newer.
+* If using Linux, you need a machine with all .NET Core Linux prerequisites: <https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites>
+* At least 10 GB of disk space and a good internet connection (our build scripts download a lot of tools and dependencies)
+* Git <https://git-scm.org>
+* (Optional) some optional components, like the SignalR Java client, may require
+    * NodeJS  <https://nodejs.org>
+    * Java Development Kit 10 or newer. Either:
+        * OpenJDK <http://jdk.java.net/10/>
+        * Oracle's JDK <https://www.oracle.com/technetwork/java/javase/downloads/index.html>
+
+## Clone the source code
+
+ASP.NET Core uses git submodules to include source from a few other projects.
+
+For a new copy of the project, run:
+```
+git clone --recursive https://github.com/aspnet/AspNetCore
+```
+
+To update an existing copy, run:
+```
+git submodule update --init --recursive
+```
+
+## Building in Visual Studio / Code
+
+Before opening our .sln files in Visual Studio or VS Code, executing the following on command-line:
+```
+.\build.cmd /t:Restore
+```
+This will download required tools.
+
+#### PATH
+
+For VS Code and Visual Studio to work correctly, you must place the following location in your PATH.
+```
+Windows: %USERPROFILE%\.dotnet\x64
+Linux/macOS: $HOME/.dotnet
+```
+This must come **before** any other installation of `dotnet`. In Windows, we recommend removing `C:\Program Files\dotnet` from PATH in system variables and adding `%USERPROFILE%\.dotnet\x64` to PATH in user variables.
+
+<img src="http://i.imgur.com/Tm2PAfy.png" width="400" />
+
+## Building on command-line
+
+You can also build the entire project on command line with the `build.cmd`/`.sh` scripts.
+
+On Windows:
+```
+.\build.cmd
+```
+
+On macOS/Linux:
+```
+./build.sh
+```
+
+#### Build properties
+
+Additional properties can be added as an argument in the form `/property:$name=$value`, or `/p:$name=$value` for short. For example:
+```
+.\build.cmd /p:Configuration=Release
+```
+
+Common properties include:
+
+Property                 | Description
+-------------------------|---------------------------------------------------------
+BuildNumber              | (string). A specific build number, typically from a CI counter
+Configuration            | `Debug` or `Release`. Default = `Debug`.
+SkipTests                | `true` or `false`. When true, builds without running tests.
+NoBuild                  | `true` or `false`. Runs tests without rebuilding.
+
+## Use the result of your build
+
+After building ASP.NET Core from source, you will need to install and use your local version of ASP.NET Core.
+
+- Run the installers produced in `artifacts/installers/` for your platform.
+- Add a NuGet.Config to your project directory with the following content:
+
+  ```xml
+  <?xml version="1.0" encoding="utf-8"?>
+  <configuration>
+      <packageSources>
+          <clear />
+          <add key="MyBuildOfAspNetCore" value="C:\src\aspnet\AspNetCore\artifacts\build\" />
+          <add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
+      </packageSources>
+  </configuration>
+  ```
+
+  *NOTE: This NuGet.Config should be with your application unless you want nightly packages to potentially start being restored for other apps on the machine.*
+
+- Update the versions on `PackageReference` items in your .csproj project file to point to the version from your local build.
+  ```xml
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="3.0.0-alpha1-t000" />
+  </ItemGroup>
+  ```
+
+
+Some features, such as new target frameworks, may require prerelease tooling builds for Visual Studio.
+These are available in the [Visual Studio Preview](https://www.visualstudio.com/vs/preview/).

+ 99 - 0
docs/DailyBuilds.md

@@ -0,0 +1,99 @@
+How to get daily builds of ASP.NET Core
+=======================================
+
+Daily builds include the latest source code changes. They are not supported for production use and are subject to frequent changes, but we strive to make sure daily builds function correctly.
+
+If you want to download the latest daily build and use it in a project, then you need to:
+
+- Obtain the latest [build of the .NET Core SDK](https://github.com/dotnet/core-sdk#installers-and-binaries)
+- Add a NuGet.Config to your project directory with the following content:
+
+  ```xml
+  <?xml version="1.0" encoding="utf-8"?>
+  <configuration>
+      <packageSources>
+          <clear />
+          <add key="dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
+          <add key="NuGet.org" value="https://api.nuget.org/v3/index.json" />
+      </packageSources>
+  </configuration>
+  ```
+
+  *NOTE: This NuGet.Config should be with your application unless you want nightly packages to potentially start being restored for other apps on the machine.*
+
+Some features, such as new target frameworks, may require prerelease tooling builds for Visual Studio.
+These are available in the [Visual Studio Preview](https://www.visualstudio.com/vs/preview/).
+
+## NuGet packages
+
+Daily builds of ackages can be found on <https://dotnet.myget.org/gallery/dotnet-core>. This feed may include
+packages that will not be supported in a officially released build.
+
+Commonly referenced packages:
+
+[app-metapackage-myget]:  https://dotnet.myget.org/feed/dotnet-core/package/nuget/Microsoft.AspNetCore.App
+[app-metapackage-myget-badge]: https://img.shields.io/dotnet.myget/dotnet-core/vpre/Microsoft.AspNetCore.App.svg?style=flat-square&label=myget
+
+[metapackage-myget]:  https://dotnet.myget.org/feed/dotnet-core/package/nuget/Microsoft.AspNetCore
+[metapackage-myget-badge]: https://img.shields.io/dotnet.myget/dotnet-core/vpre/Microsoft.AspNetCore.svg?style=flat-square&label=myget
+
+Package                           | MyGet
+:---------------------------------|:---------------------------------------------------------
+Microsoft.AspNetCore.App          | [![][app-metapackage-myget-badge]][app-metapackage-myget]
+Microsoft.AspNetCore              | [![][metapackage-myget-badge]][metapackage-myget]
+
+## Runtime installers
+
+Updated versions of the ASP.NET Core runtime can be installed separately from SDK updates. Runtime-only installers can be downloaded here:
+
+[badge-master]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-win-x64-version-badge.svg
+[win-x64-zip]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x64.zip
+[win-x64-exe]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x64.exe
+[win-x86-zip]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x86.zip
+[win-x86-exe]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-win-x86.exe
+[linux-x64-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-linux-x64.tar.gz
+[linux-arm-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-linux-arm.tar.gz
+[linux-arm64-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-linux-arm64.tar.gz
+[osx-x64-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-osx-x64.tar.gz
+[debian-x64-deb]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-x64.deb
+[redhat-x64-rpm]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-x64.rpm
+[linux-musl-x64-tar]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/master/aspnetcore-runtime-latest-linux-musl-x64.tar.gz
+
+[badge-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-win-x64-version-badge.svg
+[win-x64-zip-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x64.zip
+[win-x64-exe-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x64.exe
+[win-x86-zip-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x86.zip
+[win-x86-exe-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-win-x86.exe
+[linux-x64-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-linux-x64.tar.gz
+[osx-x64-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-osx-x64.tar.gz
+[debian-x64-deb-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-x64.deb
+[redhat-x64-rpm-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-x64.rpm
+[linux-arm-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-linux-arm.tar.gz
+[linux-musl-x64-tar-rel-22]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.2/aspnetcore-runtime-latest-linux-musl-x64.tar.gz
+
+[badge-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-win-x64-version-badge.svg
+[win-x64-zip-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x64.zip
+[win-x64-exe-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x64.exe
+[win-x86-zip-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x86.zip
+[win-x86-exe-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-win-x86.exe
+[linux-x64-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-linux-x64.tar.gz
+[osx-x64-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-osx-x64.tar.gz
+[debian-x64-deb-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-x64.deb
+[redhat-x64-rpm-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-x64.rpm
+[linux-arm-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-linux-arm.tar.gz
+[linux-musl-x64-tar-rel-21]: https://dotnetcli.blob.core.windows.net/dotnet/aspnetcore/Runtime/release/2.1/aspnetcore-runtime-latest-linux-musl-x64.tar.gz
+
+Platform              | Latest (master branch) <br> ![][badge-master]                      | release/2.2 <br> ![][badge-rel-22] | release/2.1 <br> ![][badge-rel-21]
+:---------------------|:----------------------------------------------------------------|:------------------------------------------------------------------------- |:-------------------------------------------------------------------------
+Channel name<sup>1</sup> | `master` | `release/2.2` | `release/2.1`
+Windows (x64)         | [Installer (exe)][win-x64-exe]<br>[Archive (zip)][win-x64-zip]   | [Installer (exe)][win-x64-exe-rel-22]<br>[Archive (zip)][win-x64-zip-rel-22] | [Installer (exe)][win-x64-exe-rel-21]<br>[Archive (zip)][win-x64-zip-rel-21]
+Windows (x86)         | [Installer (exe)][win-x86-exe]<br>[Archive (zip)][win-x86-zip]   | [Installer (exe)][win-x86-exe-rel-22]<br>[Archive (zip)][win-x86-zip-rel-22] | [Installer (exe)][win-x86-exe-rel-21]<br>[Archive (zip)][win-x86-zip-rel-21]
+macOS (x64)           | [Archive (tar.gz)][osx-x64-tar]                                  | [Archive (tar.gz)][osx-x64-tar-rel-22] | [Archive (tar.gz)][osx-x64-tar-rel-21]
+Linux (x64)<br>_(for glibc based OS - most common)_ | [Archive (tar.gz)][linux-x64-tar]                                | [Archive (tar.gz)][linux-x64-tar-rel-22] | [Archive (tar.gz)][linux-x64-tar-rel-21]
+Linux (x64 - musl)<br>_(for musl based OS, such as Alpine Linux)_ | [Archive (tar.gz)][linux-musl-x64-tar]                           | [Archive (tar.gz)][linux-musl-x64-tar-rel-22] | [Archive (tar.gz)][linux-musl-x64-tar-rel-21]
+Linux (arm32)         | [Archive (tar.gz)][linux-arm-tar]                                | [Archive (tar.gz)][linux-arm-tar-rel-22] | [Archive (tar.gz)][linux-arm-tar-rel-21]
+Linux (arm64)         | [Archive (tar.gz)][linux-arm64-tar]                                | |
+Debian/Ubuntu (x64)   | [Installer (deb)][debian-x64-deb]                                | [Installer (deb)][debian-x64-deb-rel-22] | [Installer (deb)][debian-x64-deb-rel-21]
+RedHat/Fedora (x64)   | [Installer (rpm)][redhat-x64-rpm]                                | [Installer (rpm)][redhat-x64-rpm-rel-22] | [Installer (rpm)][redhat-x64-rpm-rel-21]
+
+> <sup>1</sup> For use with the `-Channel` argument in [dotnet-install.ps1/sh](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script).

+ 111 - 15
eng/Baseline.props

@@ -4,6 +4,14 @@
     <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
     <AspNetCoreBaselineVersion>2.2.0</AspNetCoreBaselineVersion>
   </PropertyGroup>
+  <!-- Package: Microsoft.AspNetCore.Connections.Abstractions-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Connections.Abstractions' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Connections.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Features" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="System.IO.Pipelines" Version="[4.5.2, )" />
+  </ItemGroup>
   <!-- Package: Microsoft.AspNetCore.Cryptography.Internal-->
   <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Cryptography.Internal' ">
     <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
@@ -19,21 +27,6 @@
   <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Cryptography.KeyDerivation' AND '$(TargetFramework)' == 'netstandard2.0' ">
     <BaselinePackageReference Include="Microsoft.AspNetCore.Cryptography.Internal" Version="[2.2.0, )" />
   </ItemGroup>
-  <!-- Package: Microsoft.AspNetCore.DataProtection-->
-  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection' ">
-    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
-  </PropertyGroup>
-  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection' AND '$(TargetFramework)' == 'netstandard2.0' ">
-    <BaselinePackageReference Include="Microsoft.AspNetCore.DataProtection.Abstractions" Version="[2.2.0, )" />
-    <BaselinePackageReference Include="Microsoft.AspNetCore.Cryptography.Internal" Version="[2.2.0, )" />
-    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
-    <BaselinePackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="[2.2.0, )" />
-    <BaselinePackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0, )" />
-    <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
-    <BaselinePackageReference Include="Microsoft.Win32.Registry" Version="[4.5.0, )" />
-    <BaselinePackageReference Include="System.Security.Cryptography.Xml" Version="[4.5.0, )" />
-    <BaselinePackageReference Include="System.Security.Principal.Windows" Version="[4.5.0, )" />
-  </ItemGroup>
   <!-- Package: Microsoft.AspNetCore.DataProtection.Abstractions-->
   <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection.Abstractions' ">
     <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
@@ -88,6 +81,21 @@
     <BaselinePackageReference Include="Microsoft.AspNetCore.DataProtection" Version="[2.2.0, )" />
     <BaselinePackageReference Include="Microsoft.Extensions.DependencyInjection" Version="[2.2.0, )" />
   </ItemGroup>
+  <!-- Package: Microsoft.AspNetCore.DataProtection-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.DataProtection.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Cryptography.Internal" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Win32.Registry" Version="[4.5.0, )" />
+    <BaselinePackageReference Include="System.Security.Cryptography.Xml" Version="[4.5.0, )" />
+    <BaselinePackageReference Include="System.Security.Principal.Windows" Version="[4.5.0, )" />
+  </ItemGroup>
   <!-- Package: Microsoft.AspNetCore.Html.Abstractions-->
   <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Html.Abstractions' ">
     <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
@@ -103,6 +111,94 @@
     <BaselinePackageReference Include="Microsoft.CSharp" Version="[4.5.0, )" />
     <BaselinePackageReference Include="Newtonsoft.Json" Version="[11.0.2, )" />
   </ItemGroup>
+  <!-- Package: Microsoft.AspNetCore.Server.Kestrel.Core-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Core' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Core' AND '$(TargetFramework)' == 'netcoreapp2.1' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="System.Memory" Version="[4.5.1, )" />
+    <BaselinePackageReference Include="System.Numerics.Vectors" Version="[4.5.0, )" />
+    <BaselinePackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="[4.5.1, )" />
+    <BaselinePackageReference Include="System.Security.Cryptography.Cng" Version="[4.5.0, )" />
+    <BaselinePackageReference Include="System.Threading.Tasks.Extensions" Version="[4.5.1, )" />
+  </ItemGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Core' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Net.Http.Headers" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="System.Memory" Version="[4.5.1, )" />
+    <BaselinePackageReference Include="System.Numerics.Vectors" Version="[4.5.0, )" />
+    <BaselinePackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="[4.5.1, )" />
+    <BaselinePackageReference Include="System.Security.Cryptography.Cng" Version="[4.5.0, )" />
+    <BaselinePackageReference Include="System.Threading.Tasks.Extensions" Version="[4.5.1, )" />
+  </ItemGroup>
+  <!-- Package: Microsoft.AspNetCore.Server.Kestrel.Https-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Https' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Https' AND '$(TargetFramework)' == 'netcoreapp2.1' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.2.0, )" />
+  </ItemGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Https' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="[2.2.0, )" />
+  </ItemGroup>
+  <!-- Package: Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="[2.2.0, )" />
+  </ItemGroup>
+  <!-- Package: Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Libuv" Version="[1.10.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
+  </ItemGroup>
+  <!-- Package: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets' AND '$(TargetFramework)' == 'netcoreapp2.1' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
+  </ItemGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
+  </ItemGroup>
+  <!-- Package: Microsoft.AspNetCore.Server.Kestrel-->
+  <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel' ">
+    <BaselinePackageVersion>2.2.0</BaselinePackageVersion>
+  </PropertyGroup>
+  <ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Server.Kestrel' AND '$(TargetFramework)' == 'netstandard2.0' ">
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Core" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" Version="[2.2.0, )" />
+    <BaselinePackageReference Include="Microsoft.AspNetCore.Hosting" Version="[2.2.0, )" />
+  </ItemGroup>
   <!-- Package: Microsoft.AspNetCore.WebSockets-->
   <PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.WebSockets' ">
     <BaselinePackageVersion>2.2.0</BaselinePackageVersion>

+ 12 - 0
eng/Dependencies.props

@@ -5,13 +5,17 @@
     <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
   </PropertyGroup>
 
+  <Import Project="dependencies.temp.props" />
+
   <ItemGroup Label="ProdCon dependencies">
     <!-- These dependencies must use version variables because they may be overriden by ProdCon builds. -->
+    <LatestPackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
     <LatestPackageReference Include="Microsoft.AspNetCore.Certificates.Generation.Sources" Version="$(MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion)" />
     <LatestPackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />
     <LatestPackageReference Include="Microsoft.CSharp" Version="$(MicrosoftCSharpPackageVersion)" />
     <LatestPackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(MicrosoftEntityFrameworkCoreInMemoryPackageVersion)" />
     <LatestPackageReference Include="Microsoft.EntityFrameworkCore" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
+    <LatestPackageReference Include="Microsoft.Extensions.ActivatorUtilities.Sources" Version="$(MicrosoftExtensionsActivatorUtilitiesSourcesPackageVersion)" />
     <LatestPackageReference Include="Microsoft.Extensions.ClosedGenericMatcher.Sources" Version="$(MicrosoftExtensionsClosedGenericMatcherSourcesPackageVersion)" />
     <LatestPackageReference Include="Microsoft.Extensions.CommandLineUtils.Sources" Version="$(MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion)" />
     <LatestPackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(MicrosoftExtensionsConfigurationCommandLinePackageVersion)" />
@@ -27,19 +31,27 @@
     <LatestPackageReference Include="Microsoft.Extensions.Process.Sources" Version="$(MicrosoftExtensionsProcessSourcesPackageVersion)" />
     <LatestPackageReference Include="Microsoft.Extensions.WebEncoders.Sources" Version="$(MicrosoftExtensionsWebEncodersSourcesPackageVersion)" />
     <LatestPackageReference Include="Microsoft.Extensions.WebEncoders" Version="$(MicrosoftExtensionsWebEncodersPackageVersion)" />
+    <LatestPackageReference Include="Microsoft.Internal.AspNetCore.H2Spec.All" Version="$(MicrosoftInternalAspNetCoreH2SpecAllPackageVersion)" />
     <LatestPackageReference Include="System.Data.SqlClient" Version="$(SystemDataSqlClientPackageVersion)" />
+    <LatestPackageReference Include="System.Memory" Version="$(SystemMemoryPackageVersion)" />
     <LatestPackageReference Include="System.Net.WebSockets.WebSocketProtocol" Version="$(SystemNetWebSocketsWebSocketProtocolPackageVersion)" />
+    <LatestPackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="$(SystemRuntimeCompilerServicesUnsafePackageVersion)" />
     <LatestPackageReference Include="System.Security.Cryptography.Cng" Version="$(SystemSecurityCryptographyCngPackageVersion)" />
     <LatestPackageReference Include="System.Text.Encodings.Web" Version="$(SystemTextEncodingsWebPackageVersion)" />
+    <LatestPackageReference Include="System.Net.Http.WinHttpHandler" Version="$(SystemNetHttpWinHttpHandlerPackageVersion)" />
   </ItemGroup>
 
   <ItemGroup Label="External dependencies">
+    <LatestPackageReference Include="BenchmarkDotNet" Version="0.10.13" />
     <LatestPackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
     <LatestPackageReference Include="Moq" Version="4.10.0" />
     <!-- This version is required by MSBuild tasks or Visual Studio extensions. -->
     <LatestPackageReference Include="Newtonsoft.Json" Version="9.0.1" Condition="'$(UseMSBuildJsonNet)' == 'true'" />
     <!-- This version should be used by runtime packages -->
     <LatestPackageReference Include="Newtonsoft.Json" Version="11.0.2" Condition="'$(UseMSBuildJsonNet)' != 'true'" />
+    <LatestPackageReference Include="Selenium.WebDriver.ChromeDriver" Version="2.43.0" />
+    <LatestPackageReference Include="Selenium.WebDriver" Version="3.12.1" />
+    <LatestPackageReference Include="Utf8Json" Version="1.3.7" />
     <LatestPackageReference Include="xunit.abstractions" Version="2.0.1" />
     <LatestPackageReference Include="xunit.analyzers" Version="0.10.0" />
     <LatestPackageReference Include="xunit.assert" Version="2.3.1" />

+ 9 - 0
eng/ProjectReferences.props

@@ -13,6 +13,15 @@
     <ProjectReferenceProvider Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" ProjectPath="$(RepositoryRoot)src\DataProtection\StackExchangeRedis\src\Microsoft.AspNetCore.DataProtection.StackExchangeRedis.csproj" />
     <ProjectReferenceProvider Include="Microsoft.AspNetCore.DataProtection.SystemWeb" ProjectPath="$(RepositoryRoot)src\DataProtection\SystemWeb\src\Microsoft.AspNetCore.DataProtection.SystemWeb.csproj" />
     <ProjectReferenceProvider Include="Microsoft.AspNetCore.Html.Abstractions" ProjectPath="$(RepositoryRoot)src\Html\Abstractions\src\Microsoft.AspNetCore.Html.Abstractions.csproj" />
+    <ProjectReferenceProvider Include="Microsoft.AspNetCore.Connections.Abstractions" ProjectPath="$(RepositoryRoot)src\Servers\Connections.Abstractions\src\Microsoft.AspNetCore.Connections.Abstractions.csproj" />
+    <ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Core" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj" />
+    <ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Https" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\Https\src\Microsoft.AspNetCore.Server.Kestrel.Https.csproj" />
+    <ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\Kestrel\src\Microsoft.AspNetCore.Server.Kestrel.csproj" />
+    <ProjectReferenceProvider Include="PlatformBenchmarks" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\perf\PlatformBenchmarks\PlatformBenchmarks.csproj" />
+    <ProjectReferenceProvider Include="CodeGenerator" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\tools\CodeGenerator\CodeGenerator.csproj" />
+    <ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\Transport.Abstractions\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.csproj" />
+    <ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\Transport.Libuv\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" />
+    <ProjectReferenceProvider Include="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" ProjectPath="$(RepositoryRoot)src\Servers\Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj" />
     <ProjectReferenceProvider Include="dotnet-dev-certs" ProjectPath="$(RepositoryRoot)src\Tools\dotnet-dev-certs\src\dotnet-dev-certs.csproj" />
     <ProjectReferenceProvider Include="dotnet-sql-cache" ProjectPath="$(RepositoryRoot)src\Tools\dotnet-sql-cache\src\dotnet-sql-cache.csproj" />
     <ProjectReferenceProvider Include="dotnet-user-secrets" ProjectPath="$(RepositoryRoot)src\Tools\dotnet-user-secrets\src\dotnet-user-secrets.csproj" />

+ 15 - 0
eng/dependencies.temp.props

@@ -0,0 +1,15 @@
+<!--
+This file is temporary until aspnet/Hosting, Diagnostics, StaticFiles, and HttpAbstractions are merged into this repo.
+This is required to provide dependencies for samples and tests.
+ -->
+<Project>
+  <ItemGroup>
+    <LatestPackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="2.2.0" />
+    <LatestPackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="2.2.0" />
+    <LatestPackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
+    <LatestPackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.0" />
+    <LatestPackageReference Include="Microsoft.AspNetCore.Http.Features" Version="2.2.0" />
+    <LatestPackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
+    <LatestPackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.0" />
+  </ItemGroup>
+</Project>

+ 1 - 1
eng/targets/CSharp.Common.props

@@ -1,7 +1,7 @@
 <Project>
 
   <PropertyGroup>
-    <LangVersion>7.2</LangVersion>
+    <LangVersion>7.3</LangVersion>
 
     <!-- Instructs the compiler to use SHA256 instead of SHA1 when adding file hashes to PDBs. -->
     <ChecksumAlgorithm>SHA256</ChecksumAlgorithm>

+ 8 - 1
eng/tools/BaselineGenerator/baseline.xml

@@ -3,9 +3,9 @@
   <Package Id="dotnet-sql-cache" Version="2.2.0" />
   <Package Id="dotnet-user-secrets" Version="2.2.0" />
   <Package Id="dotnet-watch" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.Connections.Abstractions" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.Cryptography.Internal" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.2.0" />
-  <Package Id="Microsoft.AspNetCore.DataProtection" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.DataProtection.Abstractions" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.DataProtection.AzureKeyVault" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.DataProtection.AzureStorage" Version="2.2.0" />
@@ -13,7 +13,14 @@
   <Package Id="Microsoft.AspNetCore.DataProtection.Extensions" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.DataProtection.SystemWeb" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.DataProtection" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.Html.Abstractions" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.JsonPatch" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.Server.Kestrel.Core" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.Server.Kestrel.Https" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets" Version="2.2.0" />
+  <Package Id="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
   <Package Id="Microsoft.AspNetCore.WebSockets" Version="2.2.0" />
 </Baseline>

+ 0 - 1
modules/KestrelHttpServer

@@ -1 +0,0 @@
-Subproject commit 5db6394769e229139cbf8538ec73253ce76e735b

+ 43 - 0
src/Servers/Connections.Abstractions/src/ConnectionBuilder.cs

@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public class ConnectionBuilder : IConnectionBuilder
+    {
+        private readonly IList<Func<ConnectionDelegate, ConnectionDelegate>> _components = new List<Func<ConnectionDelegate, ConnectionDelegate>>();
+
+        public IServiceProvider ApplicationServices { get; }
+
+        public ConnectionBuilder(IServiceProvider applicationServices)
+        {
+            ApplicationServices = applicationServices;
+        }
+
+        public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
+        {
+            _components.Add(middleware);
+            return this;
+        }
+
+        public ConnectionDelegate Build()
+        {
+            ConnectionDelegate app = features =>
+            {
+                return Task.CompletedTask;
+            };
+
+            foreach (var component in _components.Reverse())
+            {
+                app = component(app);
+            }
+
+            return app;
+        }
+    }
+}

+ 43 - 0
src/Servers/Connections.Abstractions/src/ConnectionBuilderExtensions.cs

@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Internal;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public static class ConnectionBuilderExtensions
+    {
+        public static IConnectionBuilder UseConnectionHandler<TConnectionHandler>(this IConnectionBuilder connectionBuilder) where TConnectionHandler : ConnectionHandler
+        {
+            var handler = ActivatorUtilities.GetServiceOrCreateInstance<TConnectionHandler>(connectionBuilder.ApplicationServices);
+
+            // This is a terminal middleware, so there's no need to use the 'next' parameter
+            return connectionBuilder.Run(connection => handler.OnConnectedAsync(connection));
+        }
+
+        public static IConnectionBuilder Use(this IConnectionBuilder connectionBuilder, Func<ConnectionContext, Func<Task>, Task> middleware)
+        {
+            return connectionBuilder.Use(next =>
+            {
+                return context =>
+                {
+                    Func<Task> simpleNext = () => next(context);
+                    return middleware(context, simpleNext);
+                };
+            });
+        }
+
+        public static IConnectionBuilder Run(this IConnectionBuilder connectionBuilder, Func<ConnectionContext, Task> middleware)
+        {
+            return connectionBuilder.Use(next =>
+            {
+                return context =>
+                {
+                    return middleware(context);
+                };
+            });
+        }
+    }
+}

+ 31 - 0
src/Servers/Connections.Abstractions/src/ConnectionContext.cs

@@ -0,0 +1,31 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.IO.Pipelines;
+using Microsoft.AspNetCore.Connections.Features;
+using Microsoft.AspNetCore.Http.Features;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public abstract class ConnectionContext
+    {
+        public abstract string ConnectionId { get; set; }
+
+        public abstract IFeatureCollection Features { get; }
+
+        public abstract IDictionary<object, object> Items { get; set; }
+
+        public abstract IDuplexPipe Transport { get; set; }
+
+        public virtual void Abort(ConnectionAbortedException abortReason)
+        {
+            // We expect this to be overridden, but this helps maintain back compat
+            // with implementations of ConnectionContext that predate the addition of
+            // ConnectionContext.Abort()
+            Features.Get<IConnectionLifetimeFeature>()?.Abort();
+        }
+
+        public virtual void Abort() => Abort(new ConnectionAbortedException("The connection was aborted by the application."));
+    }
+}

+ 6 - 0
src/Servers/Connections.Abstractions/src/ConnectionDelegate.cs

@@ -0,0 +1,6 @@
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public delegate Task ConnectionDelegate(ConnectionContext connection);
+}

+ 20 - 0
src/Servers/Connections.Abstractions/src/ConnectionHandler.cs

@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    /// <summary>
+    /// Represents an end point that multiple connections connect to. For HTTP, endpoints are URLs, for non HTTP it can be a TCP listener (or similar)
+    /// </summary>
+    public abstract class ConnectionHandler
+    {
+        /// <summary>
+        /// Called when a new connection is accepted to the endpoint
+        /// </summary>
+        /// <param name="connection">The new <see cref="ConnectionContext"/></param>
+        /// <returns>A <see cref="Task"/> that represents the connection lifetime. When the task completes, the connection is complete.</returns>
+        public abstract Task OnConnectedAsync(ConnectionContext connection);
+    }
+}

+ 116 - 0
src/Servers/Connections.Abstractions/src/ConnectionItems.cs

@@ -0,0 +1,116 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public class ConnectionItems : IDictionary<object, object>
+    {
+        public ConnectionItems()
+            : this(new Dictionary<object, object>())
+        {
+        }
+
+        public ConnectionItems(IDictionary<object, object> items)
+        {
+            Items = items;
+        }
+
+        public IDictionary<object, object> Items { get; }
+
+        // Replace the indexer with one that returns null for missing values
+        object IDictionary<object, object>.this[object key]
+        {
+            get
+            {
+                if (Items.TryGetValue(key, out var value))
+                {
+                    return value;
+                }
+                return null;
+            }
+            set { Items[key] = value; }
+        }
+
+        void IDictionary<object, object>.Add(object key, object value)
+        {
+            Items.Add(key, value);
+        }
+
+        bool IDictionary<object, object>.ContainsKey(object key)
+        {
+            return Items.ContainsKey(key);
+        }
+
+        ICollection<object> IDictionary<object, object>.Keys
+        {
+            get { return Items.Keys; }
+        }
+
+        bool IDictionary<object, object>.Remove(object key)
+        {
+            return Items.Remove(key);
+        }
+
+        bool IDictionary<object, object>.TryGetValue(object key, out object value)
+        {
+            return Items.TryGetValue(key, out value);
+        }
+
+        ICollection<object> IDictionary<object, object>.Values
+        {
+            get { return Items.Values; }
+        }
+
+        void ICollection<KeyValuePair<object, object>>.Add(KeyValuePair<object, object> item)
+        {
+            Items.Add(item);
+        }
+
+        void ICollection<KeyValuePair<object, object>>.Clear()
+        {
+            Items.Clear();
+        }
+
+        bool ICollection<KeyValuePair<object, object>>.Contains(KeyValuePair<object, object> item)
+        {
+            return Items.Contains(item);
+        }
+
+        void ICollection<KeyValuePair<object, object>>.CopyTo(KeyValuePair<object, object>[] array, int arrayIndex)
+        {
+            Items.CopyTo(array, arrayIndex);
+        }
+
+        int ICollection<KeyValuePair<object, object>>.Count
+        {
+            get { return Items.Count; }
+        }
+
+        bool ICollection<KeyValuePair<object, object>>.IsReadOnly
+        {
+            get { return Items.IsReadOnly; }
+        }
+
+        bool ICollection<KeyValuePair<object, object>>.Remove(KeyValuePair<object, object> item)
+        {
+            if (Items.TryGetValue(item.Key, out var value) && Equals(item.Value, value))
+            {
+                return Items.Remove(item.Key);
+            }
+            return false;
+        }
+
+        IEnumerator<KeyValuePair<object, object>> IEnumerable<KeyValuePair<object, object>>.GetEnumerator()
+        {
+            return Items.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return Items.GetEnumerator();
+        }
+    }
+}

+ 78 - 0
src/Servers/Connections.Abstractions/src/DefaultConnectionContext.cs

@@ -0,0 +1,78 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.IO.Pipelines;
+using System.Security.Claims;
+using System.Threading;
+using Microsoft.AspNetCore.Connections.Features;
+using Microsoft.AspNetCore.Http.Features;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public class DefaultConnectionContext : ConnectionContext,
+                                            IDisposable,
+                                            IConnectionIdFeature,
+                                            IConnectionItemsFeature,
+                                            IConnectionTransportFeature,
+                                            IConnectionUserFeature,
+                                            IConnectionLifetimeFeature
+    {
+        private CancellationTokenSource _connectionClosedTokenSource = new CancellationTokenSource();
+
+        public DefaultConnectionContext() :
+            this(Guid.NewGuid().ToString())
+        {
+            ConnectionClosed = _connectionClosedTokenSource.Token;
+        }
+
+        /// <summary>
+        /// Creates the DefaultConnectionContext without Pipes to avoid upfront allocations.
+        /// The caller is expected to set the <see cref="Transport"/> and <see cref="Application"/> pipes manually.
+        /// </summary>
+        /// <param name="id"></param>
+        public DefaultConnectionContext(string id)
+        {
+            ConnectionId = id;
+
+            Features = new FeatureCollection();
+            Features.Set<IConnectionUserFeature>(this);
+            Features.Set<IConnectionItemsFeature>(this);
+            Features.Set<IConnectionIdFeature>(this);
+            Features.Set<IConnectionTransportFeature>(this);
+            Features.Set<IConnectionLifetimeFeature>(this);
+        }
+
+        public DefaultConnectionContext(string id, IDuplexPipe transport, IDuplexPipe application)
+            : this(id)
+        {
+            Transport = transport;
+            Application = application;
+        }
+
+        public override string ConnectionId { get; set; }
+
+        public override IFeatureCollection Features { get; }
+
+        public ClaimsPrincipal User { get; set; }
+
+        public override IDictionary<object, object> Items { get; set; } = new ConnectionItems();
+
+        public IDuplexPipe Application { get; set; }
+
+        public override IDuplexPipe Transport { get; set; }
+
+        public CancellationToken ConnectionClosed { get; set; }
+
+        public override void Abort(ConnectionAbortedException abortReason)
+        {
+            ThreadPool.UnsafeQueueUserWorkItem(cts => ((CancellationTokenSource)cts).Cancel(), _connectionClosedTokenSource);
+        }
+
+        public void Dispose()
+        {
+            _connectionClosedTokenSource.Dispose();
+        }
+    }
+}

+ 18 - 0
src/Servers/Connections.Abstractions/src/Exceptions/AddressInUseException.cs

@@ -0,0 +1,18 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public class AddressInUseException : InvalidOperationException
+    {
+        public AddressInUseException(string message) : base(message)
+        {
+        }
+
+        public AddressInUseException(string message, Exception inner) : base(message, inner)
+        {
+        }
+    }
+}

+ 21 - 0
src/Servers/Connections.Abstractions/src/Exceptions/ConnectionAbortedException.cs

@@ -0,0 +1,21 @@
+using System;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public class ConnectionAbortedException : OperationCanceledException
+    {
+        public ConnectionAbortedException() :
+            this("The connection was aborted")
+        {
+
+        }
+
+        public ConnectionAbortedException(string message) : base(message)
+        {
+        }
+
+        public ConnectionAbortedException(string message, Exception inner) : base(message, inner)
+        {
+        }
+    }
+}

+ 19 - 0
src/Servers/Connections.Abstractions/src/Exceptions/ConnectionResetException.cs

@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public class ConnectionResetException : IOException
+    {
+        public ConnectionResetException(string message) : base(message)
+        {
+        }
+
+        public ConnectionResetException(string message, Exception inner) : base(message, inner)
+        {
+        }
+    }
+}

+ 12 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionHeartbeatFeature.cs

@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IConnectionHeartbeatFeature
+    {
+        void OnHeartbeat(Action<object> action, object state);
+    }
+}

+ 10 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionIdFeature.cs

@@ -0,0 +1,10 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IConnectionIdFeature
+    {
+        string ConnectionId { get; set; }
+    }
+}

+ 20 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionInherentKeepAliveFeature.cs

@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    /// <summary>
+    /// Indicates if the connection transport has an "inherent keep-alive", which means that the transport will automatically
+    /// inform the client that it is still present.
+    /// </summary>
+    /// <remarks>
+    /// The most common example of this feature is the Long Polling HTTP transport, which must (due to HTTP limitations) terminate
+    /// each poll within a particular interval and return a signal indicating "the server is still here, but there is no data yet".
+    /// This feature allows applications to add keep-alive functionality, but limit it only to transports that don't have some kind
+    /// of inherent keep-alive.
+    /// </remarks>
+    public interface IConnectionInherentKeepAliveFeature
+    {
+        bool HasInherentKeepAlive { get; }
+    }
+}

+ 12 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionItemsFeature.cs

@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IConnectionItemsFeature
+    {
+        IDictionary<object, object> Items { get; set; }
+    }
+}

+ 14 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionLifetimeFeature.cs

@@ -0,0 +1,14 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IConnectionLifetimeFeature
+    {
+        CancellationToken ConnectionClosed { get; set; }
+
+        void Abort();
+    }
+}

+ 14 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionLifetimeNotificationFeature.cs

@@ -0,0 +1,14 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IConnectionLifetimeNotificationFeature
+    {
+        CancellationToken ConnectionClosedRequested { get; set; }
+
+        void RequestClose();
+    }
+}

+ 12 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionTransportFeature.cs

@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO.Pipelines;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IConnectionTransportFeature
+    {
+        IDuplexPipe Transport { get; set; }
+    }
+}

+ 9 - 0
src/Servers/Connections.Abstractions/src/Features/IConnectionUserFeature.cs

@@ -0,0 +1,9 @@
+using System.Security.Claims;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IConnectionUserFeature
+    {
+        ClaimsPrincipal User { get; set; }
+    }
+}

+ 12 - 0
src/Servers/Connections.Abstractions/src/Features/IMemoryPoolFeature.cs

@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Buffers;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface IMemoryPoolFeature
+    {
+        MemoryPool<byte> MemoryPool { get; }
+    }
+}

+ 24 - 0
src/Servers/Connections.Abstractions/src/Features/ITlsHandshakeFeature.cs

@@ -0,0 +1,24 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Security.Authentication;
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface ITlsHandshakeFeature
+    {
+        SslProtocols Protocol { get; }
+
+        CipherAlgorithmType CipherAlgorithm { get; }
+
+        int CipherStrength { get; }
+
+        HashAlgorithmType HashAlgorithm { get; }
+
+        int HashStrength { get; }
+
+        ExchangeAlgorithmType KeyExchangeAlgorithm { get; }
+
+        int KeyExchangeStrength { get; }
+    }
+}

+ 11 - 0
src/Servers/Connections.Abstractions/src/Features/ITransferFormatFeature.cs

@@ -0,0 +1,11 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Connections.Features
+{
+    public interface ITransferFormatFeature
+    {
+        TransferFormat SupportedFormats { get; }
+        TransferFormat ActiveFormat { get; set; }
+    }
+}

+ 13 - 0
src/Servers/Connections.Abstractions/src/IConnectionBuilder.cs

@@ -0,0 +1,13 @@
+using System;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    public interface IConnectionBuilder
+    {
+        IServiceProvider ApplicationServices { get; }
+
+        IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware);
+
+        ConnectionDelegate Build();
+    }
+}

+ 17 - 0
src/Servers/Connections.Abstractions/src/Microsoft.AspNetCore.Connections.Abstractions.csproj

@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <Description>Core components of ASP.NET Core networking protocol stack.</Description>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <PackageTags>aspnetcore</PackageTags>
+    <NoWarn>CS1591;$(NoWarn)</NoWarn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Reference Include="Microsoft.AspNetCore.Http.Features" />
+    <Reference Include="Microsoft.Extensions.ActivatorUtilities.Sources" PrivateAssets="All" />
+    <Reference Include="System.IO.Pipelines" />
+  </ItemGroup>
+
+</Project>

+ 14 - 0
src/Servers/Connections.Abstractions/src/TransferFormat.cs

@@ -0,0 +1,14 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Connections
+{
+    [Flags]
+    public enum TransferFormat
+    {
+        Binary = 0x01,
+        Text = 0x02
+    }
+}

+ 1060 - 0
src/Servers/Connections.Abstractions/src/baseline.netcore.json

@@ -0,0 +1,1060 @@
+{
+  "AssemblyIdentity": "Microsoft.AspNetCore.Connections.Abstractions, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
+  "Types": [
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionBuilder",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [
+        "Microsoft.AspNetCore.Connections.IConnectionBuilder"
+      ],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ApplicationServices",
+          "Parameters": [],
+          "ReturnType": "System.IServiceProvider",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Use",
+          "Parameters": [
+            {
+              "Name": "middleware",
+              "Type": "System.Func<Microsoft.AspNetCore.Connections.ConnectionDelegate, Microsoft.AspNetCore.Connections.ConnectionDelegate>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Build",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Connections.ConnectionDelegate",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "applicationServices",
+              "Type": "System.IServiceProvider"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionBuilderExtensions",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "Static": true,
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "UseConnectionHandler<T0>",
+          "Parameters": [
+            {
+              "Name": "connectionBuilder",
+              "Type": "Microsoft.AspNetCore.Connections.IConnectionBuilder"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": [
+            {
+              "ParameterName": "TConnectionHandler",
+              "ParameterPosition": 0,
+              "BaseTypeOrInterfaces": [
+                "Microsoft.AspNetCore.Connections.ConnectionHandler"
+              ]
+            }
+          ]
+        },
+        {
+          "Kind": "Method",
+          "Name": "Use",
+          "Parameters": [
+            {
+              "Name": "connectionBuilder",
+              "Type": "Microsoft.AspNetCore.Connections.IConnectionBuilder"
+            },
+            {
+              "Name": "middleware",
+              "Type": "System.Func<Microsoft.AspNetCore.Connections.ConnectionContext, System.Func<System.Threading.Tasks.Task>, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Run",
+          "Parameters": [
+            {
+              "Name": "connectionBuilder",
+              "Type": "Microsoft.AspNetCore.Connections.IConnectionBuilder"
+            },
+            {
+              "Name": "middleware",
+              "Type": "System.Func<Microsoft.AspNetCore.Connections.ConnectionContext, System.Threading.Tasks.Task>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "Static": true,
+          "Extension": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionContext",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ConnectionId",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ConnectionId",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Features",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.Features.IFeatureCollection",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Items",
+          "Parameters": [],
+          "ReturnType": "System.Collections.Generic.IDictionary<System.Object, System.Object>",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Items",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Collections.Generic.IDictionary<System.Object, System.Object>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Transport",
+          "Parameters": [],
+          "ReturnType": "System.IO.Pipelines.IDuplexPipe",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Transport",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.IO.Pipelines.IDuplexPipe"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Protected",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionDelegate",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Sealed": true,
+      "BaseType": "System.MulticastDelegate",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "Invoke",
+          "Parameters": [
+            {
+              "Name": "connection",
+              "Type": "Microsoft.AspNetCore.Connections.ConnectionContext"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "BeginInvoke",
+          "Parameters": [
+            {
+              "Name": "connection",
+              "Type": "Microsoft.AspNetCore.Connections.ConnectionContext"
+            },
+            {
+              "Name": "callback",
+              "Type": "System.AsyncCallback"
+            },
+            {
+              "Name": "object",
+              "Type": "System.Object"
+            }
+          ],
+          "ReturnType": "System.IAsyncResult",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "EndInvoke",
+          "Parameters": [
+            {
+              "Name": "result",
+              "Type": "System.IAsyncResult"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "object",
+              "Type": "System.Object"
+            },
+            {
+              "Name": "method",
+              "Type": "System.IntPtr"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionHandler",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "OnConnectedAsync",
+          "Parameters": [
+            {
+              "Name": "connection",
+              "Type": "Microsoft.AspNetCore.Connections.ConnectionContext"
+            }
+          ],
+          "ReturnType": "System.Threading.Tasks.Task",
+          "Virtual": true,
+          "Abstract": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Protected",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionItems",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "ImplementedInterfaces": [
+        "System.Collections.Generic.IDictionary<System.Object, System.Object>"
+      ],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_Items",
+          "Parameters": [],
+          "ReturnType": "System.Collections.Generic.IDictionary<System.Object, System.Object>",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "items",
+              "Type": "System.Collections.Generic.IDictionary<System.Object, System.Object>"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.DefaultConnectionContext",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "Microsoft.AspNetCore.Connections.ConnectionContext",
+      "ImplementedInterfaces": [
+        "System.IDisposable",
+        "Microsoft.AspNetCore.Connections.Features.IConnectionIdFeature",
+        "Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature",
+        "Microsoft.AspNetCore.Connections.Features.IConnectionTransportFeature",
+        "Microsoft.AspNetCore.Connections.Features.IConnectionUserFeature",
+        "Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature"
+      ],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ConnectionId",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "Virtual": true,
+          "Override": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionIdFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ConnectionId",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "Override": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionIdFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Features",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Http.Features.IFeatureCollection",
+          "Virtual": true,
+          "Override": true,
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_User",
+          "Parameters": [],
+          "ReturnType": "System.Security.Claims.ClaimsPrincipal",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionUserFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_User",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Security.Claims.ClaimsPrincipal"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionUserFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Items",
+          "Parameters": [],
+          "ReturnType": "System.Collections.Generic.IDictionary<System.Object, System.Object>",
+          "Virtual": true,
+          "Override": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Items",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Collections.Generic.IDictionary<System.Object, System.Object>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "Override": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Application",
+          "Parameters": [],
+          "ReturnType": "System.IO.Pipelines.IDuplexPipe",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Application",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.IO.Pipelines.IDuplexPipe"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_Transport",
+          "Parameters": [],
+          "ReturnType": "System.IO.Pipelines.IDuplexPipe",
+          "Virtual": true,
+          "Override": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionTransportFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Transport",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.IO.Pipelines.IDuplexPipe"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "Override": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionTransportFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_ConnectionClosed",
+          "Parameters": [],
+          "ReturnType": "System.Threading.CancellationToken",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ConnectionClosed",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Threading.CancellationToken"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Abort",
+          "Parameters": [],
+          "ReturnType": "System.Void",
+          "Virtual": true,
+          "ImplementedInterface": "Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Dispose",
+          "Parameters": [],
+          "ReturnType": "System.Void",
+          "Sealed": true,
+          "Virtual": true,
+          "ImplementedInterface": "System.IDisposable",
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "id",
+              "Type": "System.String"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "id",
+              "Type": "System.String"
+            },
+            {
+              "Name": "transport",
+              "Type": "System.IO.Pipelines.IDuplexPipe"
+            },
+            {
+              "Name": "application",
+              "Type": "System.IO.Pipelines.IDuplexPipe"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.AddressInUseException",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "System.InvalidOperationException",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "message",
+              "Type": "System.String"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "message",
+              "Type": "System.String"
+            },
+            {
+              "Name": "inner",
+              "Type": "System.Exception"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionAbortedException",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "System.OperationCanceledException",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "message",
+              "Type": "System.String"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "message",
+              "Type": "System.String"
+            },
+            {
+              "Name": "inner",
+              "Type": "System.Exception"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.ConnectionResetException",
+      "Visibility": "Public",
+      "Kind": "Class",
+      "BaseType": "System.IO.IOException",
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "message",
+              "Type": "System.String"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Constructor",
+          "Name": ".ctor",
+          "Parameters": [
+            {
+              "Name": "message",
+              "Type": "System.String"
+            },
+            {
+              "Name": "inner",
+              "Type": "System.Exception"
+            }
+          ],
+          "Visibility": "Public",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ApplicationServices",
+          "Parameters": [],
+          "ReturnType": "System.IServiceProvider",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Use",
+          "Parameters": [
+            {
+              "Name": "middleware",
+              "Type": "System.Func<Microsoft.AspNetCore.Connections.ConnectionDelegate, Microsoft.AspNetCore.Connections.ConnectionDelegate>"
+            }
+          ],
+          "ReturnType": "Microsoft.AspNetCore.Connections.IConnectionBuilder",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Build",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Connections.ConnectionDelegate",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.TransferFormat",
+      "Visibility": "Public",
+      "Kind": "Enumeration",
+      "Sealed": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Field",
+          "Name": "Binary",
+          "Parameters": [],
+          "GenericParameter": [],
+          "Literal": "1"
+        },
+        {
+          "Kind": "Field",
+          "Name": "Text",
+          "Parameters": [],
+          "GenericParameter": [],
+          "Literal": "2"
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IConnectionHeartbeatFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "OnHeartbeat",
+          "Parameters": [
+            {
+              "Name": "action",
+              "Type": "System.Action<System.Object>"
+            },
+            {
+              "Name": "state",
+              "Type": "System.Object"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IConnectionIdFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ConnectionId",
+          "Parameters": [],
+          "ReturnType": "System.String",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ConnectionId",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.String"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IConnectionInherentKeepAliveFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_HasInherentKeepAlive",
+          "Parameters": [],
+          "ReturnType": "System.Boolean",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_Items",
+          "Parameters": [],
+          "ReturnType": "System.Collections.Generic.IDictionary<System.Object, System.Object>",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Items",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Collections.Generic.IDictionary<System.Object, System.Object>"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_ConnectionClosed",
+          "Parameters": [],
+          "ReturnType": "System.Threading.CancellationToken",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ConnectionClosed",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Threading.CancellationToken"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "Abort",
+          "Parameters": [],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IConnectionTransportFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_Transport",
+          "Parameters": [],
+          "ReturnType": "System.IO.Pipelines.IDuplexPipe",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_Transport",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.IO.Pipelines.IDuplexPipe"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IConnectionUserFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_User",
+          "Parameters": [],
+          "ReturnType": "System.Security.Claims.ClaimsPrincipal",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_User",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "System.Security.Claims.ClaimsPrincipal"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.IMemoryPoolFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_MemoryPool",
+          "Parameters": [],
+          "ReturnType": "System.Buffers.MemoryPool<System.Byte>",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    },
+    {
+      "Name": "Microsoft.AspNetCore.Connections.Features.ITransferFormatFeature",
+      "Visibility": "Public",
+      "Kind": "Interface",
+      "Abstract": true,
+      "ImplementedInterfaces": [],
+      "Members": [
+        {
+          "Kind": "Method",
+          "Name": "get_SupportedFormats",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Connections.TransferFormat",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "get_ActiveFormat",
+          "Parameters": [],
+          "ReturnType": "Microsoft.AspNetCore.Connections.TransferFormat",
+          "GenericParameter": []
+        },
+        {
+          "Kind": "Method",
+          "Name": "set_ActiveFormat",
+          "Parameters": [
+            {
+              "Name": "value",
+              "Type": "Microsoft.AspNetCore.Connections.TransferFormat"
+            }
+          ],
+          "ReturnType": "System.Void",
+          "GenericParameter": []
+        }
+      ],
+      "GenericParameters": []
+    }
+  ]
+}

+ 7 - 0
src/Servers/Connections.Abstractions/src/breakingchanges.netcore.json

@@ -0,0 +1,7 @@
+[
+  {
+    "TypeId": "public class Microsoft.AspNetCore.Connections.DefaultConnectionContext : Microsoft.AspNetCore.Connections.ConnectionContext, System.IDisposable, Microsoft.AspNetCore.Connections.Features.IConnectionIdFeature, Microsoft.AspNetCore.Connections.Features.IConnectionItemsFeature, Microsoft.AspNetCore.Connections.Features.IConnectionTransportFeature, Microsoft.AspNetCore.Connections.Features.IConnectionUserFeature, Microsoft.AspNetCore.Connections.Features.IConnectionLifetimeFeature",
+    "MemberId": "public System.Void Abort()",
+    "Kind": "Removal"
+  }
+]

+ 12 - 0
src/Servers/Directory.Build.props

@@ -0,0 +1,12 @@
+<Project>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
+
+  <PropertyGroup>
+    <BaseIntermediateOutputPath>$(RepositoryRoot)obj\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
+    <BaseOutputPath>$(RepositoryRoot)bin\$(MSBuildProjectName)\</BaseOutputPath>
+  </PropertyGroup>
+
+  <ItemGroup Condition="'$(IsImplementationProject)' == 'true'">
+    <PackageReference Include="Internal.AspNetCore.Analyzers" PrivateAssets="All" Version="$(InternalAspNetCoreAnalyzersPackageVersion)" />
+  </ItemGroup>
+</Project>

+ 375 - 0
src/Servers/Kestrel.sln

@@ -0,0 +1,375 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Connections.Abstractions", "Connections.Abstractions\src\Microsoft.AspNetCore.Connections.Abstractions.csproj", "{710E0641-FFF4-4994-A7FA-B22A550A8F20}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Core", "Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj", "{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Core.Tests", "Kestrel\Core\test\Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj", "{AA10418F-3291-4011-8BF5-84F315F472B5}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Https", "Kestrel\Https\src\Microsoft.AspNetCore.Server.Kestrel.Https.csproj", "{1C342888-3514-4ECE-9820-1C7BD59EA29F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel", "Kestrel\Kestrel\src\Microsoft.AspNetCore.Server.Kestrel.csproj", "{051BE5E3-073C-4CD2-92AB-7742B2931409}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Tests", "Kestrel\Kestrel\test\Microsoft.AspNetCore.Server.Kestrel.Tests.csproj", "{B46DA84E-8442-4988-9B43-6A83812A35B7}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{40FEAA2F-DDF0-4FA3-942A-0D39B722DDE7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Performance", "Kestrel\perf\Kestrel.Performance\Microsoft.AspNetCore.Server.Kestrel.Performance.csproj", "{0730A71E-CC07-4445-AC56-606B59BBF51F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformBenchmarks", "Kestrel\perf\PlatformBenchmarks\PlatformBenchmarks.csproj", "{4641895A-5E44-4158-91C9-B3718398229E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{F826BA61-60A9-45B6-AF29-FD1A6E313EF0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Http2SampleApp", "Kestrel\samples\Http2SampleApp\Http2SampleApp.csproj", "{B5C4C2EA-5439-457D-9487-924A42E4D74D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LargeResponseApp", "Kestrel\samples\LargeResponseApp\LargeResponseApp.csproj", "{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlaintextApp", "Kestrel\samples\PlaintextApp\PlaintextApp.csproj", "{0710F560-A741-4139-BC1F-BFF1895F1274}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp", "Kestrel\samples\SampleApp\SampleApp.csproj", "{F9D090D2-0568-403D-ADBA-9E079397B584}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemdTestApp", "Kestrel\samples\SystemdTestApp\SystemdTestApp.csproj", "{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Libuv.FunctionalTests", "Kestrel\test\Libuv.FunctionalTests\Libuv.FunctionalTests.csproj", "{3CCA24C1-04AC-48C0-A60A-D43FE7479529}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sockets.FunctionalTests", "Kestrel\test\Sockets.FunctionalTests\Sockets.FunctionalTests.csproj", "{28DD5565-0546-48B0-973A-B27E1C9AD032}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0256853E-1FDA-45C6-9641-87306D378508}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeGenerator", "Kestrel\tools\CodeGenerator\CodeGenerator.csproj", "{3615A580-A595-4B64-A8C7-FD361E712BEA}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions", "Kestrel\Transport.Abstractions\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.csproj", "{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv", "Kestrel\Transport.Libuv\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj", "{551F655B-F33C-4CD6-851F-4DFB89FA96A0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests", "Kestrel\Transport.Libuv\test\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.csproj", "{6716895A-A00E-4BAC-92DF-4F8C859BC51E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets", "Kestrel\Transport.Sockets\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj", "{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InMemory.FunctionalTests", "Kestrel\test\InMemory.FunctionalTests\InMemory.FunctionalTests.csproj", "{C606C348-2232-4431-98F3-998B22792A38}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Interop.FunctionalTests", "Kestrel\test\Interop.FunctionalTests\Interop.FunctionalTests.csproj", "{75C0BD33-80E2-4061-A778-08C1FBECEA7D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Libuv.BindTests", "Kestrel\test\Libuv.BindTests\Libuv.BindTests.csproj", "{0358D319-1D91-4EDE-A424-6A26734B32CB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sockets.BindTests", "Kestrel\test\Sockets.BindTests\Sockets.BindTests.csproj", "{F254FDB7-6997-4894-9E82-C4583F605394}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Debug|x64.Build.0 = Debug|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Debug|x86.Build.0 = Debug|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Release|Any CPU.Build.0 = Release|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Release|x64.ActiveCfg = Release|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Release|x64.Build.0 = Release|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Release|x86.ActiveCfg = Release|Any CPU
+		{710E0641-FFF4-4994-A7FA-B22A550A8F20}.Release|x86.Build.0 = Release|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Debug|x64.Build.0 = Debug|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Debug|x86.Build.0 = Debug|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Release|x64.ActiveCfg = Release|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Release|x64.Build.0 = Release|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Release|x86.ActiveCfg = Release|Any CPU
+		{5F6D1661-652E-4DF3-8A81-6EBE4208CE1A}.Release|x86.Build.0 = Release|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Debug|x64.Build.0 = Debug|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Debug|x86.Build.0 = Debug|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Release|x64.ActiveCfg = Release|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Release|x64.Build.0 = Release|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Release|x86.ActiveCfg = Release|Any CPU
+		{AA10418F-3291-4011-8BF5-84F315F472B5}.Release|x86.Build.0 = Release|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Debug|x64.Build.0 = Debug|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Debug|x86.Build.0 = Debug|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Release|x64.ActiveCfg = Release|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Release|x64.Build.0 = Release|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Release|x86.ActiveCfg = Release|Any CPU
+		{1C342888-3514-4ECE-9820-1C7BD59EA29F}.Release|x86.Build.0 = Release|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Debug|x64.Build.0 = Debug|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Debug|x86.Build.0 = Debug|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Release|Any CPU.Build.0 = Release|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Release|x64.ActiveCfg = Release|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Release|x64.Build.0 = Release|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Release|x86.ActiveCfg = Release|Any CPU
+		{051BE5E3-073C-4CD2-92AB-7742B2931409}.Release|x86.Build.0 = Release|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Debug|x64.Build.0 = Debug|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Debug|x86.Build.0 = Debug|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Release|x64.ActiveCfg = Release|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Release|x64.Build.0 = Release|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Release|x86.ActiveCfg = Release|Any CPU
+		{B46DA84E-8442-4988-9B43-6A83812A35B7}.Release|x86.Build.0 = Release|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Debug|x64.Build.0 = Debug|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Debug|x86.Build.0 = Debug|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Release|x64.ActiveCfg = Release|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Release|x64.Build.0 = Release|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Release|x86.ActiveCfg = Release|Any CPU
+		{0730A71E-CC07-4445-AC56-606B59BBF51F}.Release|x86.Build.0 = Release|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Debug|x64.Build.0 = Debug|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Debug|x86.Build.0 = Debug|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Release|x64.ActiveCfg = Release|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Release|x64.Build.0 = Release|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Release|x86.ActiveCfg = Release|Any CPU
+		{4641895A-5E44-4158-91C9-B3718398229E}.Release|x86.Build.0 = Release|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Debug|x64.Build.0 = Debug|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Debug|x86.Build.0 = Debug|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Release|x64.ActiveCfg = Release|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Release|x64.Build.0 = Release|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Release|x86.ActiveCfg = Release|Any CPU
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D}.Release|x86.Build.0 = Release|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Debug|x64.Build.0 = Debug|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Debug|x86.Build.0 = Debug|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Release|x64.ActiveCfg = Release|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Release|x64.Build.0 = Release|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Release|x86.ActiveCfg = Release|Any CPU
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF}.Release|x86.Build.0 = Release|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Debug|x64.Build.0 = Debug|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Debug|x86.Build.0 = Debug|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Release|x64.ActiveCfg = Release|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Release|x64.Build.0 = Release|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Release|x86.ActiveCfg = Release|Any CPU
+		{0710F560-A741-4139-BC1F-BFF1895F1274}.Release|x86.Build.0 = Release|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Debug|x64.Build.0 = Debug|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Debug|x86.Build.0 = Debug|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Release|x64.ActiveCfg = Release|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Release|x64.Build.0 = Release|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Release|x86.ActiveCfg = Release|Any CPU
+		{F9D090D2-0568-403D-ADBA-9E079397B584}.Release|x86.Build.0 = Release|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Debug|x64.Build.0 = Debug|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Debug|x86.Build.0 = Debug|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Release|x64.ActiveCfg = Release|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Release|x64.Build.0 = Release|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Release|x86.ActiveCfg = Release|Any CPU
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD}.Release|x86.Build.0 = Release|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Debug|x64.Build.0 = Debug|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Debug|x86.Build.0 = Debug|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Release|x64.ActiveCfg = Release|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Release|x64.Build.0 = Release|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Release|x86.ActiveCfg = Release|Any CPU
+		{3CCA24C1-04AC-48C0-A60A-D43FE7479529}.Release|x86.Build.0 = Release|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Debug|x64.Build.0 = Debug|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Debug|x86.Build.0 = Debug|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Release|Any CPU.Build.0 = Release|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Release|x64.ActiveCfg = Release|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Release|x64.Build.0 = Release|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Release|x86.ActiveCfg = Release|Any CPU
+		{28DD5565-0546-48B0-973A-B27E1C9AD032}.Release|x86.Build.0 = Release|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Debug|x64.Build.0 = Debug|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Debug|x86.Build.0 = Debug|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Release|x64.ActiveCfg = Release|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Release|x64.Build.0 = Release|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Release|x86.ActiveCfg = Release|Any CPU
+		{3615A580-A595-4B64-A8C7-FD361E712BEA}.Release|x86.Build.0 = Release|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Debug|x64.Build.0 = Debug|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Debug|x86.Build.0 = Debug|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Release|x64.ActiveCfg = Release|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Release|x64.Build.0 = Release|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Release|x86.ActiveCfg = Release|Any CPU
+		{FB1A66FE-1CB9-4121-A9F7-1A1459D3C9CC}.Release|x86.Build.0 = Release|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Debug|x64.Build.0 = Debug|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Debug|x86.Build.0 = Debug|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Release|x64.ActiveCfg = Release|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Release|x64.Build.0 = Release|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Release|x86.ActiveCfg = Release|Any CPU
+		{551F655B-F33C-4CD6-851F-4DFB89FA96A0}.Release|x86.Build.0 = Release|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Debug|x64.Build.0 = Debug|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Debug|x86.Build.0 = Debug|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Release|x64.ActiveCfg = Release|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Release|x64.Build.0 = Release|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Release|x86.ActiveCfg = Release|Any CPU
+		{6716895A-A00E-4BAC-92DF-4F8C859BC51E}.Release|x86.Build.0 = Release|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Debug|x64.Build.0 = Debug|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Debug|x86.Build.0 = Debug|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Release|x64.ActiveCfg = Release|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Release|x64.Build.0 = Release|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Release|x86.ActiveCfg = Release|Any CPU
+		{C0AB577F-0227-45E6-A3AC-E7ABEFC4ED60}.Release|x86.Build.0 = Release|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Debug|x64.Build.0 = Debug|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Debug|x86.Build.0 = Debug|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Release|x64.ActiveCfg = Release|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Release|x64.Build.0 = Release|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Release|x86.ActiveCfg = Release|Any CPU
+		{C606C348-2232-4431-98F3-998B22792A38}.Release|x86.Build.0 = Release|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Debug|x64.Build.0 = Debug|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Debug|x86.Build.0 = Debug|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Release|x64.ActiveCfg = Release|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Release|x64.Build.0 = Release|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Release|x86.ActiveCfg = Release|Any CPU
+		{75C0BD33-80E2-4061-A778-08C1FBECEA7D}.Release|x86.Build.0 = Release|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Debug|x64.Build.0 = Debug|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Debug|x86.Build.0 = Debug|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Release|x64.ActiveCfg = Release|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Release|x64.Build.0 = Release|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Release|x86.ActiveCfg = Release|Any CPU
+		{0358D319-1D91-4EDE-A424-6A26734B32CB}.Release|x86.Build.0 = Release|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Debug|x64.Build.0 = Debug|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Debug|x86.Build.0 = Debug|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Release|x64.ActiveCfg = Release|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Release|x64.Build.0 = Release|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Release|x86.ActiveCfg = Release|Any CPU
+		{F254FDB7-6997-4894-9E82-C4583F605394}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{0730A71E-CC07-4445-AC56-606B59BBF51F} = {40FEAA2F-DDF0-4FA3-942A-0D39B722DDE7}
+		{4641895A-5E44-4158-91C9-B3718398229E} = {40FEAA2F-DDF0-4FA3-942A-0D39B722DDE7}
+		{B5C4C2EA-5439-457D-9487-924A42E4D74D} = {F826BA61-60A9-45B6-AF29-FD1A6E313EF0}
+		{162ADD0E-724F-4E32-AE64-37BC2B6DCAFF} = {F826BA61-60A9-45B6-AF29-FD1A6E313EF0}
+		{0710F560-A741-4139-BC1F-BFF1895F1274} = {F826BA61-60A9-45B6-AF29-FD1A6E313EF0}
+		{F9D090D2-0568-403D-ADBA-9E079397B584} = {F826BA61-60A9-45B6-AF29-FD1A6E313EF0}
+		{01D031FC-61A5-45BD-BE11-57FA00BE1BCD} = {F826BA61-60A9-45B6-AF29-FD1A6E313EF0}
+		{3615A580-A595-4B64-A8C7-FD361E712BEA} = {0256853E-1FDA-45C6-9641-87306D378508}
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {48207B50-7D05-4B10-B585-890FE0F4FCE1}
+	EndGlobalSection
+EndGlobal

+ 172 - 0
src/Servers/Kestrel/Core/src/Adapter/Internal/AdaptedPipeline.cs

@@ -0,0 +1,172 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.IO.Pipelines;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
+{
+    public class AdaptedPipeline : IDuplexPipe
+    {
+        private static readonly int MinAllocBufferSize = KestrelMemoryPool.MinimumSegmentSize / 2;
+
+        private readonly IDuplexPipe _transport;
+
+        public AdaptedPipeline(IDuplexPipe transport,
+                               Pipe inputPipe,
+                               Pipe outputPipe,
+                               IKestrelTrace log)
+        {
+            _transport = transport;
+            Input = inputPipe;
+            Output = outputPipe;
+            Log = log;
+        }
+
+        public Pipe Input { get; }
+
+        public Pipe Output { get; }
+
+        public IKestrelTrace Log { get; }
+
+        PipeReader IDuplexPipe.Input => Input.Reader;
+
+        PipeWriter IDuplexPipe.Output => Output.Writer;
+
+        public async Task RunAsync(Stream stream)
+        {
+            var inputTask = ReadInputAsync(stream);
+            var outputTask = WriteOutputAsync(stream);
+
+            await inputTask;
+            await outputTask;
+        }
+
+        private async Task WriteOutputAsync(Stream stream)
+        {
+            try
+            {
+                if (stream == null)
+                {
+                    return;
+                }
+
+                while (true)
+                {
+                    var result = await Output.Reader.ReadAsync();
+                    var buffer = result.Buffer;
+
+                    try
+                    {
+                        if (buffer.IsEmpty)
+                        {
+                            if (result.IsCompleted)
+                            {
+                                break;
+                            }
+                            await stream.FlushAsync();
+                        }
+                        else if (buffer.IsSingleSegment)
+                        {
+#if NETCOREAPP2_1
+                            await stream.WriteAsync(buffer.First);
+#elif NETSTANDARD2_0
+                            var array = buffer.First.GetArray();
+                            await stream.WriteAsync(array.Array, array.Offset, array.Count);
+#else
+#error TFMs need to be updated
+#endif
+                        }
+                        else
+                        {
+                            foreach (var memory in buffer)
+                            {
+#if NETCOREAPP2_1
+                                await stream.WriteAsync(memory);
+#elif NETSTANDARD2_0
+                                var array = memory.GetArray();
+                                await stream.WriteAsync(array.Array, array.Offset, array.Count);
+#else
+#error TFMs need to be updated
+#endif
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        Output.Reader.AdvanceTo(buffer.End);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Log.LogError(0, ex, $"{nameof(AdaptedPipeline)}.{nameof(WriteOutputAsync)}");
+            }
+            finally
+            {
+                Output.Reader.Complete();
+                _transport.Output.Complete();
+            }
+        }
+
+        private async Task ReadInputAsync(Stream stream)
+        {
+            Exception error = null;
+
+            try
+            {
+                if (stream == null)
+                {
+                    // REVIEW: Do we need an exception here?
+                    return;
+                }
+
+                while (true)
+                {
+
+                    var outputBuffer = Input.Writer.GetMemory(MinAllocBufferSize);
+#if NETCOREAPP2_1
+                    var bytesRead = await stream.ReadAsync(outputBuffer);
+#elif NETSTANDARD2_0
+                    var array = outputBuffer.GetArray();
+                    var bytesRead = await stream.ReadAsync(array.Array, array.Offset, array.Count);
+#else
+#error TFMs need to be updated
+#endif
+                    Input.Writer.Advance(bytesRead);
+
+                    if (bytesRead == 0)
+                    {
+                        // FIN
+                        break;
+                    }
+
+                    var result = await Input.Writer.FlushAsync();
+
+                    if (result.IsCompleted)
+                    {
+                        break;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                // Don't rethrow the exception. It should be handled by the Pipeline consumer.
+                error = ex;
+            }
+            finally
+            {
+                Input.Writer.Complete(error);
+                // The application could have ended the input pipe so complete
+                // the transport pipe as well
+                _transport.Input.Complete();
+            }
+        }
+    }
+}

+ 26 - 0
src/Servers/Kestrel/Core/src/Adapter/Internal/ConnectionAdapterContext.cs

@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Http.Features;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
+{
+    // Even though this only includes the non-adapted ConnectionStream currently, this is a context in case
+    // we want to add more connection metadata later.
+    public class ConnectionAdapterContext
+    {
+        internal ConnectionAdapterContext(ConnectionContext connectionContext, Stream connectionStream)
+        {
+            ConnectionContext = connectionContext;
+            ConnectionStream = connectionStream;
+        }
+
+        internal ConnectionContext ConnectionContext { get; }
+
+        public IFeatureCollection Features => ConnectionContext.Features;
+
+        public Stream ConnectionStream { get; }
+    }
+}

+ 13 - 0
src/Servers/Kestrel/Core/src/Adapter/Internal/IAdaptedConnection.cs

@@ -0,0 +1,13 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
+{
+    public interface IAdaptedConnection : IDisposable
+    {
+        Stream ConnectionStream { get; }
+    }
+}

+ 13 - 0
src/Servers/Kestrel/Core/src/Adapter/Internal/IConnectionAdapter.cs

@@ -0,0 +1,13 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
+{
+    public interface IConnectionAdapter
+    {
+        bool IsHttps { get; }
+        Task<IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context);
+    }
+}

+ 47 - 0
src/Servers/Kestrel/Core/src/Adapter/Internal/LoggingConnectionAdapter.cs

@@ -0,0 +1,47 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
+{
+    public class LoggingConnectionAdapter : IConnectionAdapter
+    {
+        private readonly ILogger _logger;
+
+        public LoggingConnectionAdapter(ILogger logger)
+        {
+            if (logger == null)
+            {
+                throw new ArgumentNullException(nameof(logger));
+            }
+
+            _logger = logger;
+        }
+
+        public bool IsHttps => false;
+
+        public Task<IAdaptedConnection> OnConnectionAsync(ConnectionAdapterContext context)
+        {
+            return Task.FromResult<IAdaptedConnection>(
+                new LoggingAdaptedConnection(context.ConnectionStream, _logger));
+        }
+
+        private class LoggingAdaptedConnection : IAdaptedConnection
+        {
+            public LoggingAdaptedConnection(Stream rawStream, ILogger logger)
+            {
+                ConnectionStream = new LoggingStream(rawStream, logger);
+            }
+
+            public Stream ConnectionStream { get; }
+
+            public void Dispose()
+            {
+            }
+        }
+    }
+}

+ 266 - 0
src/Servers/Kestrel/Core/src/Adapter/Internal/LoggingStream.cs

@@ -0,0 +1,266 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
+{
+    internal class LoggingStream : Stream
+    {
+        private readonly Stream _inner;
+        private readonly ILogger _logger;
+
+        public LoggingStream(Stream inner, ILogger logger)
+        {
+            _inner = inner;
+            _logger = logger;
+        }
+
+        public override bool CanRead
+        {
+            get
+            {
+                return _inner.CanRead;
+            }
+        }
+
+        public override bool CanSeek
+        {
+            get
+            {
+                return _inner.CanSeek;
+            }
+        }
+
+        public override bool CanWrite
+        {
+            get
+            {
+                return _inner.CanWrite;
+            }
+        }
+
+        public override long Length
+        {
+            get
+            {
+                return _inner.Length;
+            }
+        }
+
+        public override long Position
+        {
+            get
+            {
+                return _inner.Position;
+            }
+
+            set
+            {
+                _inner.Position = value;
+            }
+        }
+
+        public override void Flush()
+        {
+            _inner.Flush();
+        }
+
+        public override Task FlushAsync(CancellationToken cancellationToken)
+        {
+            return _inner.FlushAsync(cancellationToken);
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            int read = _inner.Read(buffer, offset, count);
+            Log("Read", new ReadOnlySpan<byte>(buffer, offset, read));
+            return read;
+        }
+
+#if NETCOREAPP2_1
+        public override int Read(Span<byte> destination)
+        {
+            int read = _inner.Read(destination);
+            Log("Read", destination.Slice(0, read));
+            return read;
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        public async override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            int read = await _inner.ReadAsync(buffer, offset, count, cancellationToken);
+            Log("ReadAsync", new ReadOnlySpan<byte>(buffer, offset, read));
+            return read;
+        }
+
+#if NETCOREAPP2_1
+        public override async ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
+        {
+            int read = await _inner.ReadAsync(destination, cancellationToken);
+            Log("ReadAsync", destination.Span.Slice(0, read));
+            return read;
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            return _inner.Seek(offset, origin);
+        }
+
+        public override void SetLength(long value)
+        {
+            _inner.SetLength(value);
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            Log("Write", new ReadOnlySpan<byte>(buffer, offset, count));
+            _inner.Write(buffer, offset, count);
+        }
+
+#if NETCOREAPP2_1
+        public override void Write(ReadOnlySpan<byte> source)
+        {
+            Log("Write", source);
+            _inner.Write(source);
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            Log("WriteAsync", new ReadOnlySpan<byte>(buffer, offset, count));
+            return _inner.WriteAsync(buffer, offset, count, cancellationToken);
+        }
+
+#if NETCOREAPP2_1
+        public override ValueTask WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+        {
+            Log("WriteAsync", source.Span);
+            return _inner.WriteAsync(source, cancellationToken);
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        private void Log(string method, ReadOnlySpan<byte> buffer)
+        {
+            if (!_logger.IsEnabled(LogLevel.Debug))
+            {
+                return;
+            }
+
+            var builder = new StringBuilder($"{method}[{buffer.Length}] ");
+
+            // Write the hex
+            for (int i = 0; i < buffer.Length; i++)
+            {
+                builder.Append(buffer[i].ToString("X2"));
+                builder.Append(" ");
+            }
+            builder.AppendLine();
+            builder.Append("{0}");
+
+            var rawDataBuilder = new StringBuilder();
+            // Write the bytes as if they were ASCII
+            for (int i = 0; i < buffer.Length; i++)
+            {
+                rawDataBuilder.Append((char)buffer[i]);
+            }
+
+            _logger.LogDebug(builder.ToString(), rawDataBuilder.ToString());
+        }
+
+        // The below APM methods call the underlying Read/WriteAsync methods which will still be logged.
+        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            var task = ReadAsync(buffer, offset, count, default(CancellationToken), state);
+            if (callback != null)
+            {
+                task.ContinueWith(t => callback.Invoke(t));
+            }
+            return task;
+        }
+
+        public override int EndRead(IAsyncResult asyncResult)
+        {
+            return ((Task<int>)asyncResult).GetAwaiter().GetResult();
+        }
+
+        private Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
+        {
+            var tcs = new TaskCompletionSource<int>(state);
+            var task = ReadAsync(buffer, offset, count, cancellationToken);
+            task.ContinueWith((task2, state2) =>
+            {
+                var tcs2 = (TaskCompletionSource<int>)state2;
+                if (task2.IsCanceled)
+                {
+                    tcs2.SetCanceled();
+                }
+                else if (task2.IsFaulted)
+                {
+                    tcs2.SetException(task2.Exception);
+                }
+                else
+                {
+                    tcs2.SetResult(task2.Result);
+                }
+            }, tcs, cancellationToken);
+            return tcs.Task;
+        }
+
+        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            var task = WriteAsync(buffer, offset, count, default(CancellationToken), state);
+            if (callback != null)
+            {
+                task.ContinueWith(t => callback.Invoke(t));
+            }
+            return task;
+        }
+
+        public override void EndWrite(IAsyncResult asyncResult)
+        {
+            ((Task<object>)asyncResult).GetAwaiter().GetResult();
+        }
+
+        private Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
+        {
+            var tcs = new TaskCompletionSource<object>(state);
+            var task = WriteAsync(buffer, offset, count, cancellationToken);
+            task.ContinueWith((task2, state2) =>
+            {
+                var tcs2 = (TaskCompletionSource<object>)state2;
+                if (task2.IsCanceled)
+                {
+                    tcs2.SetCanceled();
+                }
+                else if (task2.IsFaulted)
+                {
+                    tcs2.SetException(task2.Exception);
+                }
+                else
+                {
+                    tcs2.SetResult(null);
+                }
+            }, tcs, cancellationToken);
+            return tcs.Task;
+        }
+    }
+}

+ 223 - 0
src/Servers/Kestrel/Core/src/Adapter/Internal/RawStream.cs

@@ -0,0 +1,223 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO.Pipelines;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Buffers;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal
+{
+    public class RawStream : Stream
+    {
+        private readonly PipeReader _input;
+        private readonly PipeWriter _output;
+
+        public RawStream(PipeReader input, PipeWriter output)
+        {
+            _input = input;
+            _output = output;
+        }
+
+        public override bool CanRead => true;
+
+        public override bool CanSeek => false;
+
+        public override bool CanWrite => true;
+
+        public override long Length
+        {
+            get
+            {
+                throw new NotSupportedException();
+            }
+        }
+
+        public override long Position
+        {
+            get
+            {
+                throw new NotSupportedException();
+            }
+            set
+            {
+                throw new NotSupportedException();
+            }
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            // ValueTask uses .GetAwaiter().GetResult() if necessary
+            // https://github.com/dotnet/corefx/blob/f9da3b4af08214764a51b2331f3595ffaf162abe/src/System.Threading.Tasks.Extensions/src/System/Threading/Tasks/ValueTask.cs#L156
+            return ReadAsyncInternal(new Memory<byte>(buffer, offset, count)).Result;
+        }
+
+        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            return ReadAsyncInternal(new Memory<byte>(buffer, offset, count)).AsTask();
+        }
+
+#if NETCOREAPP2_1
+        public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
+        {
+            return ReadAsyncInternal(destination);
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            WriteAsync(buffer, offset, count).GetAwaiter().GetResult();
+        }
+
+        public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            if (buffer != null)
+            {
+                _output.Write(new ReadOnlySpan<byte>(buffer, offset, count));
+            }
+
+            await _output.FlushAsync(cancellationToken);
+        }
+
+#if NETCOREAPP2_1
+        public override async ValueTask WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+        {
+            _output.Write(source.Span);
+            await _output.FlushAsync(cancellationToken);
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        public override void Flush()
+        {
+            FlushAsync(CancellationToken.None).GetAwaiter().GetResult();
+        }
+
+        public override Task FlushAsync(CancellationToken cancellationToken)
+        {
+            return WriteAsync(null, 0, 0, cancellationToken);
+        }
+
+        private async ValueTask<int> ReadAsyncInternal(Memory<byte> destination)
+        {
+            while (true)
+            {
+                var result = await _input.ReadAsync();
+                var readableBuffer = result.Buffer;
+                try
+                {
+                    if (!readableBuffer.IsEmpty)
+                    {
+                        // buffer.Count is int
+                        var count = (int)Math.Min(readableBuffer.Length, destination.Length);
+                        readableBuffer = readableBuffer.Slice(0, count);
+                        readableBuffer.CopyTo(destination.Span);
+                        return count;
+                    }
+
+                    if (result.IsCompleted)
+                    {
+                        return 0;
+                    }
+                }
+                finally
+                {
+                    _input.AdvanceTo(readableBuffer.End, readableBuffer.End);
+                }
+            }
+        }
+
+        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            var task = ReadAsync(buffer, offset, count, default(CancellationToken), state);
+            if (callback != null)
+            {
+                task.ContinueWith(t => callback.Invoke(t));
+            }
+            return task;
+        }
+
+        public override int EndRead(IAsyncResult asyncResult)
+        {
+            return ((Task<int>)asyncResult).GetAwaiter().GetResult();
+        }
+
+        private Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
+        {
+            var tcs = new TaskCompletionSource<int>(state);
+            var task = ReadAsync(buffer, offset, count, cancellationToken);
+            task.ContinueWith((task2, state2) =>
+            {
+                var tcs2 = (TaskCompletionSource<int>)state2;
+                if (task2.IsCanceled)
+                {
+                    tcs2.SetCanceled();
+                }
+                else if (task2.IsFaulted)
+                {
+                    tcs2.SetException(task2.Exception);
+                }
+                else
+                {
+                    tcs2.SetResult(task2.Result);
+                }
+            }, tcs, cancellationToken);
+            return tcs.Task;
+        }
+
+        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            var task = WriteAsync(buffer, offset, count, default(CancellationToken), state);
+            if (callback != null)
+            {
+                task.ContinueWith(t => callback.Invoke(t));
+            }
+            return task;
+        }
+
+        public override void EndWrite(IAsyncResult asyncResult)
+        {
+            ((Task<object>)asyncResult).GetAwaiter().GetResult();
+        }
+
+        private Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
+        {
+            var tcs = new TaskCompletionSource<object>(state);
+            var task = WriteAsync(buffer, offset, count, cancellationToken);
+            task.ContinueWith((task2, state2) =>
+            {
+                var tcs2 = (TaskCompletionSource<object>)state2;
+                if (task2.IsCanceled)
+                {
+                    tcs2.SetCanceled();
+                }
+                else if (task2.IsFaulted)
+                {
+                    tcs2.SetException(task2.Exception);
+                }
+                else
+                {
+                    tcs2.SetResult(null);
+                }
+            }, tcs, cancellationToken);
+            return tcs.Task;
+        }
+    }
+}

+ 38 - 0
src/Servers/Kestrel/Core/src/Adapter/ListenOptionsConnectionLoggingExtensions.cs

@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Hosting
+{
+    public static class ListenOptionsConnectionLoggingExtensions
+    {
+        /// <summary>
+        /// Emits verbose logs for bytes read from and written to the connection.
+        /// </summary>
+        /// <returns>
+        /// The <see cref="ListenOptions"/>.
+        /// </returns>
+        public static ListenOptions UseConnectionLogging(this ListenOptions listenOptions)
+        {
+            return listenOptions.UseConnectionLogging(loggerName: null);
+        }
+
+        /// <summary>
+        /// Emits verbose logs for bytes read from and written to the connection.
+        /// </summary>
+        /// <returns>
+        /// The <see cref="ListenOptions"/>.
+        /// </returns>
+        public static ListenOptions UseConnectionLogging(this ListenOptions listenOptions, string loggerName)
+        {
+            var loggerFactory = listenOptions.KestrelServerOptions.ApplicationServices.GetRequiredService<ILoggerFactory>();
+            var logger = loggerName == null ? loggerFactory.CreateLogger<LoggingConnectionAdapter>() : loggerFactory.CreateLogger(loggerName);
+            listenOptions.ConnectionAdapters.Add(new LoggingConnectionAdapter(logger));
+            return listenOptions;
+        }
+    }
+}

+ 37 - 0
src/Servers/Kestrel/Core/src/AnyIPListenOptions.cs

@@ -0,0 +1,37 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Net;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core
+{
+    internal class AnyIPListenOptions : ListenOptions
+    {
+        internal AnyIPListenOptions(int port)
+            : base(new IPEndPoint(IPAddress.IPv6Any, port))
+        {
+        }
+
+        internal override async Task BindAsync(AddressBindContext context)
+        {
+            // when address is 'http://hostname:port', 'http://*:port', or 'http://+:port'
+            try
+            {
+                await base.BindAsync(context).ConfigureAwait(false);
+            }
+            catch (Exception ex) when (!(ex is IOException))
+            {
+                context.Logger.LogDebug(CoreStrings.FormatFallbackToIPv4Any(IPEndPoint.Port));
+
+                // for machines that do not support IPv6
+                IPEndPoint = new IPEndPoint(IPAddress.Any, IPEndPoint.Port);
+                await base.BindAsync(context).ConfigureAwait(false);
+            }
+        }
+    }
+}

+ 178 - 0
src/Servers/Kestrel/Core/src/BadHttpRequestException.cs

@@ -0,0 +1,178 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.CompilerServices;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core
+{
+    public sealed class BadHttpRequestException : IOException
+    {
+        private BadHttpRequestException(string message, int statusCode, RequestRejectionReason reason)
+            : this(message, statusCode, reason, null)
+        { }
+
+        private BadHttpRequestException(string message, int statusCode, RequestRejectionReason reason, HttpMethod? requiredMethod)
+            : base(message)
+        {
+            StatusCode = statusCode;
+            Reason = reason;
+
+            if (requiredMethod.HasValue)
+            {
+                AllowedHeader = HttpUtilities.MethodToString(requiredMethod.Value);
+            }
+        }
+
+        public int StatusCode { get; }
+
+        internal StringValues AllowedHeader { get; }
+
+        internal RequestRejectionReason Reason { get; }
+
+        [StackTraceHidden]
+        internal static void Throw(RequestRejectionReason reason)
+        {
+            throw GetException(reason);
+        }
+
+        [StackTraceHidden]
+#pragma warning disable PUB0001 // Pubternal type in public API
+        public static void Throw(RequestRejectionReason reason, HttpMethod method)
+            => throw GetException(reason, method.ToString().ToUpperInvariant());
+#pragma warning restore PUB0001 // Pubternal type in public API
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        internal static BadHttpRequestException GetException(RequestRejectionReason reason)
+        {
+            BadHttpRequestException ex;
+            switch (reason)
+            {
+                case RequestRejectionReason.InvalidRequestHeadersNoCRLF:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_InvalidRequestHeadersNoCRLF, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.InvalidRequestLine:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_InvalidRequestLine, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.MalformedRequestInvalidHeaders:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_MalformedRequestInvalidHeaders, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.MultipleContentLengths:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_MultipleContentLengths, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.UnexpectedEndOfRequestContent:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_UnexpectedEndOfRequestContent, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.BadChunkSuffix:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_BadChunkSuffix, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.BadChunkSizeData:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_BadChunkSizeData, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.ChunkedRequestIncomplete:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_ChunkedRequestIncomplete, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.InvalidCharactersInHeaderName:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_InvalidCharactersInHeaderName, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.RequestLineTooLong:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_RequestLineTooLong, StatusCodes.Status414UriTooLong, reason);
+                    break;
+                case RequestRejectionReason.HeadersExceedMaxTotalSize:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_HeadersExceedMaxTotalSize, StatusCodes.Status431RequestHeaderFieldsTooLarge, reason);
+                    break;
+                case RequestRejectionReason.TooManyHeaders:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_TooManyHeaders, StatusCodes.Status431RequestHeaderFieldsTooLarge, reason);
+                    break;
+                case RequestRejectionReason.RequestBodyTooLarge:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_RequestBodyTooLarge, StatusCodes.Status413PayloadTooLarge, reason);
+                    break;
+                case RequestRejectionReason.RequestHeadersTimeout:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_RequestHeadersTimeout, StatusCodes.Status408RequestTimeout, reason);
+                    break;
+                case RequestRejectionReason.RequestBodyTimeout:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_RequestBodyTimeout, StatusCodes.Status408RequestTimeout, reason);
+                    break;
+                case RequestRejectionReason.OptionsMethodRequired:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_MethodNotAllowed, StatusCodes.Status405MethodNotAllowed, reason, HttpMethod.Options);
+                    break;
+                case RequestRejectionReason.ConnectMethodRequired:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_MethodNotAllowed, StatusCodes.Status405MethodNotAllowed, reason, HttpMethod.Connect);
+                    break;
+                case RequestRejectionReason.MissingHostHeader:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_MissingHostHeader, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.MultipleHostHeaders:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_MultipleHostHeaders, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.InvalidHostHeader:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_InvalidHostHeader, StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.UpgradeRequestCannotHavePayload:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest_UpgradeRequestCannotHavePayload, StatusCodes.Status400BadRequest, reason);
+                    break;
+                default:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest, StatusCodes.Status400BadRequest, reason);
+                    break;
+            }
+            return ex;
+        }
+
+        [StackTraceHidden]
+        internal static void Throw(RequestRejectionReason reason, string detail)
+        {
+            throw GetException(reason, detail);
+        }
+
+        [StackTraceHidden]
+        internal static void Throw(RequestRejectionReason reason, in StringValues detail)
+        {
+            throw GetException(reason, detail.ToString());
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        internal static BadHttpRequestException GetException(RequestRejectionReason reason, string detail)
+        {
+            BadHttpRequestException ex;
+            switch (reason)
+            {
+                case RequestRejectionReason.InvalidRequestLine:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidRequestLine_Detail(detail), StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.InvalidRequestTarget:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidRequestTarget_Detail(detail), StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.InvalidRequestHeader:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidRequestHeader_Detail(detail), StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.InvalidContentLength:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidContentLength_Detail(detail), StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.UnrecognizedHTTPVersion:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_UnrecognizedHTTPVersion(detail), StatusCodes.Status505HttpVersionNotsupported, reason);
+                    break;
+                case RequestRejectionReason.FinalTransferCodingNotChunked:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_FinalTransferCodingNotChunked(detail), StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.LengthRequired:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_LengthRequired(detail), StatusCodes.Status411LengthRequired, reason);
+                    break;
+                case RequestRejectionReason.LengthRequiredHttp10:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_LengthRequiredHttp10(detail), StatusCodes.Status400BadRequest, reason);
+                    break;
+                case RequestRejectionReason.InvalidHostHeader:
+                    ex = new BadHttpRequestException(CoreStrings.FormatBadRequest_InvalidHostHeader_Detail(detail), StatusCodes.Status400BadRequest, reason);
+                    break;
+                default:
+                    ex = new BadHttpRequestException(CoreStrings.BadRequest, StatusCodes.Status400BadRequest, reason);
+                    break;
+            }
+            return ex;
+        }
+    }
+}

+ 26 - 0
src/Servers/Kestrel/Core/src/ClientCertificateMode.cs

@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Https
+{
+    /// <summary>
+    /// Describes the client certificate requirements for a HTTPS connection.
+    /// </summary>
+    public enum ClientCertificateMode
+    {
+        /// <summary>
+        /// A client certificate is not required and will not be requested from clients.
+        /// </summary>
+        NoCertificate,
+
+        /// <summary>
+        /// A client certificate will be requested; however, authentication will not fail if a certificate is not provided by the client.
+        /// </summary>
+        AllowCertificate,
+
+        /// <summary>
+        /// A client certificate will be requested, and the client must provide a valid certificate for authentication to succeed.
+        /// </summary>
+        RequireCertificate
+    }
+}

+ 593 - 0
src/Servers/Kestrel/Core/src/CoreStrings.resx

@@ -0,0 +1,593 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="BadRequest" xml:space="preserve">
+    <value>Bad request.</value>
+  </data>
+  <data name="BadRequest_BadChunkSizeData" xml:space="preserve">
+    <value>Bad chunk size data.</value>
+  </data>
+  <data name="BadRequest_BadChunkSuffix" xml:space="preserve">
+    <value>Bad chunk suffix.</value>
+  </data>
+  <data name="BadRequest_ChunkedRequestIncomplete" xml:space="preserve">
+    <value>Chunked request incomplete.</value>
+  </data>
+  <data name="BadRequest_FinalTransferCodingNotChunked" xml:space="preserve">
+    <value>The message body length cannot be determined because the final transfer coding was set to '{detail}' instead of 'chunked'.</value>
+  </data>
+  <data name="BadRequest_HeadersExceedMaxTotalSize" xml:space="preserve">
+    <value>Request headers too long.</value>
+  </data>
+  <data name="BadRequest_InvalidCharactersInHeaderName" xml:space="preserve">
+    <value>Invalid characters in header name.</value>
+  </data>
+  <data name="BadRequest_InvalidContentLength_Detail" xml:space="preserve">
+    <value>Invalid content length: {detail}</value>
+  </data>
+  <data name="BadRequest_InvalidHostHeader" xml:space="preserve">
+    <value>Invalid Host header.</value>
+  </data>
+  <data name="BadRequest_InvalidHostHeader_Detail" xml:space="preserve">
+    <value>Invalid Host header: '{detail}'</value>
+  </data>
+  <data name="BadRequest_InvalidRequestHeadersNoCRLF" xml:space="preserve">
+    <value>Invalid request headers: missing final CRLF in header fields.</value>
+  </data>
+  <data name="BadRequest_InvalidRequestHeader_Detail" xml:space="preserve">
+    <value>Invalid request header: '{detail}'</value>
+  </data>
+  <data name="BadRequest_InvalidRequestLine" xml:space="preserve">
+    <value>Invalid request line.</value>
+  </data>
+  <data name="BadRequest_InvalidRequestLine_Detail" xml:space="preserve">
+    <value>Invalid request line: '{detail}'</value>
+  </data>
+  <data name="BadRequest_InvalidRequestTarget_Detail" xml:space="preserve">
+    <value>Invalid request target: '{detail}'</value>
+  </data>
+  <data name="BadRequest_LengthRequired" xml:space="preserve">
+    <value>{detail} request contains no Content-Length or Transfer-Encoding header.</value>
+  </data>
+  <data name="BadRequest_LengthRequiredHttp10" xml:space="preserve">
+    <value>{detail} request contains no Content-Length header.</value>
+  </data>
+  <data name="BadRequest_MalformedRequestInvalidHeaders" xml:space="preserve">
+    <value>Malformed request: invalid headers.</value>
+  </data>
+  <data name="BadRequest_MethodNotAllowed" xml:space="preserve">
+    <value>Method not allowed.</value>
+  </data>
+  <data name="BadRequest_MissingHostHeader" xml:space="preserve">
+    <value>Request is missing Host header.</value>
+  </data>
+  <data name="BadRequest_MultipleContentLengths" xml:space="preserve">
+    <value>Multiple Content-Length headers.</value>
+  </data>
+  <data name="BadRequest_MultipleHostHeaders" xml:space="preserve">
+    <value>Multiple Host headers.</value>
+  </data>
+  <data name="BadRequest_RequestLineTooLong" xml:space="preserve">
+    <value>Request line too long.</value>
+  </data>
+  <data name="BadRequest_RequestHeadersTimeout" xml:space="preserve">
+    <value>Reading the request headers timed out.</value>
+  </data>
+  <data name="BadRequest_TooManyHeaders" xml:space="preserve">
+    <value>Request contains too many headers.</value>
+  </data>
+  <data name="BadRequest_UnexpectedEndOfRequestContent" xml:space="preserve">
+    <value>Unexpected end of request content.</value>
+  </data>
+  <data name="BadRequest_UnrecognizedHTTPVersion" xml:space="preserve">
+    <value>Unrecognized HTTP version: '{detail}'</value>
+  </data>
+  <data name="BadRequest_UpgradeRequestCannotHavePayload" xml:space="preserve">
+    <value>Requests with 'Connection: Upgrade' cannot have content in the request body.</value>
+  </data>
+  <data name="FallbackToIPv4Any" xml:space="preserve">
+    <value>Failed to bind to http://[::]:{port} (IPv6Any). Attempting to bind to http://0.0.0.0:{port} instead.</value>
+  </data>
+  <data name="ResponseStreamWasUpgraded" xml:space="preserve">
+    <value>Cannot write to response body after connection has been upgraded.</value>
+  </data>
+  <data name="BigEndianNotSupported" xml:space="preserve">
+    <value>Kestrel does not support big-endian architectures.</value>
+  </data>
+  <data name="MaxRequestBufferSmallerThanRequestHeaderBuffer" xml:space="preserve">
+    <value>Maximum request buffer size ({requestBufferSize}) must be greater than or equal to maximum request header size ({requestHeaderSize}).</value>
+  </data>
+  <data name="MaxRequestBufferSmallerThanRequestLineBuffer" xml:space="preserve">
+    <value>Maximum request buffer size ({requestBufferSize}) must be greater than or equal to maximum request line size ({requestLineSize}).</value>
+  </data>
+  <data name="ServerAlreadyStarted" xml:space="preserve">
+    <value>Server has already started.</value>
+  </data>
+  <data name="UnknownTransportMode" xml:space="preserve">
+    <value>Unknown transport mode: '{mode}'.</value>
+  </data>
+  <data name="InvalidAsciiOrControlChar" xml:space="preserve">
+    <value>Invalid non-ASCII or control character in header: {character}</value>
+  </data>
+  <data name="InvalidContentLength_InvalidNumber" xml:space="preserve">
+    <value>Invalid Content-Length: "{value}". Value must be a positive integral number.</value>
+  </data>
+  <data name="NonNegativeNumberOrNullRequired" xml:space="preserve">
+    <value>Value must be null or a non-negative number.</value>
+  </data>
+  <data name="NonNegativeNumberRequired" xml:space="preserve">
+    <value>Value must be a non-negative number.</value>
+  </data>
+  <data name="PositiveNumberRequired" xml:space="preserve">
+    <value>Value must be a positive number.</value>
+  </data>
+  <data name="PositiveNumberOrNullRequired" xml:space="preserve">
+    <value>Value must be null or a positive number.</value>
+  </data>
+  <data name="UnixSocketPathMustBeAbsolute" xml:space="preserve">
+    <value>Unix socket path must be absolute.</value>
+  </data>
+  <data name="AddressBindingFailed" xml:space="preserve">
+    <value>Failed to bind to address {address}.</value>
+  </data>
+  <data name="BindingToDefaultAddress" xml:space="preserve">
+    <value>No listening endpoints were configured. Binding to {address} by default.</value>
+  </data>
+  <data name="ConfigureHttpsFromMethodCall" xml:space="preserve">
+    <value>HTTPS endpoints can only be configured using {methodName}.</value>
+  </data>
+  <data name="ConfigurePathBaseFromMethodCall" xml:space="preserve">
+    <value>A path base can only be configured using {methodName}.</value>
+  </data>
+  <data name="DynamicPortOnLocalhostNotSupported" xml:space="preserve">
+    <value>Dynamic port binding is not supported when binding to localhost. You must either bind to 127.0.0.1:0 or [::1]:0, or both.</value>
+  </data>
+  <data name="EndpointAlreadyInUse" xml:space="preserve">
+    <value>Failed to bind to address {endpoint}: address already in use.</value>
+  </data>
+  <data name="InvalidUrl" xml:space="preserve">
+    <value>Invalid URL: '{url}'.</value>
+  </data>
+  <data name="NetworkInterfaceBindingFailed" xml:space="preserve">
+    <value>Unable to bind to {address} on the {interfaceName} interface: '{error}'.</value>
+  </data>
+  <data name="OverridingWithKestrelOptions" xml:space="preserve">
+    <value>Overriding address(es) '{addresses}'. Binding to endpoints defined in {methodName} instead.</value>
+  </data>
+  <data name="OverridingWithPreferHostingUrls" xml:space="preserve">
+    <value>Overriding endpoints defined in UseKestrel() because {settingName} is set to true. Binding to address(es) '{addresses}' instead.</value>
+  </data>
+  <data name="UnsupportedAddressScheme" xml:space="preserve">
+    <value>Unrecognized scheme in server address '{address}'. Only 'http://' is supported.</value>
+  </data>
+  <data name="HeadersAreReadOnly" xml:space="preserve">
+    <value>Headers are read-only, response has already started.</value>
+  </data>
+  <data name="KeyAlreadyExists" xml:space="preserve">
+    <value>An item with the same key has already been added.</value>
+  </data>
+  <data name="HeaderNotAllowedOnResponse" xml:space="preserve">
+    <value>Setting the header {name} is not allowed on responses with status code {statusCode}.</value>
+  </data>
+  <data name="ParameterReadOnlyAfterResponseStarted" xml:space="preserve">
+    <value>{name} cannot be set because the response has already started.</value>
+  </data>
+  <data name="RequestProcessingAborted" xml:space="preserve">
+    <value>Request processing didn't complete within the shutdown timeout.</value>
+  </data>
+  <data name="TooFewBytesWritten" xml:space="preserve">
+    <value>Response Content-Length mismatch: too few bytes written ({written} of {expected}).</value>
+  </data>
+  <data name="TooManyBytesWritten" xml:space="preserve">
+    <value>Response Content-Length mismatch: too many bytes written ({written} of {expected}).</value>
+  </data>
+  <data name="UnhandledApplicationException" xml:space="preserve">
+    <value>The response has been aborted due to an unhandled application exception.</value>
+  </data>
+  <data name="WritingToResponseBodyNotSupported" xml:space="preserve">
+    <value>Writing to the response body is invalid for responses with status code {statusCode}.</value>
+  </data>
+  <data name="ConnectionShutdownError" xml:space="preserve">
+    <value>Connection shutdown abnormally.</value>
+  </data>
+  <data name="RequestProcessingEndError" xml:space="preserve">
+    <value>Connection processing ended abnormally.</value>
+  </data>
+  <data name="CannotUpgradeNonUpgradableRequest" xml:space="preserve">
+    <value>Cannot upgrade a non-upgradable request. Check IHttpUpgradeFeature.IsUpgradableRequest to determine if a request can be upgraded.</value>
+  </data>
+  <data name="UpgradedConnectionLimitReached" xml:space="preserve">
+    <value>Request cannot be upgraded because the server has already opened the maximum number of upgraded connections.</value>
+  </data>
+  <data name="UpgradeCannotBeCalledMultipleTimes" xml:space="preserve">
+    <value>IHttpUpgradeFeature.UpgradeAsync was already called and can only be called once per connection.</value>
+  </data>
+  <data name="BadRequest_RequestBodyTooLarge" xml:space="preserve">
+    <value>Request body too large.</value>
+  </data>
+  <data name="MaxRequestBodySizeCannotBeModifiedAfterRead" xml:space="preserve">
+    <value>The maximum request body size cannot be modified after the app has already started reading from the request body.</value>
+  </data>
+  <data name="MaxRequestBodySizeCannotBeModifiedForUpgradedRequests" xml:space="preserve">
+    <value>The maximum request body size cannot be modified after the request has been upgraded.</value>
+  </data>
+  <data name="PositiveTimeSpanRequired" xml:space="preserve">
+    <value>Value must be a positive TimeSpan.</value>
+  </data>
+  <data name="NonNegativeTimeSpanRequired" xml:space="preserve">
+    <value>Value must be a non-negative TimeSpan.</value>
+  </data>
+  <data name="MinimumGracePeriodRequired" xml:space="preserve">
+    <value>The request body rate enforcement grace period must be greater than {heartbeatInterval} second.</value>
+  </data>
+  <data name="SynchronousReadsDisallowed" xml:space="preserve">
+    <value>Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.</value>
+  </data>
+  <data name="SynchronousWritesDisallowed" xml:space="preserve">
+    <value>Synchronous operations are disallowed. Call WriteAsync or set AllowSynchronousIO to true instead.</value>
+  </data>
+  <data name="PositiveNumberOrNullMinDataRateRequired" xml:space="preserve">
+    <value>Value must be a positive number. To disable a minimum data rate, use null where a MinDataRate instance is expected.</value>
+  </data>
+  <data name="ConcurrentTimeoutsNotSupported" xml:space="preserve">
+    <value>Concurrent timeouts are not supported.</value>
+  </data>
+  <data name="PositiveFiniteTimeSpanRequired" xml:space="preserve">
+    <value>Timespan must be positive and finite.</value>
+  </data>
+  <data name="EndPointRequiresAtLeastOneProtocol" xml:space="preserve">
+    <value>An endpoint must be configured to serve at least one protocol.</value>
+  </data>
+  <data name="EndPointHttp2NotNegotiated" xml:space="preserve">
+    <value>HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.</value>
+  </data>
+  <data name="HPackErrorDynamicTableSizeUpdateTooLarge" xml:space="preserve">
+    <value>A dynamic table size of {size} octets is greater than the configured maximum size of {maxSize} octets.</value>
+  </data>
+  <data name="HPackErrorIndexOutOfRange" xml:space="preserve">
+    <value>Index {index} is outside the bounds of the header field table.</value>
+  </data>
+  <data name="HPackHuffmanErrorIncomplete" xml:space="preserve">
+    <value>Input data could not be fully decoded.</value>
+  </data>
+  <data name="HPackHuffmanErrorEOS" xml:space="preserve">
+    <value>Input data contains the EOS symbol.</value>
+  </data>
+  <data name="HPackHuffmanErrorDestinationTooSmall" xml:space="preserve">
+    <value>The destination buffer is not large enough to store the decoded data.</value>
+  </data>
+  <data name="HPackHuffmanError" xml:space="preserve">
+    <value>Huffman decoding error.</value>
+  </data>
+  <data name="HPackStringLengthTooLarge" xml:space="preserve">
+    <value>Decoded string length of {length} octets is greater than the configured maximum length of {maxStringLength} octets.</value>
+  </data>
+  <data name="HPackErrorIncompleteHeaderBlock" xml:space="preserve">
+    <value>The header block was incomplete and could not be fully decoded.</value>
+  </data>
+  <data name="Http2ErrorStreamIdEven" xml:space="preserve">
+    <value>The client sent a {frameType} frame with even stream ID {streamId}.</value>
+  </data>
+  <data name="Http2ErrorPushPromiseReceived" xml:space="preserve">
+    <value>The client sent a A PUSH_PROMISE frame.</value>
+  </data>
+  <data name="Http2ErrorHeadersInterleaved" xml:space="preserve">
+    <value>The client sent a {frameType} frame to stream ID {streamId} before signaling of the header block for stream ID {headersStreamId}.</value>
+  </data>
+  <data name="Http2ErrorStreamIdZero" xml:space="preserve">
+    <value>The client sent a {frameType} frame with stream ID 0.</value>
+  </data>
+  <data name="Http2ErrorStreamIdNotZero" xml:space="preserve">
+    <value>The client sent a {frameType} frame with stream ID different than 0.</value>
+  </data>
+  <data name="Http2ErrorPaddingTooLong" xml:space="preserve">
+    <value>The client sent a {frameType} frame with padding longer than or with the same length as the sent data.</value>
+  </data>
+  <data name="Http2ErrorStreamClosed" xml:space="preserve">
+    <value>The client sent a {frameType} frame to closed stream ID {streamId}.</value>
+  </data>
+  <data name="Http2ErrorStreamHalfClosedRemote" xml:space="preserve">
+    <value>The client sent a {frameType} frame to stream ID {streamId} which is in the "half-closed (remote) state".</value>
+  </data>
+  <data name="Http2ErrorStreamSelfDependency" xml:space="preserve">
+    <value>The client sent a {frameType} frame with dependency information that would cause stream ID {streamId} to depend on itself.</value>
+  </data>
+  <data name="Http2ErrorUnexpectedFrameLength" xml:space="preserve">
+    <value>The client sent a {frameType} frame with length different than {expectedLength}.</value>
+  </data>
+  <data name="Http2ErrorSettingsLengthNotMultipleOfSix" xml:space="preserve">
+    <value>The client sent a SETTINGS frame with a length that is not a multiple of 6.</value>
+  </data>
+  <data name="Http2ErrorSettingsAckLengthNotZero" xml:space="preserve">
+    <value>The client sent a SETTINGS frame with ACK set and length different than 0.</value>
+  </data>
+  <data name="Http2ErrorSettingsParameterOutOfRange" xml:space="preserve">
+    <value>The client sent a SETTINGS frame with a value for parameter {parameter} that is out of range.</value>
+  </data>
+  <data name="Http2ErrorWindowUpdateIncrementZero" xml:space="preserve">
+    <value>The client sent a WINDOW_UPDATE frame with a window size increment of 0.</value>
+  </data>
+  <data name="Http2ErrorContinuationWithNoHeaders" xml:space="preserve">
+    <value>The client sent a CONTINUATION frame not preceded by a HEADERS frame.</value>
+  </data>
+  <data name="Http2ErrorStreamIdle" xml:space="preserve">
+    <value>The client sent a {frameType} frame to idle stream ID {streamId}.</value>
+  </data>
+  <data name="Http2ErrorTrailersContainPseudoHeaderField" xml:space="preserve">
+    <value>The client sent trailers containing one or more pseudo-header fields.</value>
+  </data>
+  <data name="Http2ErrorHeaderNameUppercase" xml:space="preserve">
+    <value>The client sent a header with uppercase characters in its name.</value>
+  </data>
+  <data name="Http2ErrorTrailerNameUppercase" xml:space="preserve">
+    <value>The client sent a trailer with uppercase characters in its name.</value>
+  </data>
+  <data name="Http2ErrorHeadersWithTrailersNoEndStream" xml:space="preserve">
+    <value>The client sent a HEADERS frame containing trailers without setting the END_STREAM flag.</value>
+  </data>
+  <data name="Http2ErrorMissingMandatoryPseudoHeaderFields" xml:space="preserve">
+    <value>Request headers missing one or more mandatory pseudo-header fields.</value>
+  </data>
+  <data name="Http2ErrorPseudoHeaderFieldAfterRegularHeaders" xml:space="preserve">
+    <value>Pseudo-header field found in request headers after regular header fields.</value>
+  </data>
+  <data name="Http2ErrorUnknownPseudoHeaderField" xml:space="preserve">
+    <value>Request headers contain unknown pseudo-header field.</value>
+  </data>
+  <data name="Http2ErrorResponsePseudoHeaderField" xml:space="preserve">
+    <value>Request headers contain response-specific pseudo-header field.</value>
+  </data>
+  <data name="Http2ErrorDuplicatePseudoHeaderField" xml:space="preserve">
+    <value>Request headers contain duplicate pseudo-header field.</value>
+  </data>
+  <data name="Http2ErrorConnectionSpecificHeaderField" xml:space="preserve">
+    <value>Request headers contain connection-specific header field.</value>
+  </data>
+  <data name="UnableToConfigureHttpsBindings" xml:space="preserve">
+    <value>Unable to configure default https bindings because no IDefaultHttpsProvider service was provided.</value>
+  </data>
+  <data name="AuthenticationFailed" xml:space="preserve">
+    <value>Failed to authenticate HTTPS connection.</value>
+  </data>
+  <data name="AuthenticationTimedOut" xml:space="preserve">
+    <value>Authentication of the HTTPS connection timed out.</value>
+  </data>
+  <data name="InvalidServerCertificateEku" xml:space="preserve">
+    <value>Certificate {thumbprint} cannot be used as an SSL server certificate. It has an Extended Key Usage extension but the usages do not include Server Authentication (OID 1.3.6.1.5.5.7.3.1).</value>
+  </data>
+  <data name="PositiveTimeSpanRequired1" xml:space="preserve">
+    <value>Value must be a positive TimeSpan.</value>
+  </data>
+  <data name="ServerCertificateRequired" xml:space="preserve">
+    <value>The server certificate parameter is required.</value>
+  </data>
+  <data name="BindingToDefaultAddresses" xml:space="preserve">
+    <value>No listening endpoints were configured. Binding to {address0} and {address1} by default.</value>
+  </data>
+  <data name="CertNotFoundInStore" xml:space="preserve">
+    <value>The requested certificate {subject} could not be found in {storeLocation}/{storeName} with AllowInvalid setting: {allowInvalid}.</value>
+  </data>
+  <data name="EndpointMissingUrl" xml:space="preserve">
+    <value>The endpoint {endpointName} is missing the required 'Url' parameter.</value>
+  </data>
+  <data name="NoCertSpecifiedNoDevelopmentCertificateFound" xml:space="preserve">
+    <value>Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found.
+To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.
+For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.</value>
+  </data>
+  <data name="MultipleCertificateSources" xml:space="preserve">
+    <value>The endpoint {endpointName} specified multiple certificate sources.</value>
+  </data>
+  <data name="WritingToResponseBodyAfterResponseCompleted" xml:space="preserve">
+    <value>Cannot write to the response body, the response has completed.</value>
+  </data>
+  <data name="BadRequest_RequestBodyTimeout" xml:space="preserve">
+    <value>Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.</value>
+  </data>
+  <data name="ConnectionAbortedByApplication" xml:space="preserve">
+    <value>The connection was aborted by the application.</value>
+  </data>
+  <data name="ConnectionAbortedDuringServerShutdown" xml:space="preserve">
+    <value>The connection was aborted because the server is shutting down and request processing didn't complete within the time specified by HostOptions.ShutdownTimeout.</value>
+  </data>
+  <data name="ConnectionTimedBecauseResponseMininumDataRateNotSatisfied" xml:space="preserve">
+    <value>The connection was timed out by the server because the response was not read by the client at the specified minimum data rate.</value>
+  </data>
+  <data name="ConnectionTimedOutByServer" xml:space="preserve">
+    <value>The connection was timed out by the server.</value>
+  </data>
+  <data name="Http2ErrorFrameOverLimit" xml:space="preserve">
+    <value>The received frame size of {size} exceeds the limit {limit}.</value>
+  </data>
+  <data name="Http2ErrorMinTlsVersion" xml:space="preserve">
+    <value>Tls 1.2 or later must be used for HTTP/2. {protocol} was negotiated.</value>
+  </data>
+  <data name="Http2ErrorInvalidPreface" xml:space="preserve">
+    <value>Invalid HTTP/2 connection preface.</value>
+  </data>
+  <data name="InvalidEmptyHeaderName" xml:space="preserve">
+    <value>Header name cannot be a null or empty string.</value>
+  </data>
+  <data name="ConnectionOrStreamAbortedByCancellationToken" xml:space="preserve">
+    <value>The connection or stream was aborted because a write operation was aborted with a CancellationToken.</value>
+  </data>
+  <data name="Http2ErrorInitialWindowSizeInvalid" xml:space="preserve">
+    <value>The client sent a SETTINGS frame with a SETTINGS_INITIAL_WINDOW_SIZE that caused a flow-control window to exceed the maximum size.</value>
+  </data>
+  <data name="Http2ErrorWindowUpdateSizeInvalid" xml:space="preserve">
+    <value>The client sent a WINDOW_UPDATE frame that caused a flow-control window to exceed the maximum size.</value>
+  </data>
+  <data name="Http2ConnectionFaulted" xml:space="preserve">
+    <value>The HTTP/2 connection faulted.</value>
+  </data>
+  <data name="Http2StreamResetByClient" xml:space="preserve">
+    <value>The client reset the request stream.</value>
+  </data>
+  <data name="Http2StreamAborted" xml:space="preserve">
+    <value>The request stream was aborted.</value>
+  </data>
+  <data name="Http2ErrorFlowControlWindowExceeded" xml:space="preserve">
+    <value>The client sent more data than what was available in the flow-control window.</value>
+  </data>
+  <data name="Http2ErrorConnectMustNotSendSchemeOrPath" xml:space="preserve">
+    <value>CONNECT requests must not send :scheme or :path headers.</value>
+  </data>
+  <data name="Http2ErrorMethodInvalid" xml:space="preserve">
+    <value>The Method '{method}' is invalid.</value>
+  </data>
+  <data name="Http2StreamErrorPathInvalid" xml:space="preserve">
+    <value>The request :path is invalid: '{path}'</value>
+  </data>
+  <data name="Http2StreamErrorSchemeMismatch" xml:space="preserve">
+    <value>The request :scheme header '{requestScheme}' does not match the transport scheme '{transportScheme}'.</value>
+  </data>
+  <data name="Http2StreamErrorLessDataThanLength" xml:space="preserve">
+    <value>Less data received than specified in the Content-Length header.</value>
+  </data>
+  <data name="Http2StreamErrorMoreDataThanLength" xml:space="preserve">
+    <value>More data received than specified in the Content-Length header.</value>
+  </data>
+  <data name="Http2StreamErrorAfterHeaders" xml:space="preserve">
+    <value>An error occurred after the response headers were sent, a reset is being sent.</value>
+  </data>
+  <data name="Http2ErrorMaxStreams" xml:space="preserve">
+    <value>A new stream was refused because this connection has reached its stream limit.</value>
+  </data>
+  <data name="GreaterThanZeroRequired" xml:space="preserve">
+    <value>A value greater than zero is required.</value>
+  </data>
+  <data name="ArgumentOutOfRange" xml:space="preserve">
+    <value>A value between {min} and {max} is required.</value>
+  </data>
+  <data name="HPackErrorDynamicTableSizeUpdateNotAtBeginningOfHeaderBlock" xml:space="preserve">
+    <value>Dynamic tables size update did not occur at the beginning of the first header block.</value>
+  </data>
+  <data name="HPackErrorNotEnoughBuffer" xml:space="preserve">
+    <value>The given buffer was too small to encode any headers.</value>
+  </data>
+  <data name="HPackErrorIntegerTooBig" xml:space="preserve">
+    <value>The decoded integer exceeds the maximum value of Int32.MaxValue.</value>
+  </data>
+  <data name="ConnectionAbortedByClient" xml:space="preserve">
+    <value>The client closed the connection.</value>
+  </data>
+  <data name="Http2ErrorStreamAborted" xml:space="preserve">
+    <value>A frame of type {frameType} was received after stream {streamId} was reset or aborted.</value>
+  </data>
+</root>

+ 26 - 0
src/Servers/Kestrel/Core/src/EndpointConfiguration.cs

@@ -0,0 +1,26 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Microsoft.AspNetCore.Server.Kestrel.Https;
+using Microsoft.Extensions.Configuration;
+
+namespace Microsoft.AspNetCore.Server.Kestrel
+{
+    public class EndpointConfiguration
+    {
+        internal EndpointConfiguration(bool isHttps, ListenOptions listenOptions, HttpsConnectionAdapterOptions httpsOptions, IConfigurationSection configSection)
+        {
+            IsHttps = isHttps;
+            ListenOptions = listenOptions ?? throw new ArgumentNullException(nameof(listenOptions));
+            HttpsOptions = httpsOptions ?? throw new ArgumentNullException(nameof(httpsOptions));
+            ConfigSection = configSection ?? throw new ArgumentNullException(nameof(configSection));
+        }
+
+        public bool IsHttps { get; }
+        public ListenOptions ListenOptions { get; }
+        public HttpsConnectionAdapterOptions HttpsOptions { get; }
+        public IConfigurationSection ConfigSection { get; }
+    }
+}

+ 31 - 0
src/Servers/Kestrel/Core/src/Features/IConnectionTimeoutFeature.cs

@@ -0,0 +1,31 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
+{
+    /// <summary>
+    /// Feature for efficiently handling connection timeouts.
+    /// </summary>
+    public interface IConnectionTimeoutFeature
+    {
+        /// <summary>
+        /// Close the connection after the specified positive finite <see cref="TimeSpan"/>
+        /// unless the timeout is canceled or reset. This will fail if there is an ongoing timeout.
+        /// </summary>
+        void SetTimeout(TimeSpan timeSpan);
+
+        /// <summary>
+        /// Close the connection after the specified positive finite <see cref="TimeSpan"/>
+        /// unless the timeout is canceled or reset. This will cancel any ongoing timeouts.
+        /// </summary>
+        void ResetTimeout(TimeSpan timeSpan);
+
+        /// <summary>
+        /// Prevent the connection from closing after a timeout specified by <see cref="SetTimeout(TimeSpan)"/>
+        /// or <see cref="ResetTimeout(TimeSpan)"/>.
+        /// </summary>
+        void CancelTimeout();
+    }
+}

+ 17 - 0
src/Servers/Kestrel/Core/src/Features/IDecrementConcurrentConnectionCountFeature.cs

@@ -0,0 +1,17 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
+{
+    /// <summary>
+    /// A connection feature allowing middleware to stop counting connections towards <see cref="KestrelServerLimits.MaxConcurrentConnections"/>.
+    /// This is used by Kestrel internally to stop counting upgraded connections towards this limit.
+    /// </summary>
+    public interface IDecrementConcurrentConnectionCountFeature
+    {
+        /// <summary>
+        /// Idempotent method to stop counting a connection towards <see cref="KestrelServerLimits.MaxConcurrentConnections"/>.
+        /// </summary>
+        void ReleaseConnection();
+    }
+}

+ 10 - 0
src/Servers/Kestrel/Core/src/Features/IHttp2StreamIdFeature.cs

@@ -0,0 +1,10 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
+{
+    public interface IHttp2StreamIdFeature
+    {
+        int StreamId { get; }
+    }
+}

+ 22 - 0
src/Servers/Kestrel/Core/src/Features/IHttpMinRequestBodyDataRateFeature.cs

@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
+{
+    /// <summary>
+    /// Feature to set the minimum data rate at which the the request body must be sent by the client.
+    /// This feature is not available for HTTP/2 requests. Instead, use <see cref="KestrelServerLimits.MinRequestBodyDataRate"/>
+    /// for server-wide configuration which applies to both HTTP/2 and HTTP/1.x.
+    /// </summary>
+    public interface IHttpMinRequestBodyDataRateFeature
+    {
+        /// <summary>
+        /// The minimum data rate in bytes/second at which the request body must be sent by the client.
+        /// Setting this property to null indicates no minimum data rate should be enforced.
+        /// This limit has no effect on upgraded connections which are always unlimited.
+        /// This feature is not available for HTTP/2 requests. Instead, use <see cref="KestrelServerLimits.MinRequestBodyDataRate"/>
+        /// for server-wide configuration which applies to both HTTP/2 and HTTP/1.x.
+        /// </summary>
+        MinDataRate MinDataRate { get; set; }
+    }
+}

+ 22 - 0
src/Servers/Kestrel/Core/src/Features/IHttpMinResponseDataRateFeature.cs

@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
+{
+    /// <summary>
+    /// Feature to set the minimum data rate at which the response must be received by the client.
+    /// This feature is not available for HTTP/2 requests. Instead, use <see cref="KestrelServerLimits.MinResponseDataRate"/>
+    /// for server-wide configuration which applies to both HTTP/2 and HTTP/1.x.
+    /// </summary>
+    public interface IHttpMinResponseDataRateFeature
+    {
+        /// <summary>
+        /// The minimum data rate in bytes/second at which the response must be received by the client.
+        /// Setting this property to null indicates no minimum data rate should be enforced.
+        /// This limit has no effect on upgraded connections which are always unlimited.
+        /// This feature is not available for HTTP/2 requests. Instead, use <see cref="KestrelServerLimits.MinResponseDataRate"/>
+        /// for server-wide configuration which applies to both HTTP/2 and HTTP/1.x.
+        /// </summary>
+        MinDataRate MinDataRate { get; set; }
+    }
+}

+ 12 - 0
src/Servers/Kestrel/Core/src/Features/ITlsApplicationProtocolFeature.cs

@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Features
+{
+    public interface ITlsApplicationProtocolFeature
+    {
+        ReadOnlyMemory<byte> ApplicationProtocol { get; }
+    }
+}

+ 145 - 0
src/Servers/Kestrel/Core/src/Http2Limits.cs

@@ -0,0 +1,145 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core
+{
+    /// <summary>
+    /// Limits only applicable to HTTP/2 connections.
+    /// </summary>
+    public class Http2Limits
+    {
+        private int _maxStreamsPerConnection = 100;
+        private int _headerTableSize = (int)Http2PeerSettings.DefaultHeaderTableSize;
+        private int _maxFrameSize = (int)Http2PeerSettings.DefaultMaxFrameSize;
+        private int _maxRequestHeaderFieldSize = 8192;
+        private int _initialConnectionWindowSize = 1024 * 128; // Larger than the default 64kb, and larger than any one single stream.
+        private int _initialStreamWindowSize = 1024 * 96; // Larger than the default 64kb
+
+        /// <summary>
+        /// Limits the number of concurrent request streams per HTTP/2 connection. Excess streams will be refused.
+        /// <para>
+        /// Value must be greater than 0, defaults to 100
+        /// </para>
+        /// </summary>
+        public int MaxStreamsPerConnection
+        {
+            get => _maxStreamsPerConnection;
+            set
+            {
+                if (value <= 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.GreaterThanZeroRequired);
+                }
+
+                _maxStreamsPerConnection = value;
+            }
+        }
+
+        /// <summary>
+        /// Limits the size of the header compression table, in octets, the HPACK decoder on the server can use.
+        /// <para>
+        /// Value must be greater than 0, defaults to 4096
+        /// </para>
+        /// </summary>
+        public int HeaderTableSize
+        {
+            get => _headerTableSize;
+            set
+            {
+                if (value <= 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.GreaterThanZeroRequired);
+                }
+
+                _headerTableSize = value;
+            }
+        }
+
+        /// <summary>
+        /// Indicates the size of the largest frame payload that is allowed to be received, in octets. The size must be between 2^14 and 2^24-1.
+        /// <para>
+        /// Value must be between 2^14 and 2^24, defaults to 2^14 (16,384)
+        /// </para>
+        /// </summary>
+        public int MaxFrameSize
+        {
+            get => _maxFrameSize;
+            set
+            {
+                if (value < Http2PeerSettings.MinAllowedMaxFrameSize || value > Http2PeerSettings.MaxAllowedMaxFrameSize)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.FormatArgumentOutOfRange(Http2PeerSettings.MinAllowedMaxFrameSize, Http2PeerSettings.MaxAllowedMaxFrameSize));
+                }
+
+                _maxFrameSize = value;
+            }
+        }
+
+        /// <summary>
+        /// Indicates the size of the maximum allowed size of a request header field sequence. This limit applies to both name and value sequences in their compressed and uncompressed representations.
+        /// <para>
+        /// Value must be greater than 0, defaults to 8192
+        /// </para>
+        /// </summary>
+        public int MaxRequestHeaderFieldSize
+        {
+            get => _maxRequestHeaderFieldSize;
+            set
+            {
+                if (value <= 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), value, CoreStrings.GreaterThanZeroRequired);
+                }
+
+                _maxRequestHeaderFieldSize = value;
+            }
+        }
+
+        /// <summary>
+        /// Indicates how much request body data the server is willing to receive and buffer at a time aggregated across all
+        /// requests (streams) per connection. Note requests are also limited by <see cref="InitialStreamWindowSize"/>
+        /// <para>
+        /// Value must be greater than or equal to 65,535 and less than 2^31, defaults to 128 kb.
+        /// </para>
+        /// </summary>
+        public int InitialConnectionWindowSize
+        {
+            get => _initialConnectionWindowSize;
+            set
+            {
+                if (value < Http2PeerSettings.DefaultInitialWindowSize || value > Http2PeerSettings.MaxWindowSize)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), value,
+                        CoreStrings.FormatArgumentOutOfRange(Http2PeerSettings.DefaultInitialWindowSize, Http2PeerSettings.MaxWindowSize));
+                }
+
+                _initialConnectionWindowSize = value;
+            }
+        }
+
+        /// <summary>
+        /// Indicates how much request body data the server is willing to receive and buffer at a time per stream.
+        /// Note connections are also limited by <see cref="InitialConnectionWindowSize"/>
+        /// <para>
+        /// Value must be greater than or equal to 65,535 and less than 2^31, defaults to 96 kb.
+        /// </para>
+        /// </summary>
+        public int InitialStreamWindowSize
+        {
+            get => _initialStreamWindowSize;
+            set
+            {
+                if (value < Http2PeerSettings.DefaultInitialWindowSize || value > Http2PeerSettings.MaxWindowSize)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), value,
+                        CoreStrings.FormatArgumentOutOfRange(Http2PeerSettings.DefaultInitialWindowSize, Http2PeerSettings.MaxWindowSize));
+                }
+
+                _initialStreamWindowSize = value;
+            }
+        }
+    }
+}

+ 16 - 0
src/Servers/Kestrel/Core/src/HttpProtocols.cs

@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core
+{
+    [Flags]
+    public enum HttpProtocols
+    {
+        None = 0x0,
+        Http1 = 0x1,
+        Http2 = 0x2,
+        Http1AndHttp2 = Http1 | Http2,
+    }
+}

+ 97 - 0
src/Servers/Kestrel/Core/src/HttpsConnectionAdapterOptions.cs

@@ -0,0 +1,97 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Net.Security;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Https
+{
+    /// <summary>
+    /// Settings for how Kestrel should handle HTTPS connections.
+    /// </summary>
+    public class HttpsConnectionAdapterOptions
+    {
+        private TimeSpan _handshakeTimeout;
+
+        /// <summary>
+        /// Initializes a new instance of <see cref="HttpsConnectionAdapterOptions"/>.
+        /// </summary>
+        public HttpsConnectionAdapterOptions()
+        {
+            ClientCertificateMode = ClientCertificateMode.NoCertificate;
+            SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11;
+            HandshakeTimeout = TimeSpan.FromSeconds(10);
+        }
+
+        /// <summary>
+        /// <para>
+        /// Specifies the server certificate used to authenticate HTTPS connections. This is ignored if ServerCertificateSelector is set.
+        /// </para>
+        /// <para>
+        /// If the server certificate has an Extended Key Usage extension, the usages must include Server Authentication (OID 1.3.6.1.5.5.7.3.1).
+        /// </para>
+        /// </summary>
+        public X509Certificate2 ServerCertificate { get; set; }
+
+        /// <summary>
+        /// <para>
+        /// A callback that will be invoked to dynamically select a server certificate. This is higher priority than ServerCertificate.
+        /// If SNI is not available then the name parameter will be null.
+        /// </para>
+        /// <para>
+        /// If the server certificate has an Extended Key Usage extension, the usages must include Server Authentication (OID 1.3.6.1.5.5.7.3.1).
+        /// </para>
+        /// </summary>
+        public Func<ConnectionContext, string, X509Certificate2> ServerCertificateSelector { get; set; }
+
+        /// <summary>
+        /// Specifies the client certificate requirements for a HTTPS connection. Defaults to <see cref="ClientCertificateMode.NoCertificate"/>.
+        /// </summary>
+        public ClientCertificateMode ClientCertificateMode { get; set; }
+
+        /// <summary>
+        /// Specifies a callback for additional client certificate validation that will be invoked during authentication.
+        /// </summary>
+        public Func<X509Certificate2, X509Chain, SslPolicyErrors, bool> ClientCertificateValidation { get; set; }
+
+        /// <summary>
+        /// Specifies allowable SSL protocols. Defaults to <see cref="SslProtocols.Tls12" /> and <see cref="SslProtocols.Tls11"/>.
+        /// </summary>
+        public SslProtocols SslProtocols { get; set; }
+
+        /// <summary>
+        /// The protocols enabled on this endpoint.
+        /// </summary>
+        /// <remarks>Defaults to HTTP/1.x only.</remarks>
+        internal HttpProtocols HttpProtocols { get; set; }
+
+        /// <summary>
+        /// Specifies whether the certificate revocation list is checked during authentication.
+        /// </summary>
+        public bool CheckCertificateRevocation { get; set; }
+
+        /// <summary>
+        /// Specifies the maximum amount of time allowed for the TLS/SSL handshake. This must be positive and finite.
+        /// </summary>
+        public TimeSpan HandshakeTimeout
+        {
+            get => _handshakeTimeout;
+            set
+            {
+                if (value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.PositiveTimeSpanRequired);
+                }
+                _handshakeTimeout = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue;
+            }
+        }
+
+        // For testing
+        internal Action OnHandshakeStarted;
+    }
+}

+ 20 - 0
src/Servers/Kestrel/Core/src/Internal/AddressBindContext.cs

@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
+{
+    internal class AddressBindContext
+    {
+        public ICollection<string> Addresses { get; set; }
+        public List<ListenOptions> ListenOptions { get; set; }
+        public KestrelServerOptions ServerOptions { get; set; }
+        public ILogger Logger { get; set; }
+
+        public Func<ListenOptions, Task> CreateBinding { get; set; }
+    }
+}

+ 268 - 0
src/Servers/Kestrel/Core/src/Internal/AddressBinder.cs

@@ -0,0 +1,268 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting.Server.Features;
+using Microsoft.AspNetCore.Http.Internal;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
+{
+    internal class AddressBinder
+    {
+        public static async Task BindAsync(IServerAddressesFeature addresses,
+            KestrelServerOptions serverOptions,
+            ILogger logger,
+            Func<ListenOptions, Task> createBinding)
+        {
+            var listenOptions = serverOptions.ListenOptions;
+            var strategy = CreateStrategy(
+                listenOptions.ToArray(),
+                addresses.Addresses.ToArray(),
+                addresses.PreferHostingUrls);
+
+            var context = new AddressBindContext
+            {
+                Addresses = addresses.Addresses,
+                ListenOptions = listenOptions,
+                ServerOptions = serverOptions,
+                Logger = logger,
+                CreateBinding = createBinding
+            };
+
+            // reset options. The actual used options and addresses will be populated
+            // by the address binding feature
+            listenOptions.Clear();
+            addresses.Addresses.Clear();
+
+            await strategy.BindAsync(context).ConfigureAwait(false);
+        }
+
+        private static IStrategy CreateStrategy(ListenOptions[] listenOptions, string[] addresses, bool preferAddresses)
+        {
+            var hasListenOptions = listenOptions.Length > 0;
+            var hasAddresses = addresses.Length > 0;
+
+            if (preferAddresses && hasAddresses)
+            {
+                if (hasListenOptions)
+                {
+                    return new OverrideWithAddressesStrategy(addresses);
+                }
+
+                return new AddressesStrategy(addresses);
+            }
+            else if (hasListenOptions)
+            {
+                if (hasAddresses)
+                {
+                    return new OverrideWithEndpointsStrategy(listenOptions, addresses);
+                }
+
+                return new EndpointsStrategy(listenOptions);
+            }
+            else if (hasAddresses)
+            {
+                // If no endpoints are configured directly using KestrelServerOptions, use those configured via the IServerAddressesFeature.
+                return new AddressesStrategy(addresses);
+            }
+            else
+            {
+                // "localhost" for both IPv4 and IPv6 can't be represented as an IPEndPoint.
+                return new DefaultAddressStrategy();
+            }
+        }
+
+        /// <summary>
+        /// Returns an <see cref="IPEndPoint"/> for the given host an port.
+        /// If the host parameter isn't "localhost" or an IP address, use IPAddress.Any.
+        /// </summary>
+        protected internal static bool TryCreateIPEndPoint(BindingAddress address, out IPEndPoint endpoint)
+        {
+            if (!IPAddress.TryParse(address.Host, out var ip))
+            {
+                endpoint = null;
+                return false;
+            }
+
+            endpoint = new IPEndPoint(ip, address.Port);
+            return true;
+        }
+
+        internal static async Task BindEndpointAsync(ListenOptions endpoint, AddressBindContext context)
+        {
+            try
+            {
+                await context.CreateBinding(endpoint).ConfigureAwait(false);
+            }
+            catch (AddressInUseException ex)
+            {
+                throw new IOException(CoreStrings.FormatEndpointAlreadyInUse(endpoint), ex);
+            }
+
+            context.ListenOptions.Add(endpoint);
+        }
+
+        internal static ListenOptions ParseAddress(string address, out bool https)
+        {
+            var parsedAddress = BindingAddress.Parse(address);
+            https = false;
+
+            if (parsedAddress.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase))
+            {
+                https = true;
+            }
+            else if (!parsedAddress.Scheme.Equals("http", StringComparison.OrdinalIgnoreCase))
+            {
+                throw new InvalidOperationException(CoreStrings.FormatUnsupportedAddressScheme(address));
+            }
+
+            if (!string.IsNullOrEmpty(parsedAddress.PathBase))
+            {
+                throw new InvalidOperationException(CoreStrings.FormatConfigurePathBaseFromMethodCall($"{nameof(IApplicationBuilder)}.UsePathBase()"));
+            }
+
+            ListenOptions options = null;
+            if (parsedAddress.IsUnixPipe)
+            {
+                options = new ListenOptions(parsedAddress.UnixPipePath);
+            }
+            else if (string.Equals(parsedAddress.Host, "localhost", StringComparison.OrdinalIgnoreCase))
+            {
+                // "localhost" for both IPv4 and IPv6 can't be represented as an IPEndPoint.
+                options = new LocalhostListenOptions(parsedAddress.Port);
+            }
+            else if (TryCreateIPEndPoint(parsedAddress, out var endpoint))
+            {
+                options = new ListenOptions(endpoint);
+            }
+            else
+            {
+                // when address is 'http://hostname:port', 'http://*:port', or 'http://+:port'
+                options = new AnyIPListenOptions(parsedAddress.Port);
+            }
+
+            return options;
+        }
+
+        private interface IStrategy
+        {
+            Task BindAsync(AddressBindContext context);
+        }
+
+        private class DefaultAddressStrategy : IStrategy
+        {
+            public async Task BindAsync(AddressBindContext context)
+            {
+                var httpDefault = ParseAddress(Constants.DefaultServerAddress, out var https);
+                context.ServerOptions.ApplyEndpointDefaults(httpDefault);
+                await httpDefault.BindAsync(context).ConfigureAwait(false);
+
+                // Conditional https default, only if a cert is available
+                var httpsDefault = ParseAddress(Constants.DefaultServerHttpsAddress, out https);
+                context.ServerOptions.ApplyEndpointDefaults(httpsDefault);
+
+                if (httpsDefault.ConnectionAdapters.Any(f => f.IsHttps)
+                    || httpsDefault.TryUseHttps())
+                {
+                    await httpsDefault.BindAsync(context).ConfigureAwait(false);
+                    context.Logger.LogDebug(CoreStrings.BindingToDefaultAddresses,
+                        Constants.DefaultServerAddress, Constants.DefaultServerHttpsAddress);
+                }
+                else
+                {
+                    // No default cert is available, do not bind to the https endpoint.
+                    context.Logger.LogDebug(CoreStrings.BindingToDefaultAddress, Constants.DefaultServerAddress);
+                }
+            }
+        }
+
+        private class OverrideWithAddressesStrategy : AddressesStrategy
+        {
+            public OverrideWithAddressesStrategy(IReadOnlyCollection<string> addresses)
+                : base(addresses)
+            {
+            }
+
+            public override Task BindAsync(AddressBindContext context)
+            {
+                var joined = string.Join(", ", _addresses);
+                context.Logger.LogInformation(CoreStrings.OverridingWithPreferHostingUrls, nameof(IServerAddressesFeature.PreferHostingUrls), joined);
+
+                return base.BindAsync(context);
+            }
+        }
+
+        private class OverrideWithEndpointsStrategy : EndpointsStrategy
+        {
+            private readonly string[] _originalAddresses;
+
+            public OverrideWithEndpointsStrategy(IReadOnlyCollection<ListenOptions> endpoints, string[] originalAddresses)
+                : base(endpoints)
+            {
+                _originalAddresses = originalAddresses;
+            }
+
+            public override Task BindAsync(AddressBindContext context)
+            {
+                var joined = string.Join(", ", _originalAddresses);
+                context.Logger.LogWarning(CoreStrings.OverridingWithKestrelOptions, joined, "UseKestrel()");
+
+                return base.BindAsync(context);
+            }
+        }
+
+        private class EndpointsStrategy : IStrategy
+        {
+            private readonly IReadOnlyCollection<ListenOptions> _endpoints;
+
+            public EndpointsStrategy(IReadOnlyCollection<ListenOptions> endpoints)
+            {
+                _endpoints = endpoints;
+            }
+
+            public virtual async Task BindAsync(AddressBindContext context)
+            {
+                foreach (var endpoint in _endpoints)
+                {
+                    await endpoint.BindAsync(context).ConfigureAwait(false);
+                }
+            }
+        }
+
+        private class AddressesStrategy : IStrategy
+        {
+            protected readonly IReadOnlyCollection<string> _addresses;
+
+            public AddressesStrategy(IReadOnlyCollection<string> addresses)
+            {
+                _addresses = addresses;
+            }
+
+            public virtual async Task BindAsync(AddressBindContext context)
+            {
+                foreach (var address in _addresses)
+                {
+                    var options = ParseAddress(address, out var https);
+                    context.ServerOptions.ApplyEndpointDefaults(options);
+
+                    if (https && !options.ConnectionAdapters.Any(f => f.IsHttps))
+                    {
+                        options.UseHttps();
+                    }
+
+                    await options.BindAsync(context).ConfigureAwait(false);
+                }
+            }
+        }
+    }
+}

+ 153 - 0
src/Servers/Kestrel/Core/src/Internal/BufferReader.cs

@@ -0,0 +1,153 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Runtime.CompilerServices;
+
+namespace System.Buffers
+{
+    internal ref struct BufferReader
+    {
+        private ReadOnlySpan<byte> _currentSpan;
+        private int _index;
+
+        private ReadOnlySequence<byte> _sequence;
+        private SequencePosition _currentSequencePosition;
+        private SequencePosition _nextSequencePosition;
+
+        private int _consumedBytes;
+        private bool _end;
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public BufferReader(in ReadOnlySequence<byte> buffer)
+        {
+            _index = 0;
+            _consumedBytes = 0;
+            _sequence = buffer;
+            _currentSequencePosition = _sequence.Start;
+            _nextSequencePosition = _currentSequencePosition;
+
+            if (_sequence.TryGet(ref _nextSequencePosition, out var memory, true))
+            {
+                _end = false;
+                _currentSpan = memory.Span;
+                if (_currentSpan.Length == 0)
+                {
+                    // No space in first span, move to one with space
+                    MoveNext();
+                }
+            }
+            else
+            {
+                // No space in any spans and at end of sequence
+                _end = true;
+                _currentSpan = default;
+            }
+        }
+
+        public bool End => _end;
+
+        public int CurrentSegmentIndex => _index;
+
+        public SequencePosition Position => _sequence.GetPosition(_index, _currentSequencePosition);
+
+        public ReadOnlySpan<byte> CurrentSegment => _currentSpan;
+
+        public ReadOnlySpan<byte> UnreadSegment => _currentSpan.Slice(_index);
+
+        public int ConsumedBytes => _consumedBytes;
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public int Peek()
+        {
+            if (_end)
+            {
+                return -1;
+            }
+            return _currentSpan[_index];
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public int Read()
+        {
+            if (_end)
+            {
+                return -1;
+            }
+
+            var value = _currentSpan[_index];
+            _index++;
+            _consumedBytes++;
+
+            if (_index >= _currentSpan.Length)
+            {
+                MoveNext();
+            }
+
+            return value;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void MoveNext()
+        {
+            var previous = _nextSequencePosition;
+            while (_sequence.TryGet(ref _nextSequencePosition, out var memory, true))
+            {
+                _currentSequencePosition = previous;
+                _currentSpan = memory.Span;
+                _index = 0;
+                if (_currentSpan.Length > 0)
+                {
+                    return;
+                }
+            }
+            _end = true;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void Advance(int byteCount)
+        {
+            if (!_end && byteCount > 0 && (_index + byteCount) < _currentSpan.Length)
+            {
+                _consumedBytes += byteCount;
+                _index += byteCount;
+            }
+            else
+            {
+                AdvanceNext(byteCount);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void AdvanceNext(int byteCount)
+        {
+            if (byteCount < 0)
+            {
+                BuffersThrowHelper.ThrowArgumentOutOfRangeException(BuffersThrowHelper.ExceptionArgument.length);
+            }
+
+            _consumedBytes += byteCount;
+
+            while (!_end && byteCount > 0)
+            {
+                if ((_index + byteCount) < _currentSpan.Length)
+                {
+                    _index += byteCount;
+                    byteCount = 0;
+                    break;
+                }
+
+                var remaining = (_currentSpan.Length - _index);
+
+                _index += remaining;
+                byteCount -= remaining;
+
+                MoveNext();
+            }
+
+            if (byteCount > 0)
+            {
+                BuffersThrowHelper.ThrowArgumentOutOfRangeException(BuffersThrowHelper.ExceptionArgument.length);
+            }
+        }
+    }
+}

+ 96 - 0
src/Servers/Kestrel/Core/src/Internal/BufferWriter.cs

@@ -0,0 +1,96 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Runtime.CompilerServices;
+
+namespace System.Buffers
+{
+    internal ref struct BufferWriter<T> where T : IBufferWriter<byte>
+    {
+        private T _output;
+        private Span<byte> _span;
+        private int _buffered;
+        private long _bytesCommitted;
+
+        public BufferWriter(T output)
+        {
+            _buffered = 0;
+            _bytesCommitted = 0;
+            _output = output;
+            _span = output.GetSpan();
+        }
+
+        public Span<byte> Span => _span;
+        public long BytesCommitted => _bytesCommitted;
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void Commit()
+        {
+            var buffered = _buffered;
+            if (buffered > 0)
+            {
+                _bytesCommitted += buffered;
+                _buffered = 0;
+                _output.Advance(buffered);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void Advance(int count)
+        {
+            _buffered += count;
+            _span = _span.Slice(count);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void Write(ReadOnlySpan<byte> source)
+        {
+            if (_span.Length >= source.Length)
+            {
+                source.CopyTo(_span);
+                Advance(source.Length);
+            }
+            else
+            {
+                WriteMultiBuffer(source);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void Ensure(int count = 1)
+        {
+            if (_span.Length < count)
+            {
+                EnsureMore(count);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void EnsureMore(int count = 0)
+        {
+            if (_buffered > 0)
+            {
+                Commit();
+            }
+
+            _output.GetMemory(count);
+            _span = _output.GetSpan();
+        }
+
+        private void WriteMultiBuffer(ReadOnlySpan<byte> source)
+        {
+            while (source.Length > 0)
+            {
+                if (_span.Length == 0)
+                {
+                    EnsureMore();
+                }
+
+                var writable = Math.Min(source.Length, _span.Length);
+                source.Slice(0, writable).CopyTo(_span);
+                source = source.Slice(writable);
+                Advance(writable);
+            }
+        }
+    }
+}

+ 97 - 0
src/Servers/Kestrel/Core/src/Internal/CertificateLoader.cs

@@ -0,0 +1,97 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Linq;
+using System.Security.Cryptography.X509Certificates;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Https.Internal
+{
+    public static class CertificateLoader
+    {
+        // See http://oid-info.com/get/1.3.6.1.5.5.7.3.1
+        // Indicates that a certificate can be used as a SSL server certificate
+        private const string ServerAuthenticationOid = "1.3.6.1.5.5.7.3.1";
+
+        public static X509Certificate2 LoadFromStoreCert(string subject, string storeName, StoreLocation storeLocation, bool allowInvalid)
+        {
+            using (var store = new X509Store(storeName, storeLocation))
+            {
+                X509Certificate2Collection storeCertificates = null;
+                X509Certificate2 foundCertificate = null;
+
+                try
+                {
+                    store.Open(OpenFlags.ReadOnly);
+                    storeCertificates = store.Certificates;
+                    var foundCertificates = storeCertificates.Find(X509FindType.FindBySubjectName, subject, !allowInvalid);
+                    foundCertificate = foundCertificates
+                        .OfType<X509Certificate2>()
+                        .Where(IsCertificateAllowedForServerAuth)
+                        .OrderByDescending(certificate => certificate.NotAfter)
+                        .FirstOrDefault();
+
+                    if (foundCertificate == null)
+                    {
+                        throw new InvalidOperationException(CoreStrings.FormatCertNotFoundInStore(subject, storeLocation, storeName, allowInvalid));
+                    }
+
+                    return foundCertificate;
+                }
+                finally
+                {
+                    DisposeCertificates(storeCertificates, except: foundCertificate);
+                }
+            }
+        }
+
+        internal static bool IsCertificateAllowedForServerAuth(X509Certificate2 certificate)
+        {
+            /* If the Extended Key Usage extension is included, then we check that the serverAuth usage is included. (http://oid-info.com/get/1.3.6.1.5.5.7.3.1)
+             * If the Extended Key Usage extension is not included, then we assume the certificate is allowed for all usages.
+             *
+             * See also https://blogs.msdn.microsoft.com/kaushal/2012/02/17/client-certificates-vs-server-certificates/
+             *
+             * From https://tools.ietf.org/html/rfc3280#section-4.2.1.13 "Certificate Extensions: Extended Key Usage"
+             *
+             * If the (Extended Key Usage) extension is present, then the certificate MUST only be used
+             * for one of the purposes indicated.  If multiple purposes are
+             * indicated the application need not recognize all purposes indicated,
+             * as long as the intended purpose is present.  Certificate using
+             * applications MAY require that a particular purpose be indicated in
+             * order for the certificate to be acceptable to that application.
+             */
+
+            var hasEkuExtension = false;
+
+            foreach (var extension in certificate.Extensions.OfType<X509EnhancedKeyUsageExtension>())
+            {
+                hasEkuExtension = true;
+                foreach (var oid in extension.EnhancedKeyUsages)
+                {
+                    if (oid.Value.Equals(ServerAuthenticationOid, StringComparison.Ordinal))
+                    {
+                        return true;
+                    }
+                }
+            }
+
+            return !hasEkuExtension;
+        }
+
+        private static void DisposeCertificates(X509Certificate2Collection certificates, X509Certificate2 except)
+        {
+            if (certificates != null)
+            {
+                foreach (var certificate in certificates)
+                {
+                    if (!certificate.Equals(except))
+                    {
+                        certificate.Dispose();
+                    }
+                }
+            }
+        }
+    }
+}

+ 68 - 0
src/Servers/Kestrel/Core/src/Internal/ClosedStream.cs

@@ -0,0 +1,68 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Https.Internal
+{
+    internal class ClosedStream : Stream
+    {
+        private static readonly Task<int> ZeroResultTask = Task.FromResult(result: 0);
+
+        public override bool CanRead => true;
+        public override bool CanSeek => false;
+        public override bool CanWrite => false;
+
+        public override long Length
+        {
+            get
+            {
+                throw new NotSupportedException();
+            }
+        }
+
+        public override long Position
+        {
+            get
+            {
+                throw new NotSupportedException();
+            }
+            set
+            {
+                throw new NotSupportedException();
+            }
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return 0;
+        }
+
+        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            return ZeroResultTask;
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new NotSupportedException();
+        }
+    }
+}

+ 195 - 0
src/Servers/Kestrel/Core/src/Internal/ConfigurationReader.cs

@@ -0,0 +1,195 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Extensions.Configuration;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
+{
+    internal class ConfigurationReader
+    {
+        private const string ProtocolsKey = "Protocols";
+        private const string CertificatesKey = "Certificates";
+        private const string CertificateKey = "Certificate";
+        private const string EndpointDefaultsKey = "EndpointDefaults";
+        private const string EndpointsKey = "Endpoints";
+        private const string UrlKey = "Url";
+
+        private IConfiguration _configuration;
+        private IDictionary<string, CertificateConfig> _certificates;
+        private IList<EndpointConfig> _endpoints;
+        private EndpointDefaults _endpointDefaults;
+
+        public ConfigurationReader(IConfiguration configuration)
+        {
+            _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
+        }
+
+        public IDictionary<string, CertificateConfig> Certificates
+        {
+            get
+            {
+                if (_certificates == null)
+                {
+                    ReadCertificates();
+                }
+
+                return _certificates;
+            }
+        }
+
+        public EndpointDefaults EndpointDefaults
+        {
+            get
+            {
+                if (_endpointDefaults == null)
+                {
+                    ReadEndpointDefaults();
+                }
+
+                return _endpointDefaults;
+            }
+        }
+
+        public IEnumerable<EndpointConfig> Endpoints
+        {
+            get
+            {
+                if (_endpoints == null)
+                {
+                    ReadEndpoints();
+                }
+
+                return _endpoints;
+            }
+        }
+
+        private void ReadCertificates()
+        {
+            _certificates = new Dictionary<string, CertificateConfig>(0);
+
+            var certificatesConfig = _configuration.GetSection(CertificatesKey).GetChildren();
+            foreach (var certificateConfig in certificatesConfig)
+            {
+                _certificates.Add(certificateConfig.Key, new CertificateConfig(certificateConfig));
+            }
+        }
+
+        // "EndpointDefaults": {
+        //    "Protocols": "Http1AndHttp2",
+        // }
+        private void ReadEndpointDefaults()
+        {
+            var configSection = _configuration.GetSection(EndpointDefaultsKey);
+            _endpointDefaults = new EndpointDefaults
+            {
+                Protocols = ParseProtocols(configSection[ProtocolsKey])
+            };
+        }
+
+        private void ReadEndpoints()
+        {
+            _endpoints = new List<EndpointConfig>();
+
+            var endpointsConfig = _configuration.GetSection(EndpointsKey).GetChildren();
+            foreach (var endpointConfig in endpointsConfig)
+            {
+                // "EndpointName": {
+                //    "Url": "https://*:5463",
+                //    "Protocols": "Http1AndHttp2",
+                //    "Certificate": {
+                //        "Path": "testCert.pfx",
+                //        "Password": "testPassword"
+                //    }
+                // }
+
+                var url = endpointConfig[UrlKey];
+                if (string.IsNullOrEmpty(url))
+                {
+                    throw new InvalidOperationException(CoreStrings.FormatEndpointMissingUrl(endpointConfig.Key));
+                }
+
+                var endpoint = new EndpointConfig
+                {
+                    Name = endpointConfig.Key,
+                    Url = url,
+                    Protocols = ParseProtocols(endpointConfig[ProtocolsKey]),
+                    ConfigSection = endpointConfig,
+                    Certificate = new CertificateConfig(endpointConfig.GetSection(CertificateKey)),
+                };
+                _endpoints.Add(endpoint);
+            }
+        }
+
+        private static HttpProtocols? ParseProtocols(string protocols)
+        {
+            if (Enum.TryParse<HttpProtocols>(protocols, ignoreCase: true, out var result))
+            {
+                return result;
+            }
+
+            return null;
+        }
+    }
+
+    // "EndpointDefaults": {
+    //    "Protocols": "Http1AndHttp2",
+    // }
+    internal class EndpointDefaults
+    {
+        public HttpProtocols? Protocols { get; set; }
+        public IConfigurationSection ConfigSection { get; set; }
+    }
+
+    // "EndpointName": {
+    //    "Url": "https://*:5463",
+    //    "Protocols": "Http1AndHttp2",
+    //    "Certificate": {
+    //        "Path": "testCert.pfx",
+    //        "Password": "testPassword"
+    //    }
+    // }
+    internal class EndpointConfig
+    {
+        public string Name { get; set; }
+        public string Url { get; set; }
+        public HttpProtocols? Protocols { get; set; }
+        public IConfigurationSection ConfigSection { get; set; }
+        public CertificateConfig Certificate { get; set; }
+    }
+
+    // "CertificateName": {
+    //      "Path": "testCert.pfx",
+    //      "Password": "testPassword"
+    // }
+    internal class CertificateConfig
+    {
+        public CertificateConfig(IConfigurationSection configSection)
+        {
+            ConfigSection = configSection;
+            ConfigSection.Bind(this);
+        }
+
+        public IConfigurationSection ConfigSection { get; }
+
+        // File
+        public bool IsFileCert => !string.IsNullOrEmpty(Path);
+
+        public string Path { get; set; }
+
+        public string Password { get; set; }
+
+        // Cert store
+
+        public bool IsStoreCert => !string.IsNullOrEmpty(Subject);
+
+        public string Subject { get; set; }
+
+        public string Store { get; set; }
+
+        public string Location { get; set; }
+
+        public bool? AllowInvalid { get; set; }
+    }
+}

+ 154 - 0
src/Servers/Kestrel/Core/src/Internal/ConnectionDispatcher.cs

@@ -0,0 +1,154 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.IO.Pipelines;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
+using Microsoft.Extensions.Logging;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
+{
+    public class ConnectionDispatcher : IConnectionDispatcher
+    {
+        private static long _lastConnectionId = long.MinValue;
+
+        private readonly ServiceContext _serviceContext;
+        private readonly ConnectionDelegate _connectionDelegate;
+
+        public ConnectionDispatcher(ServiceContext serviceContext, ConnectionDelegate connectionDelegate)
+        {
+            _serviceContext = serviceContext;
+            _connectionDelegate = connectionDelegate;
+        }
+
+        private IKestrelTrace Log => _serviceContext.Log;
+
+        public Task OnConnection(TransportConnection connection)
+        {
+            // REVIEW: Unfortunately, we still need to use the service context to create the pipes since the settings
+            // for the scheduler and limits are specified here
+            var inputOptions = GetInputPipeOptions(_serviceContext, connection.MemoryPool, connection.InputWriterScheduler);
+            var outputOptions = GetOutputPipeOptions(_serviceContext, connection.MemoryPool, connection.OutputReaderScheduler);
+
+            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);
+
+            // Set the transport and connection id
+            connection.ConnectionId = CorrelationIdGenerator.GetNextId();
+            connection.Transport = pair.Transport;
+
+            // This *must* be set before returning from OnConnection
+            connection.Application = pair.Application;
+
+            return Execute(new KestrelConnection(connection));
+        }
+
+        private async Task Execute(KestrelConnection connection)
+        {
+            var id = Interlocked.Increment(ref _lastConnectionId);
+            var connectionContext = connection.TransportConnection;
+
+            try
+            {
+                _serviceContext.ConnectionManager.AddConnection(id, connection);
+
+                Log.ConnectionStart(connectionContext.ConnectionId);
+                KestrelEventSource.Log.ConnectionStart(connectionContext);
+
+                using (BeginConnectionScope(connectionContext))
+                {
+                    try
+                    {
+                        await _connectionDelegate(connectionContext);
+                    }
+                    catch (Exception ex)
+                    {
+                        Log.LogCritical(0, ex, $"{nameof(ConnectionDispatcher)}.{nameof(Execute)}() {connectionContext.ConnectionId}");
+                    }
+                    finally
+                    {
+                        // Complete the transport PipeReader and PipeWriter after calling into application code
+                        connectionContext.Transport.Input.Complete();
+                        connectionContext.Transport.Output.Complete();
+                    }
+
+                    // Wait for the transport to close
+                    await CancellationTokenAsTask(connectionContext.ConnectionClosed);
+                }
+            }
+            finally
+            {
+                Log.ConnectionStop(connectionContext.ConnectionId);
+                KestrelEventSource.Log.ConnectionStop(connectionContext);
+
+                connection.Complete();
+
+                _serviceContext.ConnectionManager.RemoveConnection(id);
+            }
+        }
+
+        private IDisposable BeginConnectionScope(ConnectionContext connectionContext)
+        {
+            if (Log.IsEnabled(LogLevel.Critical))
+            {
+                return Log.BeginScope(new ConnectionLogScope(connectionContext.ConnectionId));
+            }
+
+            return null;
+        }
+
+        private static Task CancellationTokenAsTask(CancellationToken token)
+        {
+            if (token.IsCancellationRequested)
+            {
+                return Task.CompletedTask;
+            }
+
+            // Transports already dispatch prior to tripping ConnectionClosed
+            // since application code can register to this token.
+            var tcs = new TaskCompletionSource<object>();
+            token.Register(state => ((TaskCompletionSource<object>)state).SetResult(null), tcs);
+            return tcs.Task;
+        }
+
+        // Internal for testing
+        internal static PipeOptions GetInputPipeOptions(ServiceContext serviceContext, MemoryPool<byte> memoryPool, PipeScheduler writerScheduler) => new PipeOptions
+        (
+            pool: memoryPool,
+            readerScheduler: serviceContext.Scheduler,
+            writerScheduler: writerScheduler,
+            pauseWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
+            resumeWriterThreshold: serviceContext.ServerOptions.Limits.MaxRequestBufferSize ?? 0,
+            useSynchronizationContext: false,
+            minimumSegmentSize: KestrelMemoryPool.MinimumSegmentSize
+        );
+
+        internal static PipeOptions GetOutputPipeOptions(ServiceContext serviceContext, MemoryPool<byte> memoryPool, PipeScheduler readerScheduler) => new PipeOptions
+        (
+            pool: memoryPool,
+            readerScheduler: readerScheduler,
+            writerScheduler: serviceContext.Scheduler,
+            pauseWriterThreshold: GetOutputResponseBufferSize(serviceContext),
+            resumeWriterThreshold: GetOutputResponseBufferSize(serviceContext),
+            useSynchronizationContext: false,
+            minimumSegmentSize: KestrelMemoryPool.MinimumSegmentSize
+        );
+
+        private static long GetOutputResponseBufferSize(ServiceContext serviceContext)
+        {
+            var bufferSize = serviceContext.ServerOptions.Limits.MaxResponseBufferSize;
+            if (bufferSize == 0)
+            {
+                // 0 = no buffering so we need to configure the pipe so the writer waits on the reader directly
+                return 1;
+            }
+
+            // null means that we have no back pressure
+            return bufferSize ?? 0;
+        }
+    }
+}

+ 74 - 0
src/Servers/Kestrel/Core/src/Internal/ConnectionLimitMiddleware.cs

@@ -0,0 +1,74 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
+{
+    public class ConnectionLimitMiddleware
+    {
+        private readonly ConnectionDelegate _next;
+        private readonly ResourceCounter _concurrentConnectionCounter;
+        private readonly IKestrelTrace _trace;
+
+        public ConnectionLimitMiddleware(ConnectionDelegate next, long connectionLimit, IKestrelTrace trace)
+            : this(next, ResourceCounter.Quota(connectionLimit), trace)
+        {
+        }
+
+        // For Testing
+        internal ConnectionLimitMiddleware(ConnectionDelegate next, ResourceCounter concurrentConnectionCounter, IKestrelTrace trace)
+        {
+            _next = next;
+            _concurrentConnectionCounter = concurrentConnectionCounter;
+            _trace = trace;
+        }
+
+        public async Task OnConnectionAsync(ConnectionContext connection)
+        {
+            if (!_concurrentConnectionCounter.TryLockOne())
+            {
+                KestrelEventSource.Log.ConnectionRejected(connection.ConnectionId);
+                _trace.ConnectionRejected(connection.ConnectionId);
+                connection.Transport.Input.Complete();
+                connection.Transport.Output.Complete();
+                return;
+            }
+
+            var releasor = new ConnectionReleasor(_concurrentConnectionCounter);
+
+            try
+            {
+                connection.Features.Set<IDecrementConcurrentConnectionCountFeature>(releasor);
+                await _next(connection);
+            }
+            finally
+            {
+                releasor.ReleaseConnection();
+            }
+        }
+
+        private class ConnectionReleasor : IDecrementConcurrentConnectionCountFeature
+        {
+            private readonly ResourceCounter _concurrentConnectionCounter;
+            private bool _connectionReleased;
+
+            public ConnectionReleasor(ResourceCounter normalConnectionCounter)
+            {
+                _concurrentConnectionCounter = normalConnectionCounter;
+            }
+
+            public void ReleaseConnection()
+            {
+                if (!_connectionReleased)
+                {
+                    _connectionReleased = true;
+                    _concurrentConnectionCounter.ReleaseOne();
+                }
+            }
+        }
+    }
+}

+ 63 - 0
src/Servers/Kestrel/Core/src/Internal/ConnectionLogScope.cs

@@ -0,0 +1,63 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
+{
+    public class ConnectionLogScope : IReadOnlyList<KeyValuePair<string, object>>
+    {
+        private readonly string _connectionId;
+
+        private string _cachedToString;
+
+        public ConnectionLogScope(string connectionId)
+        {
+            _connectionId = connectionId;
+        }
+
+        public KeyValuePair<string, object> this[int index]
+        {
+            get
+            {
+                if (index == 0)
+                {
+                    return new KeyValuePair<string, object>("ConnectionId", _connectionId);
+                }
+
+                throw new ArgumentOutOfRangeException(nameof(index));
+            }
+        }
+
+        public int Count => 1;
+
+        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
+        {
+            for (int i = 0; i < Count; ++i)
+            {
+                yield return this[i];
+            }
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        public override string ToString()
+        {
+            if (_cachedToString == null)
+            {
+                _cachedToString = string.Format(
+                    CultureInfo.InvariantCulture,
+                    "ConnectionId:{0}",
+                    _connectionId);
+            }
+
+            return _cachedToString;
+        }
+    }
+}

+ 39 - 0
src/Servers/Kestrel/Core/src/Internal/DuplexPipe.cs

@@ -0,0 +1,39 @@
+namespace System.IO.Pipelines
+{
+    internal class DuplexPipe : IDuplexPipe
+    {
+        public DuplexPipe(PipeReader reader, PipeWriter writer)
+        {
+            Input = reader;
+            Output = writer;
+        }
+
+        public PipeReader Input { get; }
+
+        public PipeWriter Output { get; }
+
+        public static DuplexPipePair CreateConnectionPair(PipeOptions inputOptions, PipeOptions outputOptions)
+        {
+            var input = new Pipe(inputOptions);
+            var output = new Pipe(outputOptions);
+
+            var transportToApplication = new DuplexPipe(output.Reader, input.Writer);
+            var applicationToTransport = new DuplexPipe(input.Reader, output.Writer);
+
+            return new DuplexPipePair(applicationToTransport, transportToApplication);
+        }
+
+        // This class exists to work around issues with value tuple on .NET Framework
+        public readonly struct DuplexPipePair
+        {
+            public IDuplexPipe Transport { get; }
+            public IDuplexPipe Application { get; }
+
+            public DuplexPipePair(IDuplexPipe transport, IDuplexPipe application)
+            {
+                Transport = transport;
+                Application = application;
+            }
+        }
+    }
+}

+ 63 - 0
src/Servers/Kestrel/Core/src/Internal/Http/ChunkWriter.cs

@@ -0,0 +1,63 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.IO.Pipelines;
+using System.Text;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    internal static class ChunkWriter
+    {
+        private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
+        private static readonly byte[] _hex = Encoding.ASCII.GetBytes("0123456789abcdef");
+
+        private static ArraySegment<byte> CreateAsciiByteArraySegment(string text)
+        {
+            var bytes = Encoding.ASCII.GetBytes(text);
+            return new ArraySegment<byte>(bytes);
+        }
+
+        public static ArraySegment<byte> BeginChunkBytes(int dataCount)
+        {
+            var bytes = new byte[10]
+            {
+                _hex[((dataCount >> 0x1c) & 0x0f)],
+                _hex[((dataCount >> 0x18) & 0x0f)],
+                _hex[((dataCount >> 0x14) & 0x0f)],
+                _hex[((dataCount >> 0x10) & 0x0f)],
+                _hex[((dataCount >> 0x0c) & 0x0f)],
+                _hex[((dataCount >> 0x08) & 0x0f)],
+                _hex[((dataCount >> 0x04) & 0x0f)],
+                _hex[((dataCount >> 0x00) & 0x0f)],
+                (byte)'\r',
+                (byte)'\n',
+            };
+
+            // Determine the most-significant non-zero nibble
+            int total, shift;
+            total = (dataCount > 0xffff) ? 0x10 : 0x00;
+            dataCount >>= total;
+            shift = (dataCount > 0x00ff) ? 0x08 : 0x00;
+            dataCount >>= shift;
+            total |= shift;
+            total |= (dataCount > 0x000f) ? 0x04 : 0x00;
+
+            var offset = 7 - (total >> 2);
+            return new ArraySegment<byte>(bytes, offset, 10 - offset);
+        }
+
+        internal static int WriteBeginChunkBytes(ref BufferWriter<PipeWriter> start, int dataCount)
+        {
+            var chunkSegment = BeginChunkBytes(dataCount);
+            start.Write(new ReadOnlySpan<byte>(chunkSegment.Array, chunkSegment.Offset, chunkSegment.Count));
+            return chunkSegment.Count;
+        }
+
+        internal static void WriteEndChunkBytes(ref BufferWriter<PipeWriter> start)
+        {
+            start.Write(new ReadOnlySpan<byte>(_endChunkBytes.Array, _endChunkBytes.Offset, _endChunkBytes.Count));
+        }
+    }
+}

+ 16 - 0
src/Servers/Kestrel/Core/src/Internal/Http/ConnectionOptions.cs

@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    [Flags]
+    public enum ConnectionOptions
+    {
+        None = 0,
+        Close = 1,
+        KeepAlive = 2,
+        Upgrade = 4
+    }
+}

+ 59 - 0
src/Servers/Kestrel/Core/src/Internal/Http/DateHeaderValueManager.cs

@@ -0,0 +1,59 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Text;
+using System.Threading;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.Net.Http.Headers;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    /// <summary>
+    /// Manages the generation of the date header value.
+    /// </summary>
+    public class DateHeaderValueManager : IHeartbeatHandler
+    {
+        private static readonly byte[] _datePreambleBytes = Encoding.ASCII.GetBytes("\r\nDate: ");
+
+        private DateHeaderValues _dateValues;
+
+        /// <summary>
+        /// Returns a value representing the current server date/time for use in the HTTP "Date" response header
+        /// in accordance with http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18
+        /// </summary>
+        /// <returns>The value in string and byte[] format.</returns>
+        public DateHeaderValues GetDateHeaderValues() => _dateValues;
+
+        // Called by the Timer (background) thread
+        public void OnHeartbeat(DateTimeOffset now)
+        {
+            SetDateValues(now);
+        }
+
+        /// <summary>
+        /// Sets date values from a provided ticks value
+        /// </summary>
+        /// <param name="value">A DateTimeOffset value</param>
+        private void SetDateValues(DateTimeOffset value)
+        {
+            var dateValue = HeaderUtilities.FormatDate(value);
+            var dateBytes = new byte[_datePreambleBytes.Length + dateValue.Length];
+            Buffer.BlockCopy(_datePreambleBytes, 0, dateBytes, 0, _datePreambleBytes.Length);
+            Encoding.ASCII.GetBytes(dateValue, 0, dateValue.Length, dateBytes, _datePreambleBytes.Length);
+
+            var dateValues = new DateHeaderValues
+            {
+                Bytes = dateBytes,
+                String = dateValue
+            };
+            Volatile.Write(ref _dateValues, dateValues);
+        }
+
+        public class DateHeaderValues
+        {
+            public byte[] Bytes;
+            public string String;
+        }
+    }
+}

+ 29 - 0
src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.FeatureCollection.cs

@@ -0,0 +1,29 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public partial class Http1Connection : IHttpMinRequestBodyDataRateFeature,
+                                           IHttpMinResponseDataRateFeature
+    {
+        MinDataRate IHttpMinRequestBodyDataRateFeature.MinDataRate
+        {
+            get => MinRequestBodyDataRate;
+            set => MinRequestBodyDataRate = value;
+        }
+
+        MinDataRate IHttpMinResponseDataRateFeature.MinDataRate
+        {
+            get => MinResponseDataRate;
+            set => MinResponseDataRate = value;
+        }
+    }
+}

+ 545 - 0
src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs

@@ -0,0 +1,545 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO.Pipelines;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public partial class Http1Connection : HttpProtocol, IRequestProcessor
+    {
+        private const byte ByteAsterisk = (byte)'*';
+        private const byte ByteForwardSlash = (byte)'/';
+        private const string Asterisk = "*";
+
+        private readonly HttpConnectionContext _context;
+        private readonly IHttpParser<Http1ParsingHandler> _parser;
+        private readonly Http1OutputProducer _http1Output;
+        protected readonly long _keepAliveTicks;
+        private readonly long _requestHeadersTimeoutTicks;
+
+        private int _requestAborted;
+        private volatile bool _requestTimedOut;
+        private uint _requestCount;
+
+        private HttpRequestTarget _requestTargetForm = HttpRequestTarget.Unknown;
+        private Uri _absoluteRequestTarget;
+
+        private int _remainingRequestHeadersBytesAllowed;
+
+        public Http1Connection(HttpConnectionContext context)
+            : base(context)
+        {
+            _context = context;
+            _parser = ServiceContext.HttpParser;
+            _keepAliveTicks = ServerOptions.Limits.KeepAliveTimeout.Ticks;
+            _requestHeadersTimeoutTicks = ServerOptions.Limits.RequestHeadersTimeout.Ticks;
+
+            RequestBodyPipe = CreateRequestBodyPipe();
+
+            _http1Output = new Http1OutputProducer(
+                _context.Transport.Output,
+                _context.ConnectionId,
+                _context.ConnectionContext,
+                _context.ServiceContext.Log,
+                _context.TimeoutControl,
+                this);
+
+            Output = _http1Output;
+        }
+
+        public PipeReader Input => _context.Transport.Input;
+
+        public bool RequestTimedOut => _requestTimedOut;
+
+        public MinDataRate MinRequestBodyDataRate { get; set; }
+
+        public MinDataRate MinResponseDataRate { get; set; }
+
+        protected override void OnRequestProcessingEnded()
+        {
+            Input.Complete();
+
+            TimeoutControl.StartDrainTimeout(MinResponseDataRate, ServerOptions.Limits.MaxResponseBufferSize);
+
+            // Prevent RequestAborted from firing. Free up unneeded feature references.
+            Reset();
+
+            _http1Output.Dispose();
+        }
+
+        public void OnInputOrOutputCompleted()
+        {
+            _http1Output.Abort(new ConnectionAbortedException(CoreStrings.ConnectionAbortedByClient));
+            AbortRequest();
+        }
+
+        /// <summary>
+        /// Immediately kill the connection and poison the request body stream with an error.
+        /// </summary>
+        public void Abort(ConnectionAbortedException abortReason)
+        {
+            if (Interlocked.Exchange(ref _requestAborted, 1) != 0)
+            {
+                return;
+            }
+
+            _http1Output.Abort(abortReason);
+
+            AbortRequest();
+
+            PoisonRequestBodyStream(abortReason);
+        }
+
+        protected override void ApplicationAbort()
+        {
+            Log.ApplicationAbortedConnection(ConnectionId, TraceIdentifier);
+            Abort(new ConnectionAbortedException(CoreStrings.ConnectionAbortedByApplication));
+        }
+
+        /// <summary>
+        /// Stops the request processing loop between requests.
+        /// Called on all active connections when the server wants to initiate a shutdown
+        /// and after a keep-alive timeout.
+        /// </summary>
+        public void StopProcessingNextRequest()
+        {
+            _keepAlive = false;
+            Input.CancelPendingRead();
+        }
+
+        public void SendTimeoutResponse()
+        {
+            _requestTimedOut = true;
+            Input.CancelPendingRead();
+        }
+
+        public void HandleRequestHeadersTimeout()
+            => SendTimeoutResponse();
+
+        public void HandleReadDataRateTimeout()
+        {
+            Log.RequestBodyMinimumDataRateNotSatisfied(ConnectionId, TraceIdentifier, MinRequestBodyDataRate.BytesPerSecond);
+            SendTimeoutResponse();
+        }
+
+        public void ParseRequest(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+        {
+            consumed = buffer.Start;
+            examined = buffer.End;
+
+            switch (_requestProcessingStatus)
+            {
+                case RequestProcessingStatus.RequestPending:
+                    if (buffer.IsEmpty)
+                    {
+                        break;
+                    }
+
+                    TimeoutControl.ResetTimeout(_requestHeadersTimeoutTicks, TimeoutReason.RequestHeaders);
+
+                    _requestProcessingStatus = RequestProcessingStatus.ParsingRequestLine;
+                    goto case RequestProcessingStatus.ParsingRequestLine;
+                case RequestProcessingStatus.ParsingRequestLine:
+                    if (TakeStartLine(buffer, out consumed, out examined))
+                    {
+                        buffer = buffer.Slice(consumed, buffer.End);
+
+                        _requestProcessingStatus = RequestProcessingStatus.ParsingHeaders;
+                        goto case RequestProcessingStatus.ParsingHeaders;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case RequestProcessingStatus.ParsingHeaders:
+                    if (TakeMessageHeaders(buffer, out consumed, out examined))
+                    {
+                        _requestProcessingStatus = RequestProcessingStatus.AppStarted;
+                    }
+                    break;
+            }
+        }
+
+        public bool TakeStartLine(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+        {
+            var overLength = false;
+            if (buffer.Length >= ServerOptions.Limits.MaxRequestLineSize)
+            {
+                buffer = buffer.Slice(buffer.Start, ServerOptions.Limits.MaxRequestLineSize);
+                overLength = true;
+            }
+
+            var result = _parser.ParseRequestLine(new Http1ParsingHandler(this), buffer, out consumed, out examined);
+            if (!result && overLength)
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.RequestLineTooLong);
+            }
+
+            return result;
+        }
+
+        public bool TakeMessageHeaders(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+        {
+            // Make sure the buffer is limited
+            bool overLength = false;
+            if (buffer.Length >= _remainingRequestHeadersBytesAllowed)
+            {
+                buffer = buffer.Slice(buffer.Start, _remainingRequestHeadersBytesAllowed);
+
+                // If we sliced it means the current buffer bigger than what we're
+                // allowed to look at
+                overLength = true;
+            }
+
+            var result = _parser.ParseHeaders(new Http1ParsingHandler(this), buffer, out consumed, out examined, out var consumedBytes);
+            _remainingRequestHeadersBytesAllowed -= consumedBytes;
+
+            if (!result && overLength)
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize);
+            }
+            if (result)
+            {
+                TimeoutControl.CancelTimeout();
+            }
+
+            return result;
+        }
+
+        public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
+        {
+            Debug.Assert(target.Length != 0, "Request target must be non-zero length");
+
+            var ch = target[0];
+            if (ch == ByteForwardSlash)
+            {
+                // origin-form.
+                // The most common form of request-target.
+                // https://tools.ietf.org/html/rfc7230#section-5.3.1
+                OnOriginFormTarget(method, version, target, path, query, customMethod, pathEncoded);
+            }
+            else if (ch == ByteAsterisk && target.Length == 1)
+            {
+                OnAsteriskFormTarget(method);
+            }
+            else if (target.GetKnownHttpScheme(out var scheme))
+            {
+                OnAbsoluteFormTarget(target, query);
+            }
+            else
+            {
+                // Assume anything else is considered authority form.
+                // FYI: this should be an edge case. This should only happen when
+                // a client mistakenly thinks this server is a proxy server.
+                OnAuthorityFormTarget(method, target);
+            }
+
+            Method = method;
+            if (method == HttpMethod.Custom)
+            {
+                _methodText = customMethod.GetAsciiStringNonNullCharacters();
+            }
+
+            _httpVersion = version;
+
+            Debug.Assert(RawTarget != null, "RawTarget was not set");
+            Debug.Assert(((IHttpRequestFeature)this).Method != null, "Method was not set");
+            Debug.Assert(Path != null, "Path was not set");
+            Debug.Assert(QueryString != null, "QueryString was not set");
+            Debug.Assert(HttpVersion != null, "HttpVersion was not set");
+        }
+
+        // Compare with Http2Stream.TryValidatePseudoHeaders
+        private void OnOriginFormTarget(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
+        {
+            Debug.Assert(target[0] == ByteForwardSlash, "Should only be called when path starts with /");
+
+            _requestTargetForm = HttpRequestTarget.OriginForm;
+
+            // 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
+            {
+                // Read raw target before mutating memory.
+                RawTarget = target.GetAsciiStringNonNullCharacters();
+                QueryString = query.GetAsciiStringNonNullCharacters();
+                Path = PathNormalizer.DecodePath(path, pathEncoded, RawTarget, query.Length);
+            }
+            catch (InvalidOperationException)
+            {
+                ThrowRequestTargetRejected(target);
+            }
+        }
+
+        private void OnAuthorityFormTarget(HttpMethod method, Span<byte> target)
+        {
+            _requestTargetForm = HttpRequestTarget.AuthorityForm;
+
+            // This is not complete validation. It is just a quick scan for invalid characters
+            // but doesn't check that the target fully matches the URI spec.
+            if (HttpCharacters.ContainsInvalidAuthorityChar(target))
+            {
+                ThrowRequestTargetRejected(target);
+            }
+
+            // The authority-form of request-target is only used for CONNECT
+            // requests (https://tools.ietf.org/html/rfc7231#section-4.3.6).
+            if (method != HttpMethod.Connect)
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.ConnectMethodRequired);
+            }
+
+            // When making a CONNECT request to establish a tunnel through one or
+            // more proxies, a client MUST send only the target URI's authority
+            // component (excluding any userinfo and its "@" delimiter) as the
+            // request-target.For example,
+            //
+            //  CONNECT www.example.com:80 HTTP/1.1
+            //
+            // Allowed characters in the 'host + port' section of authority.
+            // See https://tools.ietf.org/html/rfc3986#section-3.2
+            RawTarget = target.GetAsciiStringNonNullCharacters();
+            Path = string.Empty;
+            QueryString = string.Empty;
+        }
+
+        private void OnAsteriskFormTarget(HttpMethod method)
+        {
+            _requestTargetForm = HttpRequestTarget.AsteriskForm;
+
+            // The asterisk-form of request-target is only used for a server-wide
+            // OPTIONS request (https://tools.ietf.org/html/rfc7231#section-4.3.7).
+            if (method != HttpMethod.Options)
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.OptionsMethodRequired);
+            }
+
+            RawTarget = Asterisk;
+            Path = string.Empty;
+            QueryString = string.Empty;
+        }
+
+        private void OnAbsoluteFormTarget(Span<byte> target, Span<byte> query)
+        {
+            _requestTargetForm = HttpRequestTarget.AbsoluteForm;
+
+            // absolute-form
+            // https://tools.ietf.org/html/rfc7230#section-5.3.2
+
+            // This code should be the edge-case.
+
+            // From the spec:
+            //    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))
+            {
+                ThrowRequestTargetRejected(target);
+            }
+
+            _absoluteRequestTarget = uri;
+            Path = uri.LocalPath;
+            // don't use uri.Query because we need the unescaped version
+            QueryString = query.GetAsciiStringNonNullCharacters();
+        }
+
+        internal void EnsureHostHeaderExists()
+        {
+            // https://tools.ietf.org/html/rfc7230#section-5.4
+            // A server MUST respond with a 400 (Bad Request) status code to any
+            // HTTP/1.1 request message that lacks a Host header field and to any
+            // request message that contains more than one Host header field or a
+            // Host header field with an invalid field-value.
+
+            var hostCount = HttpRequestHeaders.HostCount;
+            var hostText = HttpRequestHeaders.HeaderHost.ToString();
+            if (hostCount <= 0)
+            {
+                if (_httpVersion == Http.HttpVersion.Http10)
+                {
+                    return;
+                }
+                BadHttpRequestException.Throw(RequestRejectionReason.MissingHostHeader);
+            }
+            else if (hostCount > 1)
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.MultipleHostHeaders);
+            }
+            else if (_requestTargetForm != HttpRequestTarget.OriginForm)
+            {
+                // Tail call
+                ValidateNonOriginHostHeader(hostText);
+            }
+            else if (!HttpUtilities.IsHostHeaderValid(hostText))
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
+            }
+        }
+
+        private void ValidateNonOriginHostHeader(string hostText)
+        {
+            if (_requestTargetForm == HttpRequestTarget.AuthorityForm)
+            {
+                if (hostText != RawTarget)
+                {
+                    BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
+                }
+            }
+            else if (_requestTargetForm == HttpRequestTarget.AbsoluteForm)
+            {
+                // If the target URI includes an authority component, then a
+                // client MUST send a field - value for Host that is identical to that
+                // authority component, excluding any userinfo subcomponent and its "@"
+                // delimiter.
+
+                // System.Uri doesn't not tell us if the port was in the original string or not.
+                // When IsDefaultPort = true, we will allow Host: with or without the default port
+                if (hostText != _absoluteRequestTarget.Authority)
+                {
+                    if (!_absoluteRequestTarget.IsDefaultPort
+                        || hostText != _absoluteRequestTarget.Authority + ":" + _absoluteRequestTarget.Port.ToString(CultureInfo.InvariantCulture))
+                    {
+                        BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
+                    }
+                }
+            }
+
+            if (!HttpUtilities.IsHostHeaderValid(hostText))
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.InvalidHostHeader, hostText);
+            }
+        }
+
+        protected override void OnReset()
+        {
+            ResetHttp1Features();
+
+            _requestTimedOut = false;
+            _requestTargetForm = HttpRequestTarget.Unknown;
+            _absoluteRequestTarget = null;
+            _remainingRequestHeadersBytesAllowed = ServerOptions.Limits.MaxRequestHeadersTotalSize + 2;
+            _requestCount++;
+
+            MinRequestBodyDataRate = ServerOptions.Limits.MinRequestBodyDataRate;
+            MinResponseDataRate = ServerOptions.Limits.MinResponseDataRate;
+        }
+
+        protected override void OnRequestProcessingEnding()
+        {
+        }
+
+        protected override string CreateRequestId()
+            => StringUtilities.ConcatAsHexSuffix(ConnectionId, ':', _requestCount);
+
+        protected override MessageBody CreateMessageBody()
+            => Http1MessageBody.For(_httpVersion, HttpRequestHeaders, this);
+
+        protected override void BeginRequestProcessing()
+        {
+            // Reset the features and timeout.
+            Reset();
+            TimeoutControl.SetTimeout(_keepAliveTicks, TimeoutReason.KeepAlive);
+        }
+
+        protected override bool BeginRead(out ValueTask<ReadResult> awaitable)
+        {
+            awaitable = Input.ReadAsync();
+            return true;
+        }
+
+        protected override bool TryParseRequest(ReadResult result, out bool endConnection)
+        {
+            var examined = result.Buffer.End;
+            var consumed = result.Buffer.End;
+
+            try
+            {
+                ParseRequest(result.Buffer, out consumed, out examined);
+            }
+            catch (InvalidOperationException)
+            {
+                if (_requestProcessingStatus == RequestProcessingStatus.ParsingHeaders)
+                {
+                    BadHttpRequestException.Throw(RequestRejectionReason.MalformedRequestInvalidHeaders);
+                }
+                throw;
+            }
+            finally
+            {
+                Input.AdvanceTo(consumed, examined);
+            }
+
+            if (result.IsCompleted)
+            {
+                switch (_requestProcessingStatus)
+                {
+                    case RequestProcessingStatus.RequestPending:
+                        endConnection = true;
+                        return true;
+                    case RequestProcessingStatus.ParsingRequestLine:
+                        BadHttpRequestException.Throw(RequestRejectionReason.InvalidRequestLine);
+                        break;
+                    case RequestProcessingStatus.ParsingHeaders:
+                        BadHttpRequestException.Throw(RequestRejectionReason.MalformedRequestInvalidHeaders);
+                        break;
+                }
+            }
+            else if (!_keepAlive && _requestProcessingStatus == RequestProcessingStatus.RequestPending)
+            {
+                // Stop the request processing loop if the server is shutting down or there was a keep-alive timeout
+                // and there is no ongoing request.
+                endConnection = true;
+                return true;
+            }
+            else if (RequestTimedOut)
+            {
+                // In this case, there is an ongoing request but the start line/header parsing has timed out, so send
+                // a 408 response.
+                BadHttpRequestException.Throw(RequestRejectionReason.RequestHeadersTimeout);
+            }
+
+            endConnection = false;
+            if (_requestProcessingStatus == RequestProcessingStatus.AppStarted)
+            {
+                EnsureHostHeaderExists();
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        void IRequestProcessor.Tick(DateTimeOffset now) { }
+
+        private Pipe CreateRequestBodyPipe()
+            => new Pipe(new PipeOptions
+            (
+                pool: _context.MemoryPool,
+                readerScheduler: ServiceContext.Scheduler,
+                writerScheduler: PipeScheduler.Inline,
+                pauseWriterThreshold: 1,
+                resumeWriterThreshold: 1,
+                useSynchronizationContext: false,
+                minimumSegmentSize: KestrelMemoryPool.MinimumSegmentSize
+            ));
+    }
+}

+ 678 - 0
src/Servers/Kestrel/Core/src/Internal/Http/Http1MessageBody.cs

@@ -0,0 +1,678 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.IO;
+using System.IO.Pipelines;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public abstract class Http1MessageBody : MessageBody
+    {
+        private readonly Http1Connection _context;
+
+        private volatile bool _canceled;
+        private Task _pumpTask;
+
+        protected Http1MessageBody(Http1Connection context)
+            : base(context, context.MinRequestBodyDataRate)
+        {
+            _context = context;
+        }
+
+        private async Task PumpAsync()
+        {
+            Exception error = null;
+
+            try
+            {
+                var awaitable = _context.Input.ReadAsync();
+
+                if (!awaitable.IsCompleted)
+                {
+                    TryProduceContinue();
+                }
+
+                while (true)
+                {
+                    var result = await awaitable;
+
+                    if (_context.RequestTimedOut)
+                    {
+                        BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTimeout);
+                    }
+
+                    var readableBuffer = result.Buffer;
+                    var consumed = readableBuffer.Start;
+                    var examined = readableBuffer.Start;
+
+                    try
+                    {
+                        if (_canceled)
+                        {
+                            break;
+                        }
+
+                        if (!readableBuffer.IsEmpty)
+                        {
+                            bool done;
+                            done = Read(readableBuffer, _context.RequestBodyPipe.Writer, out consumed, out examined);
+
+                            await _context.RequestBodyPipe.Writer.FlushAsync();
+
+                            if (done)
+                            {
+                                break;
+                            }
+                        }
+
+                        // Read() will have already have greedily consumed the entire request body if able.
+                        if (result.IsCompleted)
+                        {
+                            // OnInputOrOutputCompleted() is an idempotent method that closes the connection. Sometimes
+                            // input completion is observed here before the Input.OnWriterCompleted() callback is fired,
+                            // so we call OnInputOrOutputCompleted() now to prevent a race in our tests where a 400
+                            // response is written after observing the unexpected end of request content instead of just
+                            // closing the connection without a response as expected.
+                            _context.OnInputOrOutputCompleted();
+
+                            // Treat any FIN from an upgraded request as expected.
+                            // It's up to higher-level consumer (i.e. WebSocket middleware) to determine
+                            // if the end is actually expected based on higher-level framing.
+                            if (RequestUpgrade)
+                            {
+                                break;
+                            }
+
+                            BadHttpRequestException.Throw(RequestRejectionReason.UnexpectedEndOfRequestContent);
+                        }
+                    }
+                    finally
+                    {
+                        _context.Input.AdvanceTo(consumed, examined);
+                    }
+
+                    awaitable = _context.Input.ReadAsync();
+                }
+            }
+            catch (Exception ex)
+            {
+                error = ex;
+            }
+            finally
+            {
+                _context.RequestBodyPipe.Writer.Complete(error);
+            }
+        }
+
+        protected override Task OnStopAsync()
+        {
+            if (!_context.HasStartedConsumingRequestBody)
+            {
+                return Task.CompletedTask;
+            }
+
+            // PumpTask catches all Exceptions internally.
+            if (_pumpTask.IsCompleted)
+            {
+                // At this point both the request body pipe reader and writer should be completed.
+                _context.RequestBodyPipe.Reset();
+                return Task.CompletedTask;
+            }
+
+            return StopAsyncAwaited();
+        }
+
+        private async Task StopAsyncAwaited()
+        {
+            _canceled = true;
+            _context.Input.CancelPendingRead();
+            await _pumpTask;
+
+            // At this point both the request body pipe reader and writer should be completed.
+            _context.RequestBodyPipe.Reset();
+        }
+
+        protected override Task OnConsumeAsync()
+        {
+            try
+            {
+                if (_context.RequestBodyPipe.Reader.TryRead(out var readResult))
+                {
+                    _context.RequestBodyPipe.Reader.AdvanceTo(readResult.Buffer.End);
+
+                    if (readResult.IsCompleted)
+                    {
+                        return Task.CompletedTask;
+                    }
+                }
+            }
+            catch (OperationCanceledException)
+            {
+                // TryRead can throw OperationCanceledException https://github.com/dotnet/corefx/issues/32029
+                // because of buggy logic, this works around that for now
+            }
+            catch (BadHttpRequestException ex)
+            {
+                // At this point, the response has already been written, so this won't result in a 4XX response;
+                // however, we still need to stop the request processing loop and log.
+                _context.SetBadRequestState(ex);
+                return Task.CompletedTask;
+            }
+
+            return OnConsumeAsyncAwaited();
+        }
+
+        private async Task OnConsumeAsyncAwaited()
+        {
+            Log.RequestBodyNotEntirelyRead(_context.ConnectionIdFeature, _context.TraceIdentifier);
+
+            _context.TimeoutControl.SetTimeout(Constants.RequestBodyDrainTimeout.Ticks, TimeoutReason.RequestBodyDrain);
+
+            try
+            {
+                ReadResult result;
+                do
+                {
+                    result = await _context.RequestBodyPipe.Reader.ReadAsync();
+                    _context.RequestBodyPipe.Reader.AdvanceTo(result.Buffer.End);
+                } while (!result.IsCompleted);
+            }
+            catch (BadHttpRequestException ex)
+            {
+                _context.SetBadRequestState(ex);
+            }
+            catch (ConnectionAbortedException)
+            {
+                Log.RequestBodyDrainTimedOut(_context.ConnectionIdFeature, _context.TraceIdentifier);
+            }
+            finally
+            {
+                _context.TimeoutControl.CancelTimeout();
+            }
+        }
+
+        protected void Copy(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer)
+        {
+            if (readableBuffer.IsSingleSegment)
+            {
+                writableBuffer.Write(readableBuffer.First.Span);
+            }
+            else
+            {
+                foreach (var memory in readableBuffer)
+                {
+                    writableBuffer.Write(memory.Span);
+                }
+            }
+        }
+
+        protected override void OnReadStarted()
+        {
+            _pumpTask = PumpAsync();
+        }
+
+        protected virtual bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
+        {
+            throw new NotImplementedException();
+        }
+
+        public static MessageBody For(
+            HttpVersion httpVersion,
+            HttpRequestHeaders headers,
+            Http1Connection context)
+        {
+            // see also http://tools.ietf.org/html/rfc2616#section-4.4
+            var keepAlive = httpVersion != HttpVersion.Http10;
+
+            var upgrade = false;
+            if (headers.HasConnection)
+            {
+                var connectionOptions = HttpHeaders.ParseConnection(headers.HeaderConnection);
+
+                upgrade = (connectionOptions & ConnectionOptions.Upgrade) == ConnectionOptions.Upgrade;
+                keepAlive = (connectionOptions & ConnectionOptions.KeepAlive) == ConnectionOptions.KeepAlive;
+            }
+
+            if (upgrade)
+            {
+                if (headers.HeaderTransferEncoding.Count > 0 || (headers.ContentLength.HasValue && headers.ContentLength.Value != 0))
+                {
+                    BadHttpRequestException.Throw(RequestRejectionReason.UpgradeRequestCannotHavePayload);
+                }
+
+                return new ForUpgrade(context);
+            }
+
+            if (headers.HasTransferEncoding)
+            {
+                var transferEncoding = headers.HeaderTransferEncoding;
+                var transferCoding = HttpHeaders.GetFinalTransferCoding(transferEncoding);
+
+                // https://tools.ietf.org/html/rfc7230#section-3.3.3
+                // If a Transfer-Encoding header field
+                // is present in a request and the chunked transfer coding is not
+                // the final encoding, the message body length cannot be determined
+                // reliably; the server MUST respond with the 400 (Bad Request)
+                // status code and then close the connection.
+                if (transferCoding != TransferCoding.Chunked)
+                {
+                    BadHttpRequestException.Throw(RequestRejectionReason.FinalTransferCodingNotChunked, in transferEncoding);
+                }
+
+                return new ForChunkedEncoding(keepAlive, context);
+            }
+
+            if (headers.ContentLength.HasValue)
+            {
+                var contentLength = headers.ContentLength.Value;
+
+                if (contentLength == 0)
+                {
+                    return keepAlive ? MessageBody.ZeroContentLengthKeepAlive : MessageBody.ZeroContentLengthClose;
+                }
+
+                return new ForContentLength(keepAlive, contentLength, context);
+            }
+
+            // Avoid slowing down most common case
+            if (!object.ReferenceEquals(context.Method, HttpMethods.Get))
+            {
+                // If we got here, request contains no Content-Length or Transfer-Encoding header.
+                // Reject with 411 Length Required.
+                if (context.Method == HttpMethod.Post || context.Method == HttpMethod.Put)
+                {
+                    var requestRejectionReason = httpVersion == HttpVersion.Http11 ? RequestRejectionReason.LengthRequired : RequestRejectionReason.LengthRequiredHttp10;
+                    BadHttpRequestException.Throw(requestRejectionReason, context.Method);
+                }
+            }
+
+            return keepAlive ? MessageBody.ZeroContentLengthKeepAlive : MessageBody.ZeroContentLengthClose;
+        }
+
+        private class ForUpgrade : Http1MessageBody
+        {
+            public ForUpgrade(Http1Connection context)
+                : base(context)
+            {
+                RequestUpgrade = true;
+            }
+
+            public override bool IsEmpty => true;
+
+            protected override bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                Copy(readableBuffer, writableBuffer);
+                consumed = readableBuffer.End;
+                examined = readableBuffer.End;
+                return false;
+            }
+        }
+
+        private class ForContentLength : Http1MessageBody
+        {
+            private readonly long _contentLength;
+            private long _inputLength;
+
+            public ForContentLength(bool keepAlive, long contentLength, Http1Connection context)
+                : base(context)
+            {
+                RequestKeepAlive = keepAlive;
+                _contentLength = contentLength;
+                _inputLength = _contentLength;
+            }
+
+            protected override bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                if (_inputLength == 0)
+                {
+                    throw new InvalidOperationException("Attempted to read from completed Content-Length request body.");
+                }
+
+                var actual = (int)Math.Min(readableBuffer.Length, _inputLength);
+                _inputLength -= actual;
+
+                consumed = readableBuffer.GetPosition(actual);
+                examined = consumed;
+
+                Copy(readableBuffer.Slice(0, actual), writableBuffer);
+
+                return _inputLength == 0;
+            }
+
+            protected override void OnReadStarting()
+            {
+                if (_contentLength > _context.MaxRequestBodySize)
+                {
+                    BadHttpRequestException.Throw(RequestRejectionReason.RequestBodyTooLarge);
+                }
+            }
+        }
+
+        /// <summary>
+        ///   http://tools.ietf.org/html/rfc2616#section-3.6.1
+        /// </summary>
+        private class ForChunkedEncoding : Http1MessageBody
+        {
+            // byte consts don't have a data type annotation so we pre-cast it
+            private const byte ByteCR = (byte)'\r';
+            // "7FFFFFFF\r\n" is the largest chunk size that could be returned as an int.
+            private const int MaxChunkPrefixBytes = 10;
+
+            private long _inputLength;
+
+            private Mode _mode = Mode.Prefix;
+
+            public ForChunkedEncoding(bool keepAlive, Http1Connection context)
+                : base(context)
+            {
+                RequestKeepAlive = keepAlive;
+            }
+
+            protected override bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                consumed = default(SequencePosition);
+                examined = default(SequencePosition);
+
+                while (_mode < Mode.Trailer)
+                {
+                    if (_mode == Mode.Prefix)
+                    {
+                        ParseChunkedPrefix(readableBuffer, out consumed, out examined);
+
+                        if (_mode == Mode.Prefix)
+                        {
+                            return false;
+                        }
+
+                        readableBuffer = readableBuffer.Slice(consumed);
+                    }
+
+                    if (_mode == Mode.Extension)
+                    {
+                        ParseExtension(readableBuffer, out consumed, out examined);
+
+                        if (_mode == Mode.Extension)
+                        {
+                            return false;
+                        }
+
+                        readableBuffer = readableBuffer.Slice(consumed);
+                    }
+
+                    if (_mode == Mode.Data)
+                    {
+                        ReadChunkedData(readableBuffer, writableBuffer, out consumed, out examined);
+
+                        if (_mode == Mode.Data)
+                        {
+                            return false;
+                        }
+
+                        readableBuffer = readableBuffer.Slice(consumed);
+                    }
+
+                    if (_mode == Mode.Suffix)
+                    {
+                        ParseChunkedSuffix(readableBuffer, out consumed, out examined);
+
+                        if (_mode == Mode.Suffix)
+                        {
+                            return false;
+                        }
+
+                        readableBuffer = readableBuffer.Slice(consumed);
+                    }
+                }
+
+                // Chunks finished, parse trailers
+                if (_mode == Mode.Trailer)
+                {
+                    ParseChunkedTrailer(readableBuffer, out consumed, out examined);
+
+                    if (_mode == Mode.Trailer)
+                    {
+                        return false;
+                    }
+
+                    readableBuffer = readableBuffer.Slice(consumed);
+                }
+
+                // _consumedBytes aren't tracked for trailer headers, since headers have separate limits.
+                if (_mode == Mode.TrailerHeaders)
+                {
+                    if (_context.TakeMessageHeaders(readableBuffer, out consumed, out examined))
+                    {
+                        _mode = Mode.Complete;
+                    }
+                }
+
+                return _mode == Mode.Complete;
+            }
+
+            private void ParseChunkedPrefix(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                consumed = buffer.Start;
+                examined = buffer.Start;
+                var reader = new BufferReader(buffer);
+                var ch1 = reader.Read();
+                var ch2 = reader.Read();
+
+                if (ch1 == -1 || ch2 == -1)
+                {
+                    examined = reader.Position;
+                    return;
+                }
+
+                var chunkSize = CalculateChunkSize(ch1, 0);
+                ch1 = ch2;
+
+                while (reader.ConsumedBytes < MaxChunkPrefixBytes)
+                {
+                    if (ch1 == ';')
+                    {
+                        consumed = reader.Position;
+                        examined = reader.Position;
+
+                        AddAndCheckConsumedBytes(reader.ConsumedBytes);
+                        _inputLength = chunkSize;
+                        _mode = Mode.Extension;
+                        return;
+                    }
+
+                    ch2 = reader.Read();
+                    if (ch2 == -1)
+                    {
+                        examined = reader.Position;
+                        return;
+                    }
+
+                    if (ch1 == '\r' && ch2 == '\n')
+                    {
+                        consumed = reader.Position;
+                        examined = reader.Position;
+
+                        AddAndCheckConsumedBytes(reader.ConsumedBytes);
+                        _inputLength = chunkSize;
+                        _mode = chunkSize > 0 ? Mode.Data : Mode.Trailer;
+                        return;
+                    }
+
+                    chunkSize = CalculateChunkSize(ch1, chunkSize);
+                    ch1 = ch2;
+                }
+
+                // At this point, 10 bytes have been consumed which is enough to parse the max value "7FFFFFFF\r\n".
+                BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData);
+            }
+
+            private void ParseExtension(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                // Chunk-extensions not currently parsed
+                // Just drain the data
+                consumed = buffer.Start;
+                examined = buffer.Start;
+
+                do
+                {
+                    SequencePosition? extensionCursorPosition = buffer.PositionOf(ByteCR);
+                    if (extensionCursorPosition == null)
+                    {
+                        // End marker not found yet
+                        consumed = buffer.End;
+                        examined = buffer.End;
+                        AddAndCheckConsumedBytes(buffer.Length);
+                        return;
+                    };
+
+                    var extensionCursor = extensionCursorPosition.Value;
+                    var charsToByteCRExclusive = buffer.Slice(0, extensionCursor).Length;
+
+                    var suffixBuffer = buffer.Slice(extensionCursor);
+                    if (suffixBuffer.Length < 2)
+                    {
+                        consumed = extensionCursor;
+                        examined = buffer.End;
+                        AddAndCheckConsumedBytes(charsToByteCRExclusive);
+                        return;
+                    }
+
+                    suffixBuffer = suffixBuffer.Slice(0, 2);
+                    var suffixSpan = suffixBuffer.ToSpan();
+
+                    if (suffixSpan[1] == '\n')
+                    {
+                        // We consumed the \r\n at the end of the extension, so switch modes.
+                        _mode = _inputLength > 0 ? Mode.Data : Mode.Trailer;
+
+                        consumed = suffixBuffer.End;
+                        examined = suffixBuffer.End;
+                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 2);
+                    }
+                    else
+                    {
+                        // Don't consume suffixSpan[1] in case it is also a \r.
+                        buffer = buffer.Slice(charsToByteCRExclusive + 1);
+                        consumed = extensionCursor;
+                        AddAndCheckConsumedBytes(charsToByteCRExclusive + 1);
+                    }
+                } while (_mode == Mode.Extension);
+            }
+
+            private void ReadChunkedData(ReadOnlySequence<byte> buffer, PipeWriter writableBuffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                var actual = Math.Min(buffer.Length, _inputLength);
+                consumed = buffer.GetPosition(actual);
+                examined = consumed;
+
+                Copy(buffer.Slice(0, actual), writableBuffer);
+
+                _inputLength -= actual;
+                AddAndCheckConsumedBytes(actual);
+
+                if (_inputLength == 0)
+                {
+                    _mode = Mode.Suffix;
+                }
+            }
+
+            private void ParseChunkedSuffix(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                consumed = buffer.Start;
+                examined = buffer.Start;
+
+                if (buffer.Length < 2)
+                {
+                    examined = buffer.End;
+                    return;
+                }
+
+                var suffixBuffer = buffer.Slice(0, 2);
+                var suffixSpan = suffixBuffer.ToSpan();
+                if (suffixSpan[0] == '\r' && suffixSpan[1] == '\n')
+                {
+                    consumed = suffixBuffer.End;
+                    examined = suffixBuffer.End;
+                    AddAndCheckConsumedBytes(2);
+                    _mode = Mode.Prefix;
+                }
+                else
+                {
+                    BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSuffix);
+                }
+            }
+
+            private void ParseChunkedTrailer(ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+            {
+                consumed = buffer.Start;
+                examined = buffer.Start;
+
+                if (buffer.Length < 2)
+                {
+                    examined = buffer.End;
+                    return;
+                }
+
+                var trailerBuffer = buffer.Slice(0, 2);
+                var trailerSpan = trailerBuffer.ToSpan();
+
+                if (trailerSpan[0] == '\r' && trailerSpan[1] == '\n')
+                {
+                    consumed = trailerBuffer.End;
+                    examined = trailerBuffer.End;
+                    AddAndCheckConsumedBytes(2);
+                    _mode = Mode.Complete;
+                }
+                else
+                {
+                    _mode = Mode.TrailerHeaders;
+                }
+            }
+
+            private int CalculateChunkSize(int extraHexDigit, int currentParsedSize)
+            {
+                try
+                {
+                    checked
+                    {
+                        if (extraHexDigit >= '0' && extraHexDigit <= '9')
+                        {
+                            return currentParsedSize * 0x10 + (extraHexDigit - '0');
+                        }
+                        else if (extraHexDigit >= 'A' && extraHexDigit <= 'F')
+                        {
+                            return currentParsedSize * 0x10 + (extraHexDigit - ('A' - 10));
+                        }
+                        else if (extraHexDigit >= 'a' && extraHexDigit <= 'f')
+                        {
+                            return currentParsedSize * 0x10 + (extraHexDigit - ('a' - 10));
+                        }
+                    }
+                }
+                catch (OverflowException ex)
+                {
+                    throw new IOException(CoreStrings.BadRequest_BadChunkSizeData, ex);
+                }
+
+                BadHttpRequestException.Throw(RequestRejectionReason.BadChunkSizeData);
+                return -1; // can't happen, but compiler complains
+            }
+
+            private enum Mode
+            {
+                Prefix,
+                Extension,
+                Data,
+                Suffix,
+                Trailer,
+                TrailerHeaders,
+                Complete
+            };
+        }
+    }
+}

+ 184 - 0
src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs

@@ -0,0 +1,184 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.IO.Pipelines;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public class Http1OutputProducer : IHttpOutputProducer, IHttpOutputAborter, IDisposable
+    {
+        private static readonly ReadOnlyMemory<byte> _continueBytes = new ReadOnlyMemory<byte>(Encoding.ASCII.GetBytes("HTTP/1.1 100 Continue\r\n\r\n"));
+        private static readonly byte[] _bytesHttpVersion11 = Encoding.ASCII.GetBytes("HTTP/1.1 ");
+        private static readonly byte[] _bytesEndHeaders = Encoding.ASCII.GetBytes("\r\n\r\n");
+        private static readonly ReadOnlyMemory<byte> _endChunkedResponseBytes = new ReadOnlyMemory<byte>(Encoding.ASCII.GetBytes("0\r\n\r\n"));
+
+        private readonly string _connectionId;
+        private readonly ConnectionContext _connectionContext;
+        private readonly IKestrelTrace _log;
+        private readonly IHttpMinResponseDataRateFeature _minResponseDataRateFeature;
+        private readonly TimingPipeFlusher _flusher;
+
+        // This locks access to to all of the below fields
+        private readonly object _contextLock = new object();
+
+        private bool _completed = false;
+        private bool _aborted;
+        private long _unflushedBytes;
+
+        private readonly PipeWriter _pipeWriter;
+
+        public Http1OutputProducer(
+            PipeWriter pipeWriter,
+            string connectionId,
+            ConnectionContext connectionContext,
+            IKestrelTrace log,
+            ITimeoutControl timeoutControl,
+            IHttpMinResponseDataRateFeature minResponseDataRateFeature)
+        {
+            _pipeWriter = pipeWriter;
+            _connectionId = connectionId;
+            _connectionContext = connectionContext;
+            _log = log;
+            _minResponseDataRateFeature = minResponseDataRateFeature;
+            _flusher = new TimingPipeFlusher(pipeWriter, timeoutControl, log);
+        }
+
+        public Task WriteDataAsync(ReadOnlySpan<byte> buffer, CancellationToken cancellationToken = default)
+        {
+            if (cancellationToken.IsCancellationRequested)
+            {
+                return Task.FromCanceled(cancellationToken);
+            }
+
+            return WriteAsync(buffer, cancellationToken);
+        }
+
+        public Task WriteStreamSuffixAsync()
+        {
+            return WriteAsync(_endChunkedResponseBytes.Span);
+        }
+
+        public Task FlushAsync(CancellationToken cancellationToken = default)
+        {
+            return WriteAsync(Constants.EmptyData, cancellationToken);
+        }
+
+        public Task WriteAsync<T>(Func<PipeWriter, T, long> callback, T state, CancellationToken cancellationToken)
+        {
+            lock (_contextLock)
+            {
+                if (_completed)
+                {
+                    return Task.CompletedTask;
+                }
+
+                var buffer = _pipeWriter;
+                var bytesCommitted = callback(buffer, state);
+                _unflushedBytes += bytesCommitted;
+            }
+
+            return FlushAsync(cancellationToken);
+        }
+
+        public void WriteResponseHeaders(int statusCode, string reasonPhrase, HttpResponseHeaders responseHeaders)
+        {
+            lock (_contextLock)
+            {
+                if (_completed)
+                {
+                    return;
+                }
+
+                var buffer = _pipeWriter;
+                var writer = new BufferWriter<PipeWriter>(buffer);
+
+                writer.Write(_bytesHttpVersion11);
+                var statusBytes = ReasonPhrases.ToStatusBytes(statusCode, reasonPhrase);
+                writer.Write(statusBytes);
+                responseHeaders.CopyTo(ref writer);
+                writer.Write(_bytesEndHeaders);
+
+                writer.Commit();
+
+                _unflushedBytes += writer.BytesCommitted;
+            }
+        }
+
+        public void Dispose()
+        {
+            lock (_contextLock)
+            {
+                if (_completed)
+                {
+                    return;
+                }
+
+                _log.ConnectionDisconnect(_connectionId);
+                _completed = true;
+                _pipeWriter.Complete();
+            }
+        }
+
+        public void Abort(ConnectionAbortedException error)
+        {
+            // Abort can be called after Dispose if there's a flush timeout.
+            // It's important to still call _lifetimeFeature.Abort() in this case.
+
+            lock (_contextLock)
+            {
+                if (_aborted)
+                {
+                    return;
+                }
+
+                _aborted = true;
+                _connectionContext.Abort(error);
+                Dispose();
+            }
+        }
+
+        public Task Write100ContinueAsync()
+        {
+            return WriteAsync(_continueBytes.Span);
+        }
+
+        private Task WriteAsync(
+            ReadOnlySpan<byte> buffer,
+            CancellationToken cancellationToken = default)
+        {
+            lock (_contextLock)
+            {
+                if (_completed)
+                {
+                    return Task.CompletedTask;
+                }
+
+                var writer = new BufferWriter<PipeWriter>(_pipeWriter);
+                if (buffer.Length > 0)
+                {
+                    writer.Write(buffer);
+
+                    _unflushedBytes += buffer.Length;
+                }
+                writer.Commit();
+
+                var bytesWritten = _unflushedBytes;
+                _unflushedBytes = 0;
+
+                return _flusher.FlushAsync(
+                    _minResponseDataRateFeature.MinDataRate,
+                    bytesWritten,
+                    this,
+                    cancellationToken);
+            }
+        }
+    }
+}

+ 23 - 0
src/Servers/Kestrel/Core/src/Internal/Http/Http1ParsingHandler.cs

@@ -0,0 +1,23 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public struct Http1ParsingHandler : IHttpRequestLineHandler, IHttpHeadersHandler
+    {
+        public Http1Connection Connection;
+
+        public Http1ParsingHandler(Http1Connection connection)
+        {
+            Connection = connection;
+        }
+
+        public void OnHeader(Span<byte> name, Span<byte> value)
+            => Connection.OnHeader(name, value);
+
+        public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
+            => Connection.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
+    }
+}

File diff suppressed because it is too large
+ 4796 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.Generated.cs


+ 461 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpHeaders.cs

@@ -0,0 +1,461 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public abstract class HttpHeaders : IHeaderDictionary
+    {
+        protected long? _contentLength;
+        protected bool _isReadOnly;
+        protected Dictionary<string, StringValues> MaybeUnknown;
+        protected Dictionary<string, StringValues> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase));
+
+        public long? ContentLength
+        {
+            get { return _contentLength; }
+            set
+            {
+                if (value.HasValue && value.Value < 0)
+                {
+                    ThrowInvalidContentLengthException(value.Value);
+                }
+                _contentLength = value;
+            }
+        }
+
+        StringValues IHeaderDictionary.this[string key]
+        {
+            get
+            {
+                TryGetValueFast(key, out var value);
+                return value;
+            }
+            set
+            {
+                if (_isReadOnly)
+                {
+                    ThrowHeadersReadOnlyException();
+                }
+                if (string.IsNullOrEmpty(key))
+                {
+                    ThrowInvalidEmptyHeaderName();
+                }
+                if (value.Count == 0)
+                {
+                    RemoveFast(key);
+                }
+                else
+                {
+                    SetValueFast(key, value);
+                }
+            }
+        }
+
+        StringValues IDictionary<string, StringValues>.this[string key]
+        {
+            get
+            {
+                // Unlike the IHeaderDictionary version, this getter will throw a KeyNotFoundException.
+                if (!TryGetValueFast(key, out var value))
+                {
+                    ThrowKeyNotFoundException();
+                }
+                return value;
+            }
+            set
+            {
+                ((IHeaderDictionary)this)[key] = value;
+            }
+        }
+
+        protected void ThrowHeadersReadOnlyException()
+        {
+            throw new InvalidOperationException(CoreStrings.HeadersAreReadOnly);
+        }
+
+        protected void ThrowArgumentException()
+        {
+            throw new ArgumentException();
+        }
+
+        protected void ThrowKeyNotFoundException()
+        {
+            throw new KeyNotFoundException();
+        }
+
+        protected void ThrowDuplicateKeyException()
+        {
+            throw new ArgumentException(CoreStrings.KeyAlreadyExists);
+        }
+
+        public int Count => GetCountFast();
+
+        bool ICollection<KeyValuePair<string, StringValues>>.IsReadOnly => _isReadOnly;
+
+        ICollection<string> IDictionary<string, StringValues>.Keys => ((IDictionary<string, StringValues>)this).Select(pair => pair.Key).ToList();
+
+        ICollection<StringValues> IDictionary<string, StringValues>.Values => ((IDictionary<string, StringValues>)this).Select(pair => pair.Value).ToList();
+
+        public void SetReadOnly()
+        {
+            _isReadOnly = true;
+        }
+
+        public void Reset()
+        {
+            _isReadOnly = false;
+            ClearFast();
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        protected static StringValues AppendValue(in StringValues existing, string append)
+        {
+            return StringValues.Concat(existing, append);
+        }
+
+        protected static int BitCount(long value)
+        {
+            // see https://github.com/dotnet/corefx/blob/5965fd3756bc9dd9c89a27621eb10c6931126de2/src/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/BitArithmetic.cs
+
+            const ulong Mask01010101 = 0x5555555555555555UL;
+            const ulong Mask00110011 = 0x3333333333333333UL;
+            const ulong Mask00001111 = 0x0F0F0F0F0F0F0F0FUL;
+            const ulong Mask00000001 = 0x0101010101010101UL;
+
+            var v = (ulong)value;
+
+            v = v - ((v >> 1) & Mask01010101);
+            v = (v & Mask00110011) + ((v >> 2) & Mask00110011);
+            return (int)(unchecked(((v + (v >> 4)) & Mask00001111) * Mask00000001) >> 56);
+        }
+
+        protected virtual int GetCountFast()
+        { throw new NotImplementedException(); }
+
+        protected virtual bool TryGetValueFast(string key, out StringValues value)
+        { throw new NotImplementedException(); }
+
+        protected virtual void SetValueFast(string key, in StringValues value)
+        { throw new NotImplementedException(); }
+
+        protected virtual bool AddValueFast(string key, in StringValues value)
+        { throw new NotImplementedException(); }
+
+        protected virtual bool RemoveFast(string key)
+        { throw new NotImplementedException(); }
+
+        protected virtual void ClearFast()
+        { throw new NotImplementedException(); }
+
+        protected virtual bool CopyToFast(KeyValuePair<string, StringValues>[] array, int arrayIndex)
+        { throw new NotImplementedException(); }
+
+        protected virtual IEnumerator<KeyValuePair<string, StringValues>> GetEnumeratorFast()
+        { throw new NotImplementedException(); }
+
+        void ICollection<KeyValuePair<string, StringValues>>.Add(KeyValuePair<string, StringValues> item)
+        {
+            ((IDictionary<string, StringValues>)this).Add(item.Key, item.Value);
+        }
+
+        void IDictionary<string, StringValues>.Add(string key, StringValues value)
+        {
+            if (_isReadOnly)
+            {
+                ThrowHeadersReadOnlyException();
+            }
+            if (string.IsNullOrEmpty(key))
+            {
+                ThrowInvalidEmptyHeaderName();
+            }
+
+            if (value.Count > 0 && !AddValueFast(key, value))
+            {
+                ThrowDuplicateKeyException();
+            }
+        }
+
+        void ICollection<KeyValuePair<string, StringValues>>.Clear()
+        {
+            if (_isReadOnly)
+            {
+                ThrowHeadersReadOnlyException();
+            }
+            ClearFast();
+        }
+
+        bool ICollection<KeyValuePair<string, StringValues>>.Contains(KeyValuePair<string, StringValues> item)
+        {
+            return
+                TryGetValueFast(item.Key, out var value) &&
+                value.Equals(item.Value);
+        }
+
+        bool IDictionary<string, StringValues>.ContainsKey(string key)
+        {
+            StringValues value;
+            return TryGetValueFast(key, out value);
+        }
+
+        void ICollection<KeyValuePair<string, StringValues>>.CopyTo(KeyValuePair<string, StringValues>[] array, int arrayIndex)
+        {
+            if (!CopyToFast(array, arrayIndex))
+            {
+                ThrowArgumentException();
+            }
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumeratorFast();
+        }
+
+        IEnumerator<KeyValuePair<string, StringValues>> IEnumerable<KeyValuePair<string, StringValues>>.GetEnumerator()
+        {
+            return GetEnumeratorFast();
+        }
+
+        bool ICollection<KeyValuePair<string, StringValues>>.Remove(KeyValuePair<string, StringValues> item)
+        {
+            return
+                TryGetValueFast(item.Key, out var value) &&
+                value.Equals(item.Value) &&
+                RemoveFast(item.Key);
+        }
+
+        bool IDictionary<string, StringValues>.Remove(string key)
+        {
+            if (_isReadOnly)
+            {
+                ThrowHeadersReadOnlyException();
+            }
+            return RemoveFast(key);
+        }
+
+        bool IDictionary<string, StringValues>.TryGetValue(string key, out StringValues value)
+        {
+            return TryGetValueFast(key, out value);
+        }
+
+        public static void ValidateHeaderValueCharacters(in StringValues headerValues)
+        {
+            var count = headerValues.Count;
+            for (var i = 0; i < count; i++)
+
+            {
+                ValidateHeaderValueCharacters(headerValues[i]);
+            }
+        }
+
+        public static void ValidateHeaderValueCharacters(string headerCharacters)
+        {
+            if (headerCharacters != null)
+            {
+                var invalid = HttpCharacters.IndexOfInvalidFieldValueChar(headerCharacters);
+                if (invalid >= 0)
+                {
+                    ThrowInvalidHeaderCharacter(headerCharacters[invalid]);
+                }
+            }
+        }
+
+        public static void ValidateHeaderNameCharacters(string headerCharacters)
+        {
+            var invalid = HttpCharacters.IndexOfInvalidTokenChar(headerCharacters);
+            if (invalid >= 0)
+            {
+                ThrowInvalidHeaderCharacter(headerCharacters[invalid]);
+            }
+        }
+
+        public static unsafe ConnectionOptions ParseConnection(in StringValues connection)
+        {
+            var connectionOptions = ConnectionOptions.None;
+
+            var connectionCount = connection.Count;
+            for (var i = 0; i < connectionCount; i++)
+            {
+                var value = connection[i];
+                fixed (char* ptr = value)
+                {
+                    var ch = ptr;
+                    var tokenEnd = ch;
+                    var end = ch + value.Length;
+
+                    while (ch < end)
+                    {
+                        while (tokenEnd < end && *tokenEnd != ',')
+                        {
+                            tokenEnd++;
+                        }
+
+                        while (ch < tokenEnd && *ch == ' ')
+                        {
+                            ch++;
+                        }
+
+                        var tokenLength = tokenEnd - ch;
+
+                        if (tokenLength >= 9 && (*ch | 0x20) == 'k')
+                        {
+                            if ((*++ch | 0x20) == 'e' &&
+                                (*++ch | 0x20) == 'e' &&
+                                (*++ch | 0x20) == 'p' &&
+                                *++ch == '-' &&
+                                (*++ch | 0x20) == 'a' &&
+                                (*++ch | 0x20) == 'l' &&
+                                (*++ch | 0x20) == 'i' &&
+                                (*++ch | 0x20) == 'v' &&
+                                (*++ch | 0x20) == 'e')
+                            {
+                                ch++;
+                                while (ch < tokenEnd && *ch == ' ')
+                                {
+                                    ch++;
+                                }
+
+                                if (ch == tokenEnd)
+                                {
+                                    connectionOptions |= ConnectionOptions.KeepAlive;
+                                }
+                            }
+                        }
+                        else if (tokenLength >= 7 && (*ch | 0x20) == 'u')
+                        {
+                            if ((*++ch | 0x20) == 'p' &&
+                                (*++ch | 0x20) == 'g' &&
+                                (*++ch | 0x20) == 'r' &&
+                                (*++ch | 0x20) == 'a' &&
+                                (*++ch | 0x20) == 'd' &&
+                                (*++ch | 0x20) == 'e')
+                            {
+                                ch++;
+                                while (ch < tokenEnd && *ch == ' ')
+                                {
+                                    ch++;
+                                }
+
+                                if (ch == tokenEnd)
+                                {
+                                    connectionOptions |= ConnectionOptions.Upgrade;
+                                }
+                            }
+                        }
+                        else if (tokenLength >= 5 && (*ch | 0x20) == 'c')
+                        {
+                            if ((*++ch | 0x20) == 'l' &&
+                                (*++ch | 0x20) == 'o' &&
+                                (*++ch | 0x20) == 's' &&
+                                (*++ch | 0x20) == 'e')
+                            {
+                                ch++;
+                                while (ch < tokenEnd && *ch == ' ')
+                                {
+                                    ch++;
+                                }
+
+                                if (ch == tokenEnd)
+                                {
+                                    connectionOptions |= ConnectionOptions.Close;
+                                }
+                            }
+                        }
+
+                        tokenEnd++;
+                        ch = tokenEnd;
+                    }
+                }
+            }
+
+            return connectionOptions;
+        }
+
+        public static unsafe TransferCoding GetFinalTransferCoding(in StringValues transferEncoding)
+        {
+            var transferEncodingOptions = TransferCoding.None;
+
+            var transferEncodingCount = transferEncoding.Count;
+            for (var i = 0; i < transferEncodingCount; i++)
+            {
+                var value = transferEncoding[i];
+                fixed (char* ptr = value)
+                {
+                    var ch = ptr;
+                    var tokenEnd = ch;
+                    var end = ch + value.Length;
+
+                    while (ch < end)
+                    {
+                        while (tokenEnd < end && *tokenEnd != ',')
+                        {
+                            tokenEnd++;
+                        }
+
+                        while (ch < tokenEnd && *ch == ' ')
+                        {
+                            ch++;
+                        }
+
+                        var tokenLength = tokenEnd - ch;
+
+                        if (tokenLength >= 7 && (*ch | 0x20) == 'c')
+                        {
+                            if ((*++ch | 0x20) == 'h' &&
+                                (*++ch | 0x20) == 'u' &&
+                                (*++ch | 0x20) == 'n' &&
+                                (*++ch | 0x20) == 'k' &&
+                                (*++ch | 0x20) == 'e' &&
+                                (*++ch | 0x20) == 'd')
+                            {
+                                ch++;
+                                while (ch < tokenEnd && *ch == ' ')
+                                {
+                                    ch++;
+                                }
+
+                                if (ch == tokenEnd)
+                                {
+                                    transferEncodingOptions = TransferCoding.Chunked;
+                                }
+                            }
+                        }
+
+                        if (tokenLength > 0 && ch != tokenEnd)
+                        {
+                            transferEncodingOptions = TransferCoding.Other;
+                        }
+
+                        tokenEnd++;
+                        ch = tokenEnd;
+                    }
+                }
+            }
+
+            return transferEncodingOptions;
+        }
+
+        private static void ThrowInvalidContentLengthException(long value)
+        {
+            throw new ArgumentOutOfRangeException(CoreStrings.FormatInvalidContentLength_InvalidNumber(value));
+        }
+
+        private static void ThrowInvalidHeaderCharacter(char ch)
+        {
+            throw new InvalidOperationException(CoreStrings.FormatInvalidAsciiOrControlChar(string.Format("0x{0:X4}", (ushort)ch)));
+        }
+
+        private static void ThrowInvalidEmptyHeaderName()
+        {
+            throw new InvalidOperationException(CoreStrings.InvalidEmptyHeaderName);
+        }
+    }
+}

+ 22 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpMethod.cs

@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public enum HttpMethod: byte
+    {
+        Get,
+        Put,
+        Delete,
+        Post,
+        Head,
+        Trace,
+        Patch,
+        Connect,
+        Options,
+
+        Custom,
+
+        None = byte.MaxValue,
+    }
+}

+ 475 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs

@@ -0,0 +1,475 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public class HttpParser<TRequestHandler> : IHttpParser<TRequestHandler> where TRequestHandler : IHttpHeadersHandler, IHttpRequestLineHandler
+    {
+        private bool _showErrorDetails;
+
+        public HttpParser() : this(showErrorDetails: true)
+        {
+        }
+
+        public HttpParser(bool showErrorDetails)
+        {
+            _showErrorDetails = showErrorDetails;
+        }
+
+        // byte types don't have a data type annotation so we pre-cast them; to avoid in-place casts
+        private const byte ByteCR = (byte)'\r';
+        private const byte ByteLF = (byte)'\n';
+        private const byte ByteColon = (byte)':';
+        private const byte ByteSpace = (byte)' ';
+        private const byte ByteTab = (byte)'\t';
+        private const byte ByteQuestionMark = (byte)'?';
+        private const byte BytePercentage = (byte)'%';
+
+        public unsafe bool ParseRequestLine(TRequestHandler handler, in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
+        {
+            consumed = buffer.Start;
+            examined = buffer.End;
+
+            // Prepare the first span
+            var span = buffer.First.Span;
+            var lineIndex = span.IndexOf(ByteLF);
+            if (lineIndex >= 0)
+            {
+                consumed = buffer.GetPosition(lineIndex + 1, consumed);
+                span = span.Slice(0, lineIndex + 1);
+            }
+            else if (buffer.IsSingleSegment)
+            {
+                // No request line end
+                return false;
+            }
+            else if (TryGetNewLine(buffer, out var found))
+            {
+                span = buffer.Slice(consumed, found).ToSpan();
+                consumed = found;
+            }
+            else
+            {
+                // No request line end
+                return false;
+            }
+
+            // Fix and parse the span
+            fixed (byte* data = span)
+            {
+                ParseRequestLine(handler, data, span.Length);
+            }
+
+            examined = consumed;
+            return true;
+        }
+
+        private unsafe void ParseRequestLine(TRequestHandler handler, byte* data, int length)
+        {
+            // Get Method and set the offset
+            var method = HttpUtilities.GetKnownMethod(data, length, out var offset);
+
+            Span<byte> customMethod = method == HttpMethod.Custom ?
+                GetUnknownMethod(data, length, out offset) :
+                default;
+
+            // Skip space
+            offset++;
+
+            byte ch = 0;
+            // Target = Path and Query
+            var pathEncoded = false;
+            var pathStart = -1;
+            for (; offset < length; offset++)
+            {
+                ch = data[offset];
+                if (ch == ByteSpace)
+                {
+                    if (pathStart == -1)
+                    {
+                        // Empty path is illegal
+                        RejectRequestLine(data, length);
+                    }
+
+                    break;
+                }
+                else if (ch == ByteQuestionMark)
+                {
+                    if (pathStart == -1)
+                    {
+                        // Empty path is illegal
+                        RejectRequestLine(data, length);
+                    }
+
+                    break;
+                }
+                else if (ch == BytePercentage)
+                {
+                    if (pathStart == -1)
+                    {
+                        // Path starting with % is illegal
+                        RejectRequestLine(data, length);
+                    }
+
+                    pathEncoded = true;
+                }
+                else if (pathStart == -1)
+                {
+                    pathStart = offset;
+                }
+            }
+
+            if (pathStart == -1)
+            {
+                // Start of path not found
+                RejectRequestLine(data, length);
+            }
+
+            var pathBuffer = new Span<byte>(data + pathStart, offset - pathStart);
+
+            // Query string
+            var queryStart = offset;
+            if (ch == ByteQuestionMark)
+            {
+                // We have a query string
+                for (; offset < length; offset++)
+                {
+                    ch = data[offset];
+                    if (ch == ByteSpace)
+                    {
+                        break;
+                    }
+                }
+            }
+
+            // End of query string not found
+            if (offset == length)
+            {
+                RejectRequestLine(data, length);
+            }
+
+            var targetBuffer = new Span<byte>(data + pathStart, offset - pathStart);
+            var query = new Span<byte>(data + queryStart, offset - queryStart);
+
+            // Consume space
+            offset++;
+
+            // Version
+            var httpVersion = HttpUtilities.GetKnownVersion(data + offset, length - offset);
+            if (httpVersion == HttpVersion.Unknown)
+            {
+                if (data[offset] == ByteCR || data[length - 2] != ByteCR)
+                {
+                    // If missing delimiter or CR before LF, reject and log entire line
+                    RejectRequestLine(data, length);
+                }
+                else
+                {
+                    // else inform HTTP version is unsupported.
+                    RejectUnknownVersion(data + offset, length - offset - 2);
+                }
+            }
+
+            // After version's 8 bytes and CR, expect LF
+            if (data[offset + 8 + 1] != ByteLF)
+            {
+                RejectRequestLine(data, length);
+            }
+
+            handler.OnStartLine(method, httpVersion, targetBuffer, pathBuffer, query, customMethod, pathEncoded);
+        }
+
+        public unsafe bool ParseHeaders(TRequestHandler handler, in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined, out int consumedBytes)
+        {
+            consumed = buffer.Start;
+            examined = buffer.End;
+            consumedBytes = 0;
+
+            var bufferEnd = buffer.End;
+
+            var reader = new BufferReader(buffer);
+            var start = default(BufferReader);
+            var done = false;
+
+            try
+            {
+                while (!reader.End)
+                {
+                    var span = reader.CurrentSegment;
+                    var remaining = span.Length - reader.CurrentSegmentIndex;
+
+                    fixed (byte* pBuffer = span)
+                    {
+                        while (remaining > 0)
+                        {
+                            var index = reader.CurrentSegmentIndex;
+                            int ch1;
+                            int ch2;
+                            var readAhead = false;
+
+                            // Fast path, we're still looking at the same span
+                            if (remaining >= 2)
+                            {
+                                ch1 = pBuffer[index];
+                                ch2 = pBuffer[index + 1];
+                            }
+                            else
+                            {
+                                // Store the reader before we look ahead 2 bytes (probably straddling
+                                // spans)
+                                start = reader;
+
+                                // Possibly split across spans
+                                ch1 = reader.Read();
+                                ch2 = reader.Read();
+
+                                readAhead = true;
+                            }
+
+                            if (ch1 == ByteCR)
+                            {
+                                // Check for final CRLF.
+                                if (ch2 == -1)
+                                {
+                                    // Reset the reader so we don't consume anything
+                                    reader = start;
+                                    return false;
+                                }
+                                else if (ch2 == ByteLF)
+                                {
+                                    // If we got 2 bytes from the span directly so skip ahead 2 so that
+                                    // the reader's state matches what we expect
+                                    if (!readAhead)
+                                    {
+                                        reader.Advance(2);
+                                    }
+
+                                    done = true;
+                                    return true;
+                                }
+
+                                // Headers don't end in CRLF line.
+                                BadHttpRequestException.Throw(RequestRejectionReason.InvalidRequestHeadersNoCRLF);
+                            }
+
+                            // We moved the reader so look ahead 2 bytes so reset both the reader
+                            // and the index
+                            if (readAhead)
+                            {
+                                reader = start;
+                                index = reader.CurrentSegmentIndex;
+                            }
+
+                            var endIndex = new Span<byte>(pBuffer + index, remaining).IndexOf(ByteLF);
+                            var length = 0;
+
+                            if (endIndex != -1)
+                            {
+                                length = endIndex + 1;
+                                var pHeader = pBuffer + index;
+
+                                TakeSingleHeader(pHeader, length, handler);
+                            }
+                            else
+                            {
+                                var current = reader.Position;
+                                var currentSlice = buffer.Slice(current, bufferEnd);
+
+                                var lineEndPosition = currentSlice.PositionOf(ByteLF);
+                                // Split buffers
+                                if (lineEndPosition == null)
+                                {
+                                    // Not there
+                                    return false;
+                                }
+
+                                var lineEnd = lineEndPosition.Value;
+
+                                // Make sure LF is included in lineEnd
+                                lineEnd = buffer.GetPosition(1, lineEnd);
+                                var headerSpan = buffer.Slice(current, lineEnd).ToSpan();
+                                length = headerSpan.Length;
+
+                                fixed (byte* pHeader = headerSpan)
+                                {
+                                    TakeSingleHeader(pHeader, length, handler);
+                                }
+
+                                // We're going to the next span after this since we know we crossed spans here
+                                // so mark the remaining as equal to the headerSpan so that we end up at 0
+                                // on the next iteration
+                                remaining = length;
+                            }
+
+                            // Skip the reader forward past the header line
+                            reader.Advance(length);
+                            remaining -= length;
+                        }
+                    }
+                }
+
+                return false;
+            }
+            finally
+            {
+                consumed = reader.Position;
+                consumedBytes = reader.ConsumedBytes;
+
+                if (done)
+                {
+                    examined = consumed;
+                }
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private unsafe int FindEndOfName(byte* headerLine, int length)
+        {
+            var index = 0;
+            var sawWhitespace = false;
+            for (; index < length; index++)
+            {
+                var ch = headerLine[index];
+                if (ch == ByteColon)
+                {
+                    break;
+                }
+                if (ch == ByteTab || ch == ByteSpace || ch == ByteCR)
+                {
+                    sawWhitespace = true;
+                }
+            }
+
+            if (index == length || sawWhitespace)
+            {
+                RejectRequestHeader(headerLine, length);
+            }
+
+            return index;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private unsafe void TakeSingleHeader(byte* headerLine, int length, TRequestHandler handler)
+        {
+            // Skip CR, LF from end position
+            var valueEnd = length - 3;
+            var nameEnd = FindEndOfName(headerLine, length);
+
+            // Header name is empty
+            if (nameEnd == 0)
+            {
+                RejectRequestHeader(headerLine, length);
+            }
+
+            if (headerLine[valueEnd + 2] != ByteLF)
+            {
+                RejectRequestHeader(headerLine, length);
+            }
+            if (headerLine[valueEnd + 1] != ByteCR)
+            {
+                RejectRequestHeader(headerLine, length);
+            }
+
+            // Skip colon from value start
+            var valueStart = nameEnd + 1;
+            // Ignore start whitespace
+            for (; valueStart < valueEnd; valueStart++)
+            {
+                var ch = headerLine[valueStart];
+                if (ch != ByteTab && ch != ByteSpace && ch != ByteCR)
+                {
+                    break;
+                }
+                else if (ch == ByteCR)
+                {
+                    RejectRequestHeader(headerLine, length);
+                }
+            }
+
+            // Check for CR in value
+            var valueBuffer = new Span<byte>(headerLine + valueStart, valueEnd - valueStart + 1);
+            if (valueBuffer.IndexOf(ByteCR) >= 0)
+            {
+                RejectRequestHeader(headerLine, length);
+            }
+
+            // Ignore end whitespace
+            var lengthChanged = false;
+            for (; valueEnd >= valueStart; valueEnd--)
+            {
+                var ch = headerLine[valueEnd];
+                if (ch != ByteTab && ch != ByteSpace)
+                {
+                    break;
+                }
+
+                lengthChanged = true;
+            }
+
+            if (lengthChanged)
+            {
+                // Length changed
+                valueBuffer = new Span<byte>(headerLine + valueStart, valueEnd - valueStart + 1);
+            }
+
+            var nameBuffer = new Span<byte>(headerLine, nameEnd);
+
+            handler.OnHeader(nameBuffer, valueBuffer);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private static bool TryGetNewLine(in ReadOnlySequence<byte> buffer, out SequencePosition found)
+        {
+            var byteLfPosition = buffer.PositionOf(ByteLF);
+            if (byteLfPosition != null)
+            {
+                // Move 1 byte past the \n
+                found = buffer.GetPosition(1, byteLfPosition.Value);
+                return true;
+            }
+
+            found = default;
+            return false;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private unsafe Span<byte> GetUnknownMethod(byte* data, int length, out int methodLength)
+        {
+            var invalidIndex = HttpCharacters.IndexOfInvalidTokenChar(data, length);
+
+            if (invalidIndex <= 0 || data[invalidIndex] != ByteSpace)
+            {
+                RejectRequestLine(data, length);
+            }
+
+            methodLength = invalidIndex;
+            return new Span<byte>(data, methodLength);
+        }
+
+        [StackTraceHidden]
+        private unsafe void RejectRequestLine(byte* requestLine, int length)
+            => throw GetInvalidRequestException(RequestRejectionReason.InvalidRequestLine, requestLine, length);
+
+        [StackTraceHidden]
+        private unsafe void RejectRequestHeader(byte* headerLine, int length)
+            => throw GetInvalidRequestException(RequestRejectionReason.InvalidRequestHeader, headerLine, length);
+
+        [StackTraceHidden]
+        private unsafe void RejectUnknownVersion(byte* version, int length)
+            => throw GetInvalidRequestException(RequestRejectionReason.UnrecognizedHTTPVersion, version, length);
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private unsafe BadHttpRequestException GetInvalidRequestException(RequestRejectionReason reason, byte* detail, int length)
+            => BadHttpRequestException.GetException(
+                reason,
+                _showErrorDetails
+                    ? new Span<byte>(detail, length).GetAsciiStringEscaped(Constants.MaxExceptionDetailSize)
+                    : string.Empty);
+    }
+}

+ 254 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.FeatureCollection.cs

@@ -0,0 +1,254 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public partial class HttpProtocol : IHttpRequestFeature,
+                                        IHttpResponseFeature,
+                                        IHttpUpgradeFeature,
+                                        IHttpConnectionFeature,
+                                        IHttpRequestLifetimeFeature,
+                                        IHttpRequestIdentifierFeature,
+                                        IHttpBodyControlFeature,
+                                        IHttpMaxRequestBodySizeFeature
+    {
+        // NOTE: When feature interfaces are added to or removed from this HttpProtocol class implementation,
+        // then the list of `implementedFeatures` in the generated code project MUST also be updated.
+        // See also: tools/CodeGenerator/HttpProtocolFeatureCollection.cs
+
+        string IHttpRequestFeature.Protocol
+        {
+            get => HttpVersion;
+            set => HttpVersion = value;
+        }
+
+        string IHttpRequestFeature.Scheme
+        {
+            get => Scheme ?? "http";
+            set => Scheme = value;
+        }
+
+        string IHttpRequestFeature.Method
+        {
+            get
+            {
+                if (_methodText != null)
+                {
+                    return _methodText;
+                }
+
+                _methodText = HttpUtilities.MethodToString(Method) ?? string.Empty;
+                return _methodText;
+            }
+            set
+            {
+                _methodText = value;
+            }
+        }
+
+        string IHttpRequestFeature.PathBase
+        {
+            get => PathBase ?? "";
+            set => PathBase = value;
+        }
+
+        string IHttpRequestFeature.Path
+        {
+            get => Path;
+            set => Path = value;
+        }
+
+        string IHttpRequestFeature.QueryString
+        {
+            get => QueryString;
+            set => QueryString = value;
+        }
+
+        string IHttpRequestFeature.RawTarget
+        {
+            get => RawTarget;
+            set => RawTarget = value;
+        }
+
+        IHeaderDictionary IHttpRequestFeature.Headers
+        {
+            get => RequestHeaders;
+            set => RequestHeaders = value;
+        }
+
+        Stream IHttpRequestFeature.Body
+        {
+            get => RequestBody;
+            set => RequestBody = value;
+        }
+
+        int IHttpResponseFeature.StatusCode
+        {
+            get => StatusCode;
+            set => StatusCode = value;
+        }
+
+        string IHttpResponseFeature.ReasonPhrase
+        {
+            get => ReasonPhrase;
+            set => ReasonPhrase = value;
+        }
+
+        IHeaderDictionary IHttpResponseFeature.Headers
+        {
+            get => ResponseHeaders;
+            set => ResponseHeaders = value;
+        }
+
+        Stream IHttpResponseFeature.Body
+        {
+            get => ResponseBody;
+            set => ResponseBody = value;
+        }
+
+        CancellationToken IHttpRequestLifetimeFeature.RequestAborted
+        {
+            get => RequestAborted;
+            set => RequestAborted = value;
+        }
+
+        bool IHttpResponseFeature.HasStarted => HasResponseStarted;
+
+        bool IHttpUpgradeFeature.IsUpgradableRequest => IsUpgradableRequest;
+
+        IPAddress IHttpConnectionFeature.RemoteIpAddress
+        {
+            get => RemoteIpAddress;
+            set => RemoteIpAddress = value;
+        }
+
+        IPAddress IHttpConnectionFeature.LocalIpAddress
+        {
+            get => LocalIpAddress;
+            set => LocalIpAddress = value;
+        }
+
+        int IHttpConnectionFeature.RemotePort
+        {
+            get => RemotePort;
+            set => RemotePort = value;
+        }
+
+        int IHttpConnectionFeature.LocalPort
+        {
+            get => LocalPort;
+            set => LocalPort = value;
+        }
+
+        string IHttpConnectionFeature.ConnectionId
+        {
+            get => ConnectionIdFeature;
+            set => ConnectionIdFeature = value;
+        }
+
+        string IHttpRequestIdentifierFeature.TraceIdentifier
+        {
+            get => TraceIdentifier;
+            set => TraceIdentifier = value;
+        }
+
+        bool IHttpBodyControlFeature.AllowSynchronousIO
+        {
+            get => AllowSynchronousIO;
+            set => AllowSynchronousIO = value;
+        }
+
+        bool IHttpMaxRequestBodySizeFeature.IsReadOnly => HasStartedConsumingRequestBody || IsUpgraded;
+
+        long? IHttpMaxRequestBodySizeFeature.MaxRequestBodySize
+        {
+            get => MaxRequestBodySize;
+            set
+            {
+                if (HasStartedConsumingRequestBody)
+                {
+                    throw new InvalidOperationException(CoreStrings.MaxRequestBodySizeCannotBeModifiedAfterRead);
+                }
+                if (IsUpgraded)
+                {
+                    throw new InvalidOperationException(CoreStrings.MaxRequestBodySizeCannotBeModifiedForUpgradedRequests);
+                }
+                if (value < 0)
+                {
+                    throw new ArgumentOutOfRangeException(nameof(value), CoreStrings.NonNegativeNumberOrNullRequired);
+                }
+
+                MaxRequestBodySize = value;
+            }
+        }
+
+        protected void ResetHttp1Features()
+        {
+            _currentIHttpMinRequestBodyDataRateFeature = this;
+            _currentIHttpMinResponseDataRateFeature = this;
+        }
+
+        protected void ResetHttp2Features()
+        {
+            _currentIHttp2StreamIdFeature = this;
+            _currentIHttpResponseTrailersFeature = this;
+        }
+
+        void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
+        {
+            OnStarting(callback, state);
+        }
+
+        void IHttpResponseFeature.OnCompleted(Func<object, Task> callback, object state)
+        {
+            OnCompleted(callback, state);
+        }
+
+        async Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
+        {
+            if (!IsUpgradableRequest)
+            {
+                throw new InvalidOperationException(CoreStrings.CannotUpgradeNonUpgradableRequest);
+            }
+
+            if (IsUpgraded)
+            {
+                throw new InvalidOperationException(CoreStrings.UpgradeCannotBeCalledMultipleTimes);
+            }
+
+            if (!ServiceContext.ConnectionManager.UpgradedConnectionCount.TryLockOne())
+            {
+                throw new InvalidOperationException(CoreStrings.UpgradedConnectionLimitReached);
+            }
+
+            IsUpgraded = true;
+
+            ConnectionFeatures.Get<IDecrementConcurrentConnectionCountFeature>()?.ReleaseConnection();
+
+            StatusCode = StatusCodes.Status101SwitchingProtocols;
+            ReasonPhrase = "Switching Protocols";
+            ResponseHeaders["Connection"] = "Upgrade";
+
+            await FlushAsync();
+
+            return _streams.Upgrade();
+        }
+
+        void IHttpRequestLifetimeFeature.Abort()
+        {
+            ApplicationAbort();
+        }
+
+        protected abstract void ApplicationAbort();
+    }
+}

+ 645 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs

@@ -0,0 +1,645 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Http.Features.Authentication;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public partial class HttpProtocol : IFeatureCollection
+    {
+        private static readonly Type IHttpRequestFeatureType = typeof(IHttpRequestFeature);
+        private static readonly Type IHttpResponseFeatureType = typeof(IHttpResponseFeature);
+        private static readonly Type IHttpRequestIdentifierFeatureType = typeof(IHttpRequestIdentifierFeature);
+        private static readonly Type IServiceProvidersFeatureType = typeof(IServiceProvidersFeature);
+        private static readonly Type IHttpRequestLifetimeFeatureType = typeof(IHttpRequestLifetimeFeature);
+        private static readonly Type IHttpConnectionFeatureType = typeof(IHttpConnectionFeature);
+        private static readonly Type IHttpAuthenticationFeatureType = typeof(IHttpAuthenticationFeature);
+        private static readonly Type IQueryFeatureType = typeof(IQueryFeature);
+        private static readonly Type IFormFeatureType = typeof(IFormFeature);
+        private static readonly Type IHttpUpgradeFeatureType = typeof(IHttpUpgradeFeature);
+        private static readonly Type IHttp2StreamIdFeatureType = typeof(IHttp2StreamIdFeature);
+        private static readonly Type IHttpResponseTrailersFeatureType = typeof(IHttpResponseTrailersFeature);
+        private static readonly Type IResponseCookiesFeatureType = typeof(IResponseCookiesFeature);
+        private static readonly Type IItemsFeatureType = typeof(IItemsFeature);
+        private static readonly Type ITlsConnectionFeatureType = typeof(ITlsConnectionFeature);
+        private static readonly Type IHttpWebSocketFeatureType = typeof(IHttpWebSocketFeature);
+        private static readonly Type ISessionFeatureType = typeof(ISessionFeature);
+        private static readonly Type IHttpMaxRequestBodySizeFeatureType = typeof(IHttpMaxRequestBodySizeFeature);
+        private static readonly Type IHttpMinRequestBodyDataRateFeatureType = typeof(IHttpMinRequestBodyDataRateFeature);
+        private static readonly Type IHttpMinResponseDataRateFeatureType = typeof(IHttpMinResponseDataRateFeature);
+        private static readonly Type IHttpBodyControlFeatureType = typeof(IHttpBodyControlFeature);
+        private static readonly Type IHttpSendFileFeatureType = typeof(IHttpSendFileFeature);
+
+        private object _currentIHttpRequestFeature;
+        private object _currentIHttpResponseFeature;
+        private object _currentIHttpRequestIdentifierFeature;
+        private object _currentIServiceProvidersFeature;
+        private object _currentIHttpRequestLifetimeFeature;
+        private object _currentIHttpConnectionFeature;
+        private object _currentIHttpAuthenticationFeature;
+        private object _currentIQueryFeature;
+        private object _currentIFormFeature;
+        private object _currentIHttpUpgradeFeature;
+        private object _currentIHttp2StreamIdFeature;
+        private object _currentIHttpResponseTrailersFeature;
+        private object _currentIResponseCookiesFeature;
+        private object _currentIItemsFeature;
+        private object _currentITlsConnectionFeature;
+        private object _currentIHttpWebSocketFeature;
+        private object _currentISessionFeature;
+        private object _currentIHttpMaxRequestBodySizeFeature;
+        private object _currentIHttpMinRequestBodyDataRateFeature;
+        private object _currentIHttpMinResponseDataRateFeature;
+        private object _currentIHttpBodyControlFeature;
+        private object _currentIHttpSendFileFeature;
+
+        private int _featureRevision;
+
+        private List<KeyValuePair<Type, object>> MaybeExtra;
+
+        private void FastReset()
+        {
+            _currentIHttpRequestFeature = this;
+            _currentIHttpResponseFeature = this;
+            _currentIHttpUpgradeFeature = this;
+            _currentIHttpRequestIdentifierFeature = this;
+            _currentIHttpRequestLifetimeFeature = this;
+            _currentIHttpConnectionFeature = this;
+            _currentIHttpMaxRequestBodySizeFeature = this;
+            _currentIHttpBodyControlFeature = this;
+
+            _currentIServiceProvidersFeature = null;
+            _currentIHttpAuthenticationFeature = null;
+            _currentIQueryFeature = null;
+            _currentIFormFeature = null;
+            _currentIHttp2StreamIdFeature = null;
+            _currentIHttpResponseTrailersFeature = null;
+            _currentIResponseCookiesFeature = null;
+            _currentIItemsFeature = null;
+            _currentITlsConnectionFeature = null;
+            _currentIHttpWebSocketFeature = null;
+            _currentISessionFeature = null;
+            _currentIHttpMinRequestBodyDataRateFeature = null;
+            _currentIHttpMinResponseDataRateFeature = null;
+            _currentIHttpSendFileFeature = null;
+        }
+
+        // Internal for testing
+        internal void ResetFeatureCollection()
+        {
+            FastReset();
+            MaybeExtra?.Clear();
+            _featureRevision++;
+        }
+
+        private object ExtraFeatureGet(Type key)
+        {
+            if (MaybeExtra == null)
+            {
+                return null;
+            }
+            for (var i = 0; i < MaybeExtra.Count; i++)
+            {
+                var kv = MaybeExtra[i];
+                if (kv.Key == key)
+                {
+                    return kv.Value;
+                }
+            }
+            return null;
+        }
+
+        private void ExtraFeatureSet(Type key, object value)
+        {
+            if (MaybeExtra == null)
+            {
+                MaybeExtra = new List<KeyValuePair<Type, object>>(2);
+            }
+
+            for (var i = 0; i < MaybeExtra.Count; i++)
+            {
+                if (MaybeExtra[i].Key == key)
+                {
+                    MaybeExtra[i] = new KeyValuePair<Type, object>(key, value);
+                    return;
+                }
+            }
+            MaybeExtra.Add(new KeyValuePair<Type, object>(key, value));
+        }
+
+        bool IFeatureCollection.IsReadOnly => false;
+
+        int IFeatureCollection.Revision => _featureRevision;
+
+        object IFeatureCollection.this[Type key]
+        {
+            get
+            {
+                object feature = null;
+                if (key == IHttpRequestFeatureType)
+                {
+                    feature = _currentIHttpRequestFeature;
+                }
+                else if (key == IHttpResponseFeatureType)
+                {
+                    feature = _currentIHttpResponseFeature;
+                }
+                else if (key == IHttpRequestIdentifierFeatureType)
+                {
+                    feature = _currentIHttpRequestIdentifierFeature;
+                }
+                else if (key == IServiceProvidersFeatureType)
+                {
+                    feature = _currentIServiceProvidersFeature;
+                }
+                else if (key == IHttpRequestLifetimeFeatureType)
+                {
+                    feature = _currentIHttpRequestLifetimeFeature;
+                }
+                else if (key == IHttpConnectionFeatureType)
+                {
+                    feature = _currentIHttpConnectionFeature;
+                }
+                else if (key == IHttpAuthenticationFeatureType)
+                {
+                    feature = _currentIHttpAuthenticationFeature;
+                }
+                else if (key == IQueryFeatureType)
+                {
+                    feature = _currentIQueryFeature;
+                }
+                else if (key == IFormFeatureType)
+                {
+                    feature = _currentIFormFeature;
+                }
+                else if (key == IHttpUpgradeFeatureType)
+                {
+                    feature = _currentIHttpUpgradeFeature;
+                }
+                else if (key == IHttp2StreamIdFeatureType)
+                {
+                    feature = _currentIHttp2StreamIdFeature;
+                }
+                else if (key == IHttpResponseTrailersFeatureType)
+                {
+                    feature = _currentIHttpResponseTrailersFeature;
+                }
+                else if (key == IResponseCookiesFeatureType)
+                {
+                    feature = _currentIResponseCookiesFeature;
+                }
+                else if (key == IItemsFeatureType)
+                {
+                    feature = _currentIItemsFeature;
+                }
+                else if (key == ITlsConnectionFeatureType)
+                {
+                    feature = _currentITlsConnectionFeature;
+                }
+                else if (key == IHttpWebSocketFeatureType)
+                {
+                    feature = _currentIHttpWebSocketFeature;
+                }
+                else if (key == ISessionFeatureType)
+                {
+                    feature = _currentISessionFeature;
+                }
+                else if (key == IHttpMaxRequestBodySizeFeatureType)
+                {
+                    feature = _currentIHttpMaxRequestBodySizeFeature;
+                }
+                else if (key == IHttpMinRequestBodyDataRateFeatureType)
+                {
+                    feature = _currentIHttpMinRequestBodyDataRateFeature;
+                }
+                else if (key == IHttpMinResponseDataRateFeatureType)
+                {
+                    feature = _currentIHttpMinResponseDataRateFeature;
+                }
+                else if (key == IHttpBodyControlFeatureType)
+                {
+                    feature = _currentIHttpBodyControlFeature;
+                }
+                else if (key == IHttpSendFileFeatureType)
+                {
+                    feature = _currentIHttpSendFileFeature;
+                }
+                else if (MaybeExtra != null)
+                {
+                    feature = ExtraFeatureGet(key);
+                }
+
+                return feature ?? ConnectionFeatures[key];
+            }
+
+            set
+            {
+                _featureRevision++;
+
+                if (key == IHttpRequestFeatureType)
+                {
+                    _currentIHttpRequestFeature = value;
+                }
+                else if (key == IHttpResponseFeatureType)
+                {
+                    _currentIHttpResponseFeature = value;
+                }
+                else if (key == IHttpRequestIdentifierFeatureType)
+                {
+                    _currentIHttpRequestIdentifierFeature = value;
+                }
+                else if (key == IServiceProvidersFeatureType)
+                {
+                    _currentIServiceProvidersFeature = value;
+                }
+                else if (key == IHttpRequestLifetimeFeatureType)
+                {
+                    _currentIHttpRequestLifetimeFeature = value;
+                }
+                else if (key == IHttpConnectionFeatureType)
+                {
+                    _currentIHttpConnectionFeature = value;
+                }
+                else if (key == IHttpAuthenticationFeatureType)
+                {
+                    _currentIHttpAuthenticationFeature = value;
+                }
+                else if (key == IQueryFeatureType)
+                {
+                    _currentIQueryFeature = value;
+                }
+                else if (key == IFormFeatureType)
+                {
+                    _currentIFormFeature = value;
+                }
+                else if (key == IHttpUpgradeFeatureType)
+                {
+                    _currentIHttpUpgradeFeature = value;
+                }
+                else if (key == IHttp2StreamIdFeatureType)
+                {
+                    _currentIHttp2StreamIdFeature = value;
+                }
+                else if (key == IHttpResponseTrailersFeatureType)
+                {
+                    _currentIHttpResponseTrailersFeature = value;
+                }
+                else if (key == IResponseCookiesFeatureType)
+                {
+                    _currentIResponseCookiesFeature = value;
+                }
+                else if (key == IItemsFeatureType)
+                {
+                    _currentIItemsFeature = value;
+                }
+                else if (key == ITlsConnectionFeatureType)
+                {
+                    _currentITlsConnectionFeature = value;
+                }
+                else if (key == IHttpWebSocketFeatureType)
+                {
+                    _currentIHttpWebSocketFeature = value;
+                }
+                else if (key == ISessionFeatureType)
+                {
+                    _currentISessionFeature = value;
+                }
+                else if (key == IHttpMaxRequestBodySizeFeatureType)
+                {
+                    _currentIHttpMaxRequestBodySizeFeature = value;
+                }
+                else if (key == IHttpMinRequestBodyDataRateFeatureType)
+                {
+                    _currentIHttpMinRequestBodyDataRateFeature = value;
+                }
+                else if (key == IHttpMinResponseDataRateFeatureType)
+                {
+                    _currentIHttpMinResponseDataRateFeature = value;
+                }
+                else if (key == IHttpBodyControlFeatureType)
+                {
+                    _currentIHttpBodyControlFeature = value;
+                }
+                else if (key == IHttpSendFileFeatureType)
+                {
+                    _currentIHttpSendFileFeature = value;
+                }
+                else
+                {
+                    ExtraFeatureSet(key, value);
+                }
+            }
+        }
+
+        TFeature IFeatureCollection.Get<TFeature>()
+        {
+            TFeature feature = default;
+            if (typeof(TFeature) == typeof(IHttpRequestFeature))
+            {
+                feature = (TFeature)_currentIHttpRequestFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpResponseFeature))
+            {
+                feature = (TFeature)_currentIHttpResponseFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpRequestIdentifierFeature))
+            {
+                feature = (TFeature)_currentIHttpRequestIdentifierFeature;
+            }
+            else if (typeof(TFeature) == typeof(IServiceProvidersFeature))
+            {
+                feature = (TFeature)_currentIServiceProvidersFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpRequestLifetimeFeature))
+            {
+                feature = (TFeature)_currentIHttpRequestLifetimeFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpConnectionFeature))
+            {
+                feature = (TFeature)_currentIHttpConnectionFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
+            {
+                feature = (TFeature)_currentIHttpAuthenticationFeature;
+            }
+            else if (typeof(TFeature) == typeof(IQueryFeature))
+            {
+                feature = (TFeature)_currentIQueryFeature;
+            }
+            else if (typeof(TFeature) == typeof(IFormFeature))
+            {
+                feature = (TFeature)_currentIFormFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpUpgradeFeature))
+            {
+                feature = (TFeature)_currentIHttpUpgradeFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttp2StreamIdFeature))
+            {
+                feature = (TFeature)_currentIHttp2StreamIdFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpResponseTrailersFeature))
+            {
+                feature = (TFeature)_currentIHttpResponseTrailersFeature;
+            }
+            else if (typeof(TFeature) == typeof(IResponseCookiesFeature))
+            {
+                feature = (TFeature)_currentIResponseCookiesFeature;
+            }
+            else if (typeof(TFeature) == typeof(IItemsFeature))
+            {
+                feature = (TFeature)_currentIItemsFeature;
+            }
+            else if (typeof(TFeature) == typeof(ITlsConnectionFeature))
+            {
+                feature = (TFeature)_currentITlsConnectionFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpWebSocketFeature))
+            {
+                feature = (TFeature)_currentIHttpWebSocketFeature;
+            }
+            else if (typeof(TFeature) == typeof(ISessionFeature))
+            {
+                feature = (TFeature)_currentISessionFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpMaxRequestBodySizeFeature))
+            {
+                feature = (TFeature)_currentIHttpMaxRequestBodySizeFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpMinRequestBodyDataRateFeature))
+            {
+                feature = (TFeature)_currentIHttpMinRequestBodyDataRateFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpMinResponseDataRateFeature))
+            {
+                feature = (TFeature)_currentIHttpMinResponseDataRateFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpBodyControlFeature))
+            {
+                feature = (TFeature)_currentIHttpBodyControlFeature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpSendFileFeature))
+            {
+                feature = (TFeature)_currentIHttpSendFileFeature;
+            }
+            else if (MaybeExtra != null)
+            {
+                feature = (TFeature)(ExtraFeatureGet(typeof(TFeature)));
+            }
+
+            if (feature == null)
+            {
+                feature = ConnectionFeatures.Get<TFeature>();
+            }
+
+            return feature;
+        }
+
+        void IFeatureCollection.Set<TFeature>(TFeature feature)
+        {
+            _featureRevision++;
+            if (typeof(TFeature) == typeof(IHttpRequestFeature))
+            {
+                _currentIHttpRequestFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpResponseFeature))
+            {
+                _currentIHttpResponseFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpRequestIdentifierFeature))
+            {
+                _currentIHttpRequestIdentifierFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IServiceProvidersFeature))
+            {
+                _currentIServiceProvidersFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpRequestLifetimeFeature))
+            {
+                _currentIHttpRequestLifetimeFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpConnectionFeature))
+            {
+                _currentIHttpConnectionFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpAuthenticationFeature))
+            {
+                _currentIHttpAuthenticationFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IQueryFeature))
+            {
+                _currentIQueryFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IFormFeature))
+            {
+                _currentIFormFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpUpgradeFeature))
+            {
+                _currentIHttpUpgradeFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttp2StreamIdFeature))
+            {
+                _currentIHttp2StreamIdFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpResponseTrailersFeature))
+            {
+                _currentIHttpResponseTrailersFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IResponseCookiesFeature))
+            {
+                _currentIResponseCookiesFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IItemsFeature))
+            {
+                _currentIItemsFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(ITlsConnectionFeature))
+            {
+                _currentITlsConnectionFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpWebSocketFeature))
+            {
+                _currentIHttpWebSocketFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(ISessionFeature))
+            {
+                _currentISessionFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpMaxRequestBodySizeFeature))
+            {
+                _currentIHttpMaxRequestBodySizeFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpMinRequestBodyDataRateFeature))
+            {
+                _currentIHttpMinRequestBodyDataRateFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpMinResponseDataRateFeature))
+            {
+                _currentIHttpMinResponseDataRateFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpBodyControlFeature))
+            {
+                _currentIHttpBodyControlFeature = feature;
+            }
+            else if (typeof(TFeature) == typeof(IHttpSendFileFeature))
+            {
+                _currentIHttpSendFileFeature = feature;
+            }
+            else
+            {
+                ExtraFeatureSet(typeof(TFeature), feature);
+            }
+        }
+
+        private IEnumerable<KeyValuePair<Type, object>> FastEnumerable()
+        {
+            if (_currentIHttpRequestFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpRequestFeatureType, _currentIHttpRequestFeature);
+            }
+            if (_currentIHttpResponseFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpResponseFeatureType, _currentIHttpResponseFeature);
+            }
+            if (_currentIHttpRequestIdentifierFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpRequestIdentifierFeatureType, _currentIHttpRequestIdentifierFeature);
+            }
+            if (_currentIServiceProvidersFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IServiceProvidersFeatureType, _currentIServiceProvidersFeature);
+            }
+            if (_currentIHttpRequestLifetimeFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpRequestLifetimeFeatureType, _currentIHttpRequestLifetimeFeature);
+            }
+            if (_currentIHttpConnectionFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpConnectionFeatureType, _currentIHttpConnectionFeature);
+            }
+            if (_currentIHttpAuthenticationFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpAuthenticationFeatureType, _currentIHttpAuthenticationFeature);
+            }
+            if (_currentIQueryFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IQueryFeatureType, _currentIQueryFeature);
+            }
+            if (_currentIFormFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IFormFeatureType, _currentIFormFeature);
+            }
+            if (_currentIHttpUpgradeFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpUpgradeFeatureType, _currentIHttpUpgradeFeature);
+            }
+            if (_currentIHttp2StreamIdFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttp2StreamIdFeatureType, _currentIHttp2StreamIdFeature);
+            }
+            if (_currentIHttpResponseTrailersFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpResponseTrailersFeatureType, _currentIHttpResponseTrailersFeature);
+            }
+            if (_currentIResponseCookiesFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IResponseCookiesFeatureType, _currentIResponseCookiesFeature);
+            }
+            if (_currentIItemsFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IItemsFeatureType, _currentIItemsFeature);
+            }
+            if (_currentITlsConnectionFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(ITlsConnectionFeatureType, _currentITlsConnectionFeature);
+            }
+            if (_currentIHttpWebSocketFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpWebSocketFeatureType, _currentIHttpWebSocketFeature);
+            }
+            if (_currentISessionFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(ISessionFeatureType, _currentISessionFeature);
+            }
+            if (_currentIHttpMaxRequestBodySizeFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpMaxRequestBodySizeFeatureType, _currentIHttpMaxRequestBodySizeFeature);
+            }
+            if (_currentIHttpMinRequestBodyDataRateFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpMinRequestBodyDataRateFeatureType, _currentIHttpMinRequestBodyDataRateFeature);
+            }
+            if (_currentIHttpMinResponseDataRateFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpMinResponseDataRateFeatureType, _currentIHttpMinResponseDataRateFeature);
+            }
+            if (_currentIHttpBodyControlFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpBodyControlFeatureType, _currentIHttpBodyControlFeature);
+            }
+            if (_currentIHttpSendFileFeature != null)
+            {
+                yield return new KeyValuePair<Type, object>(IHttpSendFileFeatureType, _currentIHttpSendFileFeature);
+            }
+
+            if (MaybeExtra != null)
+            {
+                foreach (var item in MaybeExtra)
+                {
+                    yield return item;
+                }
+            }
+        }
+
+        IEnumerator<KeyValuePair<Type, object>> IEnumerable<KeyValuePair<Type, object>>.GetEnumerator() => FastEnumerable().GetEnumerator();
+
+        IEnumerator IEnumerable.GetEnumerator() => FastEnumerable().GetEnumerator();
+    }
+}

+ 1326 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs

@@ -0,0 +1,1326 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Pipelines;
+using System.Linq;
+using System.Net;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Hosting.Server;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Primitives;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public abstract partial class HttpProtocol : IHttpResponseControl
+    {
+        private static readonly byte[] _bytesConnectionClose = Encoding.ASCII.GetBytes("\r\nConnection: close");
+        private static readonly byte[] _bytesConnectionKeepAlive = Encoding.ASCII.GetBytes("\r\nConnection: keep-alive");
+        private static readonly byte[] _bytesTransferEncodingChunked = Encoding.ASCII.GetBytes("\r\nTransfer-Encoding: chunked");
+        private static readonly byte[] _bytesServer = Encoding.ASCII.GetBytes("\r\nServer: " + Constants.ServerName);
+        private static readonly Func<PipeWriter, ReadOnlyMemory<byte>, long> _writeChunk = WriteChunk;
+
+        private readonly object _onStartingSync = new Object();
+        private readonly object _onCompletedSync = new Object();
+
+        protected Streams _streams;
+
+        private Stack<KeyValuePair<Func<object, Task>, object>> _onStarting;
+        private Stack<KeyValuePair<Func<object, Task>, object>> _onCompleted;
+
+        private object _abortLock = new object();
+        private volatile bool _requestAborted;
+        private bool _preventRequestAbortedCancellation;
+        private CancellationTokenSource _abortedCts;
+        private CancellationToken? _manuallySetRequestAbortToken;
+
+        protected RequestProcessingStatus _requestProcessingStatus;
+
+        // Keep-alive is default for HTTP/1.1 and HTTP/2; parsing and errors will change its value
+        // volatile, see: https://msdn.microsoft.com/en-us/library/x13ttww7.aspx
+        protected volatile bool _keepAlive = true;
+        private bool _canHaveBody;
+        private bool _autoChunk;
+        private Exception _applicationException;
+        private BadHttpRequestException _requestRejectedException;
+
+        protected HttpVersion _httpVersion;
+
+        private string _requestId;
+        private int _requestHeadersParsed;
+
+        private long _responseBytesWritten;
+
+        private readonly HttpConnectionContext _context;
+
+        protected string _methodText = null;
+        private string _scheme = null;
+
+        public HttpProtocol(HttpConnectionContext context)
+        {
+            _context = context;
+
+            ServerOptions = ServiceContext.ServerOptions;
+            HttpResponseControl = this;
+        }
+
+        public IHttpResponseControl HttpResponseControl { get; set; }
+
+        public Pipe RequestBodyPipe { get; protected set; }
+
+        public ServiceContext ServiceContext => _context.ServiceContext;
+        private IPEndPoint LocalEndPoint => _context.LocalEndPoint;
+        private IPEndPoint RemoteEndPoint => _context.RemoteEndPoint;
+        public ITimeoutControl TimeoutControl => _context.TimeoutControl;
+
+        public IFeatureCollection ConnectionFeatures => _context.ConnectionFeatures;
+        public IHttpOutputProducer Output { get; protected set; }
+
+        protected IKestrelTrace Log => ServiceContext.Log;
+        private DateHeaderValueManager DateHeaderValueManager => ServiceContext.DateHeaderValueManager;
+        // Hold direct reference to ServerOptions since this is used very often in the request processing path
+        protected KestrelServerOptions ServerOptions { get; }
+        protected string ConnectionId => _context.ConnectionId;
+
+        public string ConnectionIdFeature { get; set; }
+        public bool HasStartedConsumingRequestBody { get; set; }
+        public long? MaxRequestBodySize { get; set; }
+        public bool AllowSynchronousIO { get; set; }
+
+        /// <summary>
+        /// The request id. <seealso cref="HttpContext.TraceIdentifier"/>
+        /// </summary>
+        public string TraceIdentifier
+        {
+            set => _requestId = value;
+            get
+            {
+                // don't generate an ID until it is requested
+                if (_requestId == null)
+                {
+                    _requestId = CreateRequestId();
+                }
+                return _requestId;
+            }
+        }
+
+        public bool IsUpgradableRequest { get; private set; }
+        public bool IsUpgraded { get; set; }
+        public IPAddress RemoteIpAddress { get; set; }
+        public int RemotePort { get; set; }
+        public IPAddress LocalIpAddress { get; set; }
+        public int LocalPort { get; set; }
+        public string Scheme { get; set; }
+        public HttpMethod Method { get; set; }
+        public string PathBase { get; set; }
+        public string Path { get; set; }
+        public string QueryString { get; set; }
+        public string RawTarget { get; set; }
+
+        public string HttpVersion
+        {
+            get
+            {
+                if (_httpVersion == Http.HttpVersion.Http11)
+                {
+                    return HttpUtilities.Http11Version;
+                }
+                if (_httpVersion == Http.HttpVersion.Http10)
+                {
+                    return HttpUtilities.Http10Version;
+                }
+                if (_httpVersion == Http.HttpVersion.Http2)
+                {
+                    return HttpUtilities.Http2Version;
+                }
+
+                return string.Empty;
+            }
+
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            set
+            {
+                // GetKnownVersion returns versions which ReferenceEquals interned string
+                // As most common path, check for this only in fast-path and inline
+                if (ReferenceEquals(value, HttpUtilities.Http11Version))
+                {
+                    _httpVersion = Http.HttpVersion.Http11;
+                }
+                else if (ReferenceEquals(value, HttpUtilities.Http10Version))
+                {
+                    _httpVersion = Http.HttpVersion.Http10;
+                }
+                else if (ReferenceEquals(value, HttpUtilities.Http2Version))
+                {
+                    _httpVersion = Http.HttpVersion.Http2;
+                }
+                else
+                {
+                    HttpVersionSetSlow(value);
+                }
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void HttpVersionSetSlow(string value)
+        {
+            if (value == HttpUtilities.Http11Version)
+            {
+                _httpVersion = Http.HttpVersion.Http11;
+            }
+            else if (value == HttpUtilities.Http10Version)
+            {
+                _httpVersion = Http.HttpVersion.Http10;
+            }
+            else if (value == HttpUtilities.Http2Version)
+            {
+                _httpVersion = Http.HttpVersion.Http2;
+            }
+            else
+            {
+                _httpVersion = Http.HttpVersion.Unknown;
+            }
+        }
+
+        public IHeaderDictionary RequestHeaders { get; set; }
+        public Stream RequestBody { get; set; }
+
+        private int _statusCode;
+        public int StatusCode
+        {
+            get => _statusCode;
+            set
+            {
+                if (HasResponseStarted)
+                {
+                    ThrowResponseAlreadyStartedException(nameof(StatusCode));
+                }
+
+                _statusCode = value;
+            }
+        }
+
+        private string _reasonPhrase;
+
+        public string ReasonPhrase
+        {
+            get => _reasonPhrase;
+
+            set
+            {
+                if (HasResponseStarted)
+                {
+                    ThrowResponseAlreadyStartedException(nameof(ReasonPhrase));
+                }
+
+                _reasonPhrase = value;
+            }
+        }
+
+        public IHeaderDictionary ResponseHeaders { get; set; }
+        public Stream ResponseBody { get; set; }
+
+        public CancellationToken RequestAborted
+        {
+            get
+            {
+                // If a request abort token was previously explicitly set, return it.
+                if (_manuallySetRequestAbortToken.HasValue)
+                {
+                    return _manuallySetRequestAbortToken.Value;
+                }
+
+                lock (_abortLock)
+                {
+                    if (_preventRequestAbortedCancellation)
+                    {
+                        return new CancellationToken(false);
+                    }
+
+                    if (_requestAborted)
+                    {
+                        return new CancellationToken(true);
+                    }
+
+                    if (_abortedCts == null)
+                    {
+                        _abortedCts = new CancellationTokenSource();
+                    }
+
+                    return _abortedCts.Token;
+                }
+            }
+            set
+            {
+                // Set an abort token, overriding one we create internally.  This setter and associated
+                // field exist purely to support IHttpRequestLifetimeFeature.set_RequestAborted.
+                _manuallySetRequestAbortToken = value;
+            }
+        }
+
+        public bool HasResponseStarted => _requestProcessingStatus == RequestProcessingStatus.ResponseStarted;
+
+        protected HttpRequestHeaders HttpRequestHeaders { get; } = new HttpRequestHeaders();
+
+        protected HttpResponseHeaders HttpResponseHeaders { get; } = new HttpResponseHeaders();
+
+        public void InitializeStreams(MessageBody messageBody)
+        {
+            if (_streams == null)
+            {
+                _streams = new Streams(bodyControl: this, httpResponseControl: this);
+            }
+
+            (RequestBody, ResponseBody) = _streams.Start(messageBody);
+        }
+
+        public void StopStreams() => _streams.Stop();
+
+        // For testing
+        internal void ResetState()
+        {
+            _requestProcessingStatus = RequestProcessingStatus.RequestPending;
+        }
+
+        public void Reset()
+        {
+            _onStarting = null;
+            _onCompleted = null;
+
+            _requestProcessingStatus = RequestProcessingStatus.RequestPending;
+            _autoChunk = false;
+            _applicationException = null;
+            _requestRejectedException = null;
+
+            ResetFeatureCollection();
+
+            HasStartedConsumingRequestBody = false;
+            MaxRequestBodySize = ServerOptions.Limits.MaxRequestBodySize;
+            AllowSynchronousIO = ServerOptions.AllowSynchronousIO;
+            TraceIdentifier = null;
+            Method = HttpMethod.None;
+            _methodText = null;
+            PathBase = null;
+            Path = null;
+            RawTarget = null;
+            QueryString = null;
+            _httpVersion = Http.HttpVersion.Unknown;
+            _statusCode = StatusCodes.Status200OK;
+            _reasonPhrase = null;
+
+            var remoteEndPoint = RemoteEndPoint;
+            RemoteIpAddress = remoteEndPoint?.Address;
+            RemotePort = remoteEndPoint?.Port ?? 0;
+
+            var localEndPoint = LocalEndPoint;
+            LocalIpAddress = localEndPoint?.Address;
+            LocalPort = localEndPoint?.Port ?? 0;
+
+            ConnectionIdFeature = ConnectionId;
+
+            HttpRequestHeaders.Reset();
+            HttpResponseHeaders.Reset();
+            RequestHeaders = HttpRequestHeaders;
+            ResponseHeaders = HttpResponseHeaders;
+
+            if (_scheme == null)
+            {
+                var tlsFeature = ConnectionFeatures?[typeof(ITlsConnectionFeature)];
+                _scheme = tlsFeature != null ? "https" : "http";
+            }
+
+            Scheme = _scheme;
+
+            _manuallySetRequestAbortToken = null;
+            _preventRequestAbortedCancellation = false;
+
+            // Lock to prevent CancelRequestAbortedToken from attempting to cancel an disposed CTS.
+            lock (_abortLock)
+            {
+                if (!_requestAborted)
+                {
+                    _abortedCts?.Dispose();
+                    _abortedCts = null;
+                }
+            }
+
+            _requestHeadersParsed = 0;
+
+            _responseBytesWritten = 0;
+
+            OnReset();
+        }
+
+        protected abstract void OnReset();
+
+        protected virtual void OnRequestProcessingEnding()
+        {
+        }
+
+        protected virtual void OnRequestProcessingEnded()
+        {
+        }
+
+        protected virtual void BeginRequestProcessing()
+        {
+        }
+
+        protected virtual void OnErrorAfterResponseStarted()
+        {
+        }
+
+        protected virtual bool BeginRead(out ValueTask<ReadResult> awaitable)
+        {
+            awaitable = default;
+            return false;
+        }
+
+        protected abstract string CreateRequestId();
+
+        protected abstract MessageBody CreateMessageBody();
+
+        protected abstract bool TryParseRequest(ReadResult result, out bool endConnection);
+
+        private void CancelRequestAbortedToken()
+        {
+            try
+            {
+                _abortedCts.Cancel();
+                _abortedCts.Dispose();
+                _abortedCts = null;
+            }
+            catch (Exception ex)
+            {
+                Log.ApplicationError(ConnectionId, TraceIdentifier, ex);
+            }
+        }
+
+        protected void AbortRequest()
+        {
+            lock (_abortLock)
+            {
+                if (_requestAborted)
+                {
+                    return;
+                }
+
+                _requestAborted = true;
+            }
+
+            if (_abortedCts != null)
+            {
+                // Potentially calling user code. CancelRequestAbortedToken logs any exceptions.
+                ServiceContext.Scheduler.Schedule(state => ((HttpProtocol)state).CancelRequestAbortedToken(), this);
+            }
+        }
+
+        protected void PoisonRequestBodyStream(Exception abortReason)
+        {
+            _streams?.Abort(abortReason);
+        }
+
+        // Prevents the RequestAborted token from firing for the duration of the request.
+        private void PreventRequestAbortedCancellation()
+        {
+            lock (_abortLock)
+            {
+                if (_requestAborted)
+                {
+                    return;
+                }
+
+                _preventRequestAbortedCancellation = true;
+                _abortedCts?.Dispose();
+                _abortedCts = null;
+            }
+        }
+
+        public void OnHeader(Span<byte> name, Span<byte> value)
+        {
+            _requestHeadersParsed++;
+            if (_requestHeadersParsed > ServerOptions.Limits.MaxRequestHeaderCount)
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.TooManyHeaders);
+            }
+            var valueString = value.GetAsciiOrUTF8StringNonNullCharacters();
+
+            HttpRequestHeaders.Append(name, valueString);
+        }
+
+        public async Task ProcessRequestsAsync<TContext>(IHttpApplication<TContext> application)
+        {
+            try
+            {
+                await ProcessRequests(application);
+            }
+            catch (BadHttpRequestException ex)
+            {
+                // Handle BadHttpRequestException thrown during request line or header parsing.
+                // SetBadRequestState logs the error.
+                SetBadRequestState(ex);
+            }
+            catch (ConnectionResetException ex)
+            {
+                // Don't log ECONNRESET errors made between requests. Browsers like IE will reset connections regularly.
+                if (_requestProcessingStatus != RequestProcessingStatus.RequestPending)
+                {
+                    Log.RequestProcessingError(ConnectionId, ex);
+                }
+            }
+            catch (IOException ex)
+            {
+                Log.RequestProcessingError(ConnectionId, ex);
+            }
+            catch (Exception ex)
+            {
+                Log.LogWarning(0, ex, CoreStrings.RequestProcessingEndError);
+            }
+            finally
+            {
+                try
+                {
+                    await TryProduceInvalidRequestResponse();
+                }
+                catch (Exception ex)
+                {
+                    Log.LogWarning(0, ex, CoreStrings.ConnectionShutdownError);
+                }
+                finally
+                {
+                    OnRequestProcessingEnded();
+                }
+            }
+        }
+
+        private async Task ProcessRequests<TContext>(IHttpApplication<TContext> application)
+        {
+            while (_keepAlive)
+            {
+                BeginRequestProcessing();
+
+                var result = default(ReadResult);
+                var endConnection = false;
+                do
+                {
+                    if (BeginRead(out var awaitable))
+                    {
+                        result = await awaitable;
+                    }
+                } while (!TryParseRequest(result, out endConnection));
+
+                if (endConnection)
+                {
+                    // Connection finished, stop processing requests
+                    return;
+                }
+
+                var messageBody = CreateMessageBody();
+                if (!messageBody.RequestKeepAlive)
+                {
+                    _keepAlive = false;
+                }
+
+                IsUpgradableRequest = messageBody.RequestUpgrade;
+
+                InitializeStreams(messageBody);
+
+                var httpContext = application.CreateContext(this);
+
+                try
+                {
+                    KestrelEventSource.Log.RequestStart(this);
+
+                    // Run the application code for this request
+                    await application.ProcessRequestAsync(httpContext);
+
+                    if (!_requestAborted)
+                    {
+                        VerifyResponseContentLength();
+                    }
+                }
+                catch (BadHttpRequestException ex)
+                {
+                    // Capture BadHttpRequestException for further processing
+                    // This has to be caught here so StatusCode is set properly before disposing the HttpContext
+                    // (DisposeContext logs StatusCode).
+                    SetBadRequestState(ex);
+                    ReportApplicationError(ex);
+                }
+                catch (Exception ex)
+                {
+                    ReportApplicationError(ex);
+                }
+
+                KestrelEventSource.Log.RequestStop(this);
+
+                // Trigger OnStarting if it hasn't been called yet and the app hasn't
+                // already failed. If an OnStarting callback throws we can go through
+                // our normal error handling in ProduceEnd.
+                // https://github.com/aspnet/KestrelHttpServer/issues/43
+                if (!HasResponseStarted && _applicationException == null && _onStarting != null)
+                {
+                    await FireOnStarting();
+                }
+
+                // At this point all user code that needs use to the request or response streams has completed.
+                // Using these streams in the OnCompleted callback is not allowed.
+                StopStreams();
+
+                // 4XX responses are written by TryProduceInvalidRequestResponse during connection tear down.
+                if (_requestRejectedException == null)
+                {
+                    if (!_requestAborted)
+                    {
+                        // Call ProduceEnd() before consuming the rest of the request body to prevent
+                        // delaying clients waiting for the chunk terminator:
+                        //
+                        // https://github.com/dotnet/corefx/issues/17330#issuecomment-288248663
+                        //
+                        // This also prevents the 100 Continue response from being sent if the app
+                        // never tried to read the body.
+                        // https://github.com/aspnet/KestrelHttpServer/issues/2102
+                        //
+                        // ProduceEnd() must be called before _application.DisposeContext(), to ensure
+                        // HttpContext.Response.StatusCode is correctly set when
+                        // IHttpContextFactory.Dispose(HttpContext) is called.
+                        await ProduceEnd();
+                    }
+                    else if (!HasResponseStarted)
+                    {
+                        // If the request was aborted and no response was sent, there's no
+                        // meaningful status code to log.
+                        StatusCode = 0;
+                    }
+                }
+
+                if (_onCompleted != null)
+                {
+                    await FireOnCompleted();
+                }
+
+                application.DisposeContext(httpContext, _applicationException);
+
+                // Even for non-keep-alive requests, try to consume the entire body to avoid RSTs.
+                if (!_requestAborted && _requestRejectedException == null && !messageBody.IsEmpty)
+                {
+                    await messageBody.ConsumeAsync();
+                }
+
+                if (HasStartedConsumingRequestBody)
+                {
+                    RequestBodyPipe.Reader.Complete();
+
+                    // Wait for Http1MessageBody.PumpAsync() to call RequestBodyPipe.Writer.Complete().
+                    await messageBody.StopAsync();
+                }
+            }
+        }
+
+        public void OnStarting(Func<object, Task> callback, object state)
+        {
+            lock (_onStartingSync)
+            {
+                if (HasResponseStarted)
+                {
+                    ThrowResponseAlreadyStartedException(nameof(OnStarting));
+                }
+
+                if (_onStarting == null)
+                {
+                    _onStarting = new Stack<KeyValuePair<Func<object, Task>, object>>();
+                }
+                _onStarting.Push(new KeyValuePair<Func<object, Task>, object>(callback, state));
+            }
+        }
+
+        public void OnCompleted(Func<object, Task> callback, object state)
+        {
+            lock (_onCompletedSync)
+            {
+                if (_onCompleted == null)
+                {
+                    _onCompleted = new Stack<KeyValuePair<Func<object, Task>, object>>();
+                }
+                _onCompleted.Push(new KeyValuePair<Func<object, Task>, object>(callback, state));
+            }
+        }
+
+        protected Task FireOnStarting()
+        {
+            Stack<KeyValuePair<Func<object, Task>, object>> onStarting;
+            lock (_onStartingSync)
+            {
+                onStarting = _onStarting;
+                _onStarting = null;
+            }
+
+            if (onStarting == null)
+            {
+                return Task.CompletedTask;
+            }
+            else
+            {
+                return FireOnStartingMayAwait(onStarting);
+            }
+
+        }
+
+        private Task FireOnStartingMayAwait(Stack<KeyValuePair<Func<object, Task>, object>> onStarting)
+        {
+            try
+            {
+                var count = onStarting.Count;
+                for (var i = 0; i < count; i++)
+                {
+                    var entry = onStarting.Pop();
+                    var task = entry.Key.Invoke(entry.Value);
+                    if (!ReferenceEquals(task, Task.CompletedTask))
+                    {
+                        return FireOnStartingAwaited(task, onStarting);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                ReportApplicationError(ex);
+            }
+
+            return Task.CompletedTask;
+        }
+
+        private async Task FireOnStartingAwaited(Task currentTask, Stack<KeyValuePair<Func<object, Task>, object>> onStarting)
+        {
+            try
+            {
+                await currentTask;
+
+                var count = onStarting.Count;
+                for (var i = 0; i < count; i++)
+                {
+                    var entry = onStarting.Pop();
+                    await entry.Key.Invoke(entry.Value);
+                }
+            }
+            catch (Exception ex)
+            {
+                ReportApplicationError(ex);
+            }
+        }
+
+        protected Task FireOnCompleted()
+        {
+            Stack<KeyValuePair<Func<object, Task>, object>> onCompleted;
+            lock (_onCompletedSync)
+            {
+                onCompleted = _onCompleted;
+                _onCompleted = null;
+            }
+
+            if (onCompleted == null)
+            {
+                return Task.CompletedTask;
+            }
+
+            return FireOnCompletedAwaited(onCompleted);
+        }
+
+        private async Task FireOnCompletedAwaited(Stack<KeyValuePair<Func<object, Task>, object>> onCompleted)
+        {
+            foreach (var entry in onCompleted)
+            {
+                try
+                {
+                    await entry.Key.Invoke(entry.Value);
+                }
+                catch (Exception ex)
+                {
+                    Log.ApplicationError(ConnectionId, TraceIdentifier, ex);
+                }
+            }
+        }
+
+        public Task FlushAsync(CancellationToken cancellationToken = default(CancellationToken))
+        {
+            if (!HasResponseStarted)
+            {
+                var initializeTask = InitializeResponseAsync(0);
+                // If return is Task.CompletedTask no awaiting is required
+                if (!ReferenceEquals(initializeTask, Task.CompletedTask))
+                {
+                    return FlushAsyncAwaited(initializeTask, cancellationToken);
+                }
+            }
+
+            return Output.FlushAsync(cancellationToken);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private async Task FlushAsyncAwaited(Task initializeTask, CancellationToken cancellationToken)
+        {
+            await initializeTask;
+            await Output.FlushAsync(cancellationToken);
+        }
+
+        public Task WriteAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken = default(CancellationToken))
+        {
+            // For the first write, ensure headers are flushed if WriteDataAsync isn't called.
+            var firstWrite = !HasResponseStarted;
+
+            if (firstWrite)
+            {
+                var initializeTask = InitializeResponseAsync(data.Length);
+                // If return is Task.CompletedTask no awaiting is required
+                if (!ReferenceEquals(initializeTask, Task.CompletedTask))
+                {
+                    return WriteAsyncAwaited(initializeTask, data, cancellationToken);
+                }
+            }
+            else
+            {
+                VerifyAndUpdateWrite(data.Length);
+            }
+
+            if (_canHaveBody)
+            {
+                if (_autoChunk)
+                {
+                    if (data.Length == 0)
+                    {
+                        return !firstWrite ? Task.CompletedTask : FlushAsync(cancellationToken);
+                    }
+                    return WriteChunkedAsync(data, cancellationToken);
+                }
+                else
+                {
+                    CheckLastWrite();
+                    return Output.WriteDataAsync(data.Span, cancellationToken: cancellationToken);
+                }
+            }
+            else
+            {
+                HandleNonBodyResponseWrite();
+                return !firstWrite ? Task.CompletedTask : FlushAsync(cancellationToken);
+            }
+        }
+
+        public async Task WriteAsyncAwaited(Task initializeTask, ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
+        {
+            await initializeTask;
+
+            // WriteAsyncAwaited is only called for the first write to the body.
+            // Ensure headers are flushed if Write(Chunked)Async isn't called.
+            if (_canHaveBody)
+            {
+                if (_autoChunk)
+                {
+                    if (data.Length == 0)
+                    {
+                        await FlushAsync(cancellationToken);
+                        return;
+                    }
+
+                    await WriteChunkedAsync(data, cancellationToken);
+                }
+                else
+                {
+                    CheckLastWrite();
+                    await Output.WriteDataAsync(data.Span, cancellationToken: cancellationToken);
+                }
+            }
+            else
+            {
+                HandleNonBodyResponseWrite();
+                await FlushAsync(cancellationToken);
+            }
+        }
+
+        private void VerifyAndUpdateWrite(int count)
+        {
+            var responseHeaders = HttpResponseHeaders;
+
+            if (responseHeaders != null &&
+                !responseHeaders.HasTransferEncoding &&
+                responseHeaders.ContentLength.HasValue &&
+                _responseBytesWritten + count > responseHeaders.ContentLength.Value)
+            {
+                _keepAlive = false;
+                ThrowTooManyBytesWritten(count);
+            }
+
+            _responseBytesWritten += count;
+        }
+
+        [StackTraceHidden]
+        private void ThrowTooManyBytesWritten(int count)
+        {
+            throw GetTooManyBytesWrittenException(count);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private InvalidOperationException GetTooManyBytesWrittenException(int count)
+        {
+            var responseHeaders = HttpResponseHeaders;
+            return new InvalidOperationException(
+                CoreStrings.FormatTooManyBytesWritten(_responseBytesWritten + count, responseHeaders.ContentLength.Value));
+        }
+
+        private void CheckLastWrite()
+        {
+            var responseHeaders = HttpResponseHeaders;
+
+            // Prevent firing request aborted token if this is the last write, to avoid
+            // aborting the request if the app is still running when the client receives
+            // the final bytes of the response and gracefully closes the connection.
+            //
+            // Called after VerifyAndUpdateWrite(), so _responseBytesWritten has already been updated.
+            if (responseHeaders != null &&
+                !responseHeaders.HasTransferEncoding &&
+                responseHeaders.ContentLength.HasValue &&
+                _responseBytesWritten == responseHeaders.ContentLength.Value)
+            {
+                PreventRequestAbortedCancellation();
+            }
+        }
+
+        protected void VerifyResponseContentLength()
+        {
+            var responseHeaders = HttpResponseHeaders;
+
+            if (Method != HttpMethod.Head &&
+                StatusCode != StatusCodes.Status304NotModified &&
+                !responseHeaders.HasTransferEncoding &&
+                responseHeaders.ContentLength.HasValue &&
+                _responseBytesWritten < responseHeaders.ContentLength.Value)
+            {
+                // We need to close the connection if any bytes were written since the client
+                // cannot be certain of how many bytes it will receive.
+                if (_responseBytesWritten > 0)
+                {
+                    _keepAlive = false;
+                }
+
+                ReportApplicationError(new InvalidOperationException(
+                    CoreStrings.FormatTooFewBytesWritten(_responseBytesWritten, responseHeaders.ContentLength.Value)));
+            }
+        }
+
+        private Task WriteChunkedAsync(ReadOnlyMemory<byte> data, CancellationToken cancellationToken)
+        {
+            return Output.WriteAsync(_writeChunk, data, cancellationToken);
+        }
+
+        private static long WriteChunk(PipeWriter writableBuffer, ReadOnlyMemory<byte> buffer)
+        {
+            var bytesWritten = 0L;
+            if (buffer.Length > 0)
+            {
+                var writer = new BufferWriter<PipeWriter>(writableBuffer);
+
+                ChunkWriter.WriteBeginChunkBytes(ref writer, buffer.Length);
+                writer.Write(buffer.Span);
+                ChunkWriter.WriteEndChunkBytes(ref writer);
+                writer.Commit();
+
+                bytesWritten = writer.BytesCommitted;
+            }
+
+            return bytesWritten;
+        }
+
+        private static ArraySegment<byte> CreateAsciiByteArraySegment(string text)
+        {
+            var bytes = Encoding.ASCII.GetBytes(text);
+            return new ArraySegment<byte>(bytes);
+        }
+
+        public void ProduceContinue()
+        {
+            if (HasResponseStarted)
+            {
+                return;
+            }
+
+            if (_httpVersion != Http.HttpVersion.Http10 &&
+                RequestHeaders.TryGetValue("Expect", out var expect) &&
+                (expect.FirstOrDefault() ?? "").Equals("100-continue", StringComparison.OrdinalIgnoreCase))
+            {
+                Output.Write100ContinueAsync().GetAwaiter().GetResult();
+            }
+        }
+
+        public Task InitializeResponseAsync(int firstWriteByteCount)
+        {
+            var startingTask = FireOnStarting();
+            // If return is Task.CompletedTask no awaiting is required
+            if (!ReferenceEquals(startingTask, Task.CompletedTask))
+            {
+                return InitializeResponseAwaited(startingTask, firstWriteByteCount);
+            }
+
+            if (_applicationException != null)
+            {
+                ThrowResponseAbortedException();
+            }
+
+            VerifyAndUpdateWrite(firstWriteByteCount);
+            ProduceStart(appCompleted: false);
+
+            return Task.CompletedTask;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        public async Task InitializeResponseAwaited(Task startingTask, int firstWriteByteCount)
+        {
+            await startingTask;
+
+            if (_applicationException != null)
+            {
+                ThrowResponseAbortedException();
+            }
+
+            VerifyAndUpdateWrite(firstWriteByteCount);
+            ProduceStart(appCompleted: false);
+        }
+
+        private void ProduceStart(bool appCompleted)
+        {
+            if (HasResponseStarted)
+            {
+                return;
+            }
+
+            _requestProcessingStatus = RequestProcessingStatus.ResponseStarted;
+
+            CreateResponseHeader(appCompleted);
+        }
+
+        protected Task TryProduceInvalidRequestResponse()
+        {
+            // If _requestAborted is set, the connection has already been closed.
+            if (_requestRejectedException != null && !_requestAborted)
+            {
+                return ProduceEnd();
+            }
+
+            return Task.CompletedTask;
+        }
+
+        protected Task ProduceEnd()
+        {
+            if (_requestRejectedException != null || _applicationException != null)
+            {
+                if (HasResponseStarted)
+                {
+                    // We can no longer change the response, so we simply close the connection.
+                    _keepAlive = false;
+                    OnErrorAfterResponseStarted();
+                    return Task.CompletedTask;
+                }
+
+                // If the request was rejected, the error state has already been set by SetBadRequestState and
+                // that should take precedence.
+                if (_requestRejectedException != null)
+                {
+                    SetErrorResponseException(_requestRejectedException);
+                }
+                else
+                {
+                    // 500 Internal Server Error
+                    SetErrorResponseHeaders(statusCode: StatusCodes.Status500InternalServerError);
+                }
+            }
+
+            if (!HasResponseStarted)
+            {
+                return ProduceEndAwaited();
+            }
+
+            return WriteSuffix();
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private async Task ProduceEndAwaited()
+        {
+            ProduceStart(appCompleted: true);
+
+            // Force flush
+            await Output.FlushAsync(default(CancellationToken));
+
+            await WriteSuffix();
+        }
+
+        private Task WriteSuffix()
+        {
+            // _autoChunk should be checked after we are sure ProduceStart() has been called
+            // since ProduceStart() may set _autoChunk to true.
+            if (_autoChunk || _httpVersion == Http.HttpVersion.Http2)
+            {
+                return WriteSuffixAwaited();
+            }
+
+            if (_keepAlive)
+            {
+                Log.ConnectionKeepAlive(ConnectionId);
+            }
+
+            if (Method == HttpMethod.Head && _responseBytesWritten > 0)
+            {
+                Log.ConnectionHeadResponseBodyWrite(ConnectionId, _responseBytesWritten);
+            }
+
+            return Task.CompletedTask;
+        }
+
+        private async Task WriteSuffixAwaited()
+        {
+            // For the same reason we call CheckLastWrite() in Content-Length responses.
+            PreventRequestAbortedCancellation();
+
+            await Output.WriteStreamSuffixAsync();
+
+            if (_keepAlive)
+            {
+                Log.ConnectionKeepAlive(ConnectionId);
+            }
+
+            if (Method == HttpMethod.Head && _responseBytesWritten > 0)
+            {
+                Log.ConnectionHeadResponseBodyWrite(ConnectionId, _responseBytesWritten);
+            }
+        }
+
+        private void CreateResponseHeader(bool appCompleted)
+        {
+            var responseHeaders = HttpResponseHeaders;
+            var hasConnection = responseHeaders.HasConnection;
+            var connectionOptions = HttpHeaders.ParseConnection(responseHeaders.HeaderConnection);
+            var hasTransferEncoding = responseHeaders.HasTransferEncoding;
+
+            if (_keepAlive && hasConnection && (connectionOptions & ConnectionOptions.KeepAlive) != ConnectionOptions.KeepAlive)
+            {
+                _keepAlive = false;
+            }
+
+            // https://tools.ietf.org/html/rfc7230#section-3.3.1
+            // If any transfer coding other than
+            // chunked is applied to a response payload body, the sender MUST either
+            // apply chunked as the final transfer coding or terminate the message
+            // by closing the connection.
+            if (hasTransferEncoding &&
+                HttpHeaders.GetFinalTransferCoding(responseHeaders.HeaderTransferEncoding) != TransferCoding.Chunked)
+            {
+                _keepAlive = false;
+            }
+
+            // Set whether response can have body
+            _canHaveBody = StatusCanHaveBody(StatusCode) && Method != HttpMethod.Head;
+
+            // Don't set the Content-Length or Transfer-Encoding headers
+            // automatically for HEAD requests or 204, 205, 304 responses.
+            if (_canHaveBody)
+            {
+                if (!hasTransferEncoding && !responseHeaders.ContentLength.HasValue)
+                {
+                    if (appCompleted && StatusCode != StatusCodes.Status101SwitchingProtocols)
+                    {
+                        // Since the app has completed and we are only now generating
+                        // the headers we can safely set the Content-Length to 0.
+                        responseHeaders.ContentLength = 0;
+                    }
+                    else
+                    {
+                        // Note for future reference: never change this to set _autoChunk to true on HTTP/1.0
+                        // connections, even if we were to infer the client supports it because an HTTP/1.0 request
+                        // was received that used chunked encoding. Sending a chunked response to an HTTP/1.0
+                        // client would break compliance with RFC 7230 (section 3.3.1):
+                        //
+                        // A server MUST NOT send a response containing Transfer-Encoding unless the corresponding
+                        // request indicates HTTP/1.1 (or later).
+                        //
+                        // This also covers HTTP/2, which forbids chunked encoding in RFC 7540 (section 8.1:
+                        //
+                        // The chunked transfer encoding defined in Section 4.1 of [RFC7230] MUST NOT be used in HTTP/2.
+                        if (_httpVersion == Http.HttpVersion.Http11 && StatusCode != StatusCodes.Status101SwitchingProtocols)
+                        {
+                            _autoChunk = true;
+                            responseHeaders.SetRawTransferEncoding("chunked", _bytesTransferEncodingChunked);
+                        }
+                        else
+                        {
+                            _keepAlive = false;
+                        }
+                    }
+                }
+            }
+            else if (hasTransferEncoding)
+            {
+                RejectNonBodyTransferEncodingResponse(appCompleted);
+            }
+
+            responseHeaders.SetReadOnly();
+
+            if (!hasConnection && _httpVersion != Http.HttpVersion.Http2)
+            {
+                if (!_keepAlive)
+                {
+                    responseHeaders.SetRawConnection("close", _bytesConnectionClose);
+                }
+                else if (_httpVersion == Http.HttpVersion.Http10)
+                {
+                    responseHeaders.SetRawConnection("keep-alive", _bytesConnectionKeepAlive);
+                }
+            }
+
+            if (ServerOptions.AddServerHeader && !responseHeaders.HasServer)
+            {
+                responseHeaders.SetRawServer(Constants.ServerName, _bytesServer);
+            }
+
+            if (!responseHeaders.HasDate)
+            {
+                var dateHeaderValues = DateHeaderValueManager.GetDateHeaderValues();
+                responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);
+            }
+
+            Output.WriteResponseHeaders(StatusCode, ReasonPhrase, responseHeaders);
+        }
+
+        public bool StatusCanHaveBody(int statusCode)
+        {
+            // List of status codes taken from Microsoft.Net.Http.Server.Response
+            return statusCode != StatusCodes.Status204NoContent &&
+                   statusCode != StatusCodes.Status205ResetContent &&
+                   statusCode != StatusCodes.Status304NotModified;
+        }
+
+        private void ThrowResponseAlreadyStartedException(string value)
+        {
+            throw new InvalidOperationException(CoreStrings.FormatParameterReadOnlyAfterResponseStarted(value));
+        }
+
+        private void RejectNonBodyTransferEncodingResponse(bool appCompleted)
+        {
+            var ex = new InvalidOperationException(CoreStrings.FormatHeaderNotAllowedOnResponse("Transfer-Encoding", StatusCode));
+            if (!appCompleted)
+            {
+                // Back out of header creation surface exception in user code
+                _requestProcessingStatus = RequestProcessingStatus.AppStarted;
+                throw ex;
+            }
+            else
+            {
+                ReportApplicationError(ex);
+
+                // 500 Internal Server Error
+                SetErrorResponseHeaders(statusCode: StatusCodes.Status500InternalServerError);
+            }
+        }
+
+        private void SetErrorResponseException(BadHttpRequestException ex)
+        {
+            SetErrorResponseHeaders(ex.StatusCode);
+
+            if (!StringValues.IsNullOrEmpty(ex.AllowedHeader))
+            {
+                HttpResponseHeaders.HeaderAllow = ex.AllowedHeader;
+            }
+        }
+
+        private void SetErrorResponseHeaders(int statusCode)
+        {
+            Debug.Assert(!HasResponseStarted, $"{nameof(SetErrorResponseHeaders)} called after response had already started.");
+
+            StatusCode = statusCode;
+            ReasonPhrase = null;
+
+            var responseHeaders = HttpResponseHeaders;
+            responseHeaders.Reset();
+            var dateHeaderValues = DateHeaderValueManager.GetDateHeaderValues();
+
+            responseHeaders.SetRawDate(dateHeaderValues.String, dateHeaderValues.Bytes);
+
+            responseHeaders.ContentLength = 0;
+
+            if (ServerOptions.AddServerHeader)
+            {
+                responseHeaders.SetRawServer(Constants.ServerName, _bytesServer);
+            }
+        }
+
+        public void HandleNonBodyResponseWrite()
+        {
+            // Writes to HEAD response are ignored and logged at the end of the request
+            if (Method != HttpMethod.Head)
+            {
+                ThrowWritingToResponseBodyNotSupported();
+            }
+        }
+
+        [StackTraceHidden]
+        private void ThrowWritingToResponseBodyNotSupported()
+        {
+            // Throw Exception for 204, 205, 304 responses.
+            throw new InvalidOperationException(CoreStrings.FormatWritingToResponseBodyNotSupported(StatusCode));
+        }
+
+        [StackTraceHidden]
+        private void ThrowResponseAbortedException()
+        {
+            throw new ObjectDisposedException(CoreStrings.UnhandledApplicationException, _applicationException);
+        }
+
+        [StackTraceHidden]
+        public void ThrowRequestTargetRejected(Span<byte> target)
+            => throw GetInvalidRequestTargetException(target);
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private BadHttpRequestException GetInvalidRequestTargetException(Span<byte> target)
+            => BadHttpRequestException.GetException(
+                RequestRejectionReason.InvalidRequestTarget,
+                Log.IsEnabled(LogLevel.Information)
+                    ? target.GetAsciiStringEscaped(Constants.MaxExceptionDetailSize)
+                    : string.Empty);
+
+        public void SetBadRequestState(BadHttpRequestException ex)
+        {
+            Log.ConnectionBadRequest(ConnectionId, ex);
+
+            if (!HasResponseStarted)
+            {
+                SetErrorResponseException(ex);
+            }
+
+            _keepAlive = false;
+            _requestRejectedException = ex;
+        }
+
+        protected void ReportApplicationError(Exception ex)
+        {
+            if (_applicationException == null)
+            {
+                _applicationException = ex;
+            }
+            else if (_applicationException is AggregateException)
+            {
+                _applicationException = new AggregateException(_applicationException, ex).Flatten();
+            }
+            else
+            {
+                _applicationException = new AggregateException(_applicationException, ex);
+            }
+
+            Log.ApplicationError(ConnectionId, TraceIdentifier, ex);
+        }
+    }
+}

+ 101 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestHeaders.cs

@@ -0,0 +1,101 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.Extensions.Primitives;
+using Microsoft.Net.Http.Headers;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public partial class HttpRequestHeaders : HttpHeaders
+    {
+        private static long ParseContentLength(string value)
+        {
+            if (!HeaderUtilities.TryParseNonNegativeInt64(value, out var parsed))
+            {
+                BadHttpRequestException.Throw(RequestRejectionReason.InvalidContentLength, value);
+            }
+
+            return parsed;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void SetValueUnknown(string key, in StringValues value)
+        {
+            Unknown[key] = value;
+        }
+
+        public unsafe void Append(Span<byte> 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)
+        {
+            string key = new string('\0', keyLength);
+            fixed (char* keyBuffer = key)
+            {
+                if (!StringUtilities.TryGetAsciiString(pKeyBytes, keyBuffer, keyLength))
+                {
+                    BadHttpRequestException.Throw(RequestRejectionReason.InvalidCharactersInHeaderName);
+                }
+            }
+
+            Unknown.TryGetValue(key, out var existing);
+            Unknown[key] = AppendValue(existing, value);
+        }
+
+        public Enumerator GetEnumerator()
+        {
+            return new Enumerator(this);
+        }
+
+        protected override IEnumerator<KeyValuePair<string, StringValues>> GetEnumeratorFast()
+        {
+            return GetEnumerator();
+        }
+
+        public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>
+        {
+            private readonly HttpRequestHeaders _collection;
+            private readonly long _bits;
+            private int _state;
+            private KeyValuePair<string, StringValues> _current;
+            private readonly bool _hasUnknown;
+            private Dictionary<string, StringValues>.Enumerator _unknownEnumerator;
+
+            internal Enumerator(HttpRequestHeaders collection)
+            {
+                _collection = collection;
+                _bits = collection._bits;
+                _state = 0;
+                _current = default(KeyValuePair<string, StringValues>);
+                _hasUnknown = collection.MaybeUnknown != null;
+                _unknownEnumerator = _hasUnknown
+                    ? collection.MaybeUnknown.GetEnumerator()
+                    : default(Dictionary<string, StringValues>.Enumerator);
+            }
+
+            public KeyValuePair<string, StringValues> Current => _current;
+
+            object IEnumerator.Current => _current;
+
+            public void Dispose()
+            {
+            }
+
+            public void Reset()
+            {
+                _state = 0;
+            }
+        }
+    }
+}

+ 224 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestStream.cs

@@ -0,0 +1,224 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Connections;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    internal class HttpRequestStream : ReadOnlyStream
+    {
+        private readonly IHttpBodyControlFeature _bodyControl;
+        private MessageBody _body;
+        private HttpStreamState _state;
+        private Exception _error;
+
+        public HttpRequestStream(IHttpBodyControlFeature bodyControl)
+        {
+            _bodyControl = bodyControl;
+            _state = HttpStreamState.Closed;
+        }
+
+        public override bool CanSeek => false;
+
+        public override long Length
+            => throw new NotSupportedException();
+
+        public override long Position
+        {
+            get => throw new NotSupportedException();
+            set => throw new NotSupportedException();
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override Task FlushAsync(CancellationToken cancellationToken)
+        {
+            return Task.CompletedTask;
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            if (!_bodyControl.AllowSynchronousIO)
+            {
+                throw new InvalidOperationException(CoreStrings.SynchronousReadsDisallowed);
+            }
+
+            return ReadAsync(buffer, offset, count).GetAwaiter().GetResult();
+        }
+
+        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            var task = ReadAsync(buffer, offset, count, default(CancellationToken), state);
+            if (callback != null)
+            {
+                task.ContinueWith(t => callback.Invoke(t));
+            }
+            return task;
+        }
+
+        public override int EndRead(IAsyncResult asyncResult)
+        {
+            return ((Task<int>)asyncResult).GetAwaiter().GetResult();
+        }
+
+        private Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
+        {
+            var tcs = new TaskCompletionSource<int>(state);
+            var task = ReadAsync(buffer, offset, count, cancellationToken);
+            task.ContinueWith((task2, state2) =>
+            {
+                var tcs2 = (TaskCompletionSource<int>)state2;
+                if (task2.IsCanceled)
+                {
+                    tcs2.SetCanceled();
+                }
+                else if (task2.IsFaulted)
+                {
+                    tcs2.SetException(task2.Exception);
+                }
+                else
+                {
+                    tcs2.SetResult(task2.Result);
+                }
+            }, tcs, cancellationToken);
+            return tcs.Task;
+        }
+
+        public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            ValidateState(cancellationToken);
+
+            return ReadAsyncInternal(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
+        }
+
+#if NETCOREAPP2_1
+        public override ValueTask<int> ReadAsync(Memory<byte> destination, CancellationToken cancellationToken = default)
+        {
+            ValidateState(cancellationToken);
+
+            return ReadAsyncInternal(destination, cancellationToken);
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        private async ValueTask<int> ReadAsyncInternal(Memory<byte> buffer, CancellationToken cancellationToken)
+        {
+            try
+            {
+                return await _body.ReadAsync(buffer, cancellationToken);
+            }
+            catch (ConnectionAbortedException ex)
+            {
+                throw new TaskCanceledException("The request was aborted", ex);
+            }
+        }
+
+        public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+        {
+            if (destination == null)
+            {
+                throw new ArgumentNullException(nameof(destination));
+            }
+            if (bufferSize <= 0)
+            {
+                throw new ArgumentException(CoreStrings.PositiveNumberRequired, nameof(bufferSize));
+            }
+
+            ValidateState(cancellationToken);
+
+            return CopyToAsyncInternal(destination, cancellationToken);
+        }
+
+        private async Task CopyToAsyncInternal(Stream destination, CancellationToken cancellationToken)
+        {
+            try
+            {
+                await _body.CopyToAsync(destination, cancellationToken);
+            }
+            catch (ConnectionAbortedException ex)
+            {
+                throw new TaskCanceledException("The request was aborted", ex);
+            }
+        }
+
+        public void StartAcceptingReads(MessageBody body)
+        {
+            // Only start if not aborted
+            if (_state == HttpStreamState.Closed)
+            {
+                _state = HttpStreamState.Open;
+                _body = body;
+            }
+        }
+
+        public void StopAcceptingReads()
+        {
+            // Can't use dispose (or close) as can be disposed too early by user code
+            // As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
+            _state = HttpStreamState.Closed;
+            _body = null;
+        }
+
+        public void Abort(Exception error = null)
+        {
+            // We don't want to throw an ODE until the app func actually completes.
+            // If the request is aborted, we throw a TaskCanceledException instead,
+            // unless error is not null, in which case we throw it.
+            if (_state != HttpStreamState.Closed)
+            {
+                _state = HttpStreamState.Aborted;
+                _error = error;
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private void ValidateState(CancellationToken cancellationToken)
+        {
+            var state = _state;
+            if (state == HttpStreamState.Open)
+            {
+                cancellationToken.ThrowIfCancellationRequested();
+            }
+            else if (state == HttpStreamState.Closed)
+            {
+                ThrowObjectDisposedException();
+            }
+            else
+            {
+                if (_error != null)
+                {
+                    ExceptionDispatchInfo.Capture(_error).Throw();
+                }
+                else
+                {
+                    ThrowTaskCanceledException();
+                }
+            }
+
+            void ThrowObjectDisposedException() => throw new ObjectDisposedException(nameof(HttpRequestStream));
+            void ThrowTaskCanceledException() => throw new TaskCanceledException();
+        }
+    }
+}

+ 15 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpRequestTargetForm.cs

@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public enum HttpRequestTarget
+    {
+        Unknown = -1,
+        // origin-form is the most common
+        OriginForm,
+        AbsoluteForm,
+        AuthorityForm,
+        AsteriskForm
+    }
+}

+ 109 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseHeaders.cs

@@ -0,0 +1,109 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Buffers;
+using System.IO.Pipelines;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using Microsoft.Extensions.Primitives;
+using Microsoft.Net.Http.Headers;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    public partial class HttpResponseHeaders : HttpHeaders
+    {
+        private static readonly byte[] _CrLf = new[] { (byte)'\r', (byte)'\n' };
+        private static readonly byte[] _colonSpace = new[] { (byte)':', (byte)' ' };
+
+        public Enumerator GetEnumerator()
+        {
+            return new Enumerator(this);
+        }
+
+        protected override IEnumerator<KeyValuePair<string, StringValues>> GetEnumeratorFast()
+        {
+            return GetEnumerator();
+        }
+
+        internal void CopyTo(ref BufferWriter<PipeWriter> buffer)
+        {
+            CopyToFast(ref buffer);
+            if (MaybeUnknown != null)
+            {
+                foreach (var kv in MaybeUnknown)
+                {
+                    foreach (var value in kv.Value)
+                    {
+                        if (value != null)
+                        {
+                            buffer.Write(_CrLf);
+                            PipelineExtensions.WriteAsciiNoValidation(ref buffer, kv.Key);
+                            buffer.Write(_colonSpace);
+                            PipelineExtensions.WriteAsciiNoValidation(ref buffer, value);
+                        }
+                    }
+                }
+            }
+        }
+
+        private static long ParseContentLength(string value)
+        {
+            if (!HeaderUtilities.TryParseNonNegativeInt64(value, out var parsed))
+            {
+                ThrowInvalidContentLengthException(value);
+            }
+
+            return parsed;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void SetValueUnknown(string key, in StringValues value)
+        {
+            ValidateHeaderNameCharacters(key);
+            Unknown[key] = value;
+        }
+
+        private static void ThrowInvalidContentLengthException(string value)
+        {
+            throw new InvalidOperationException(CoreStrings.FormatInvalidContentLength_InvalidNumber(value));
+        }
+
+        public partial struct Enumerator : IEnumerator<KeyValuePair<string, StringValues>>
+        {
+            private readonly HttpResponseHeaders _collection;
+            private readonly long _bits;
+            private int _state;
+            private KeyValuePair<string, StringValues> _current;
+            private readonly bool _hasUnknown;
+            private Dictionary<string, StringValues>.Enumerator _unknownEnumerator;
+
+            internal Enumerator(HttpResponseHeaders collection)
+            {
+                _collection = collection;
+                _bits = collection._bits;
+                _state = 0;
+                _current = default;
+                _hasUnknown = collection.MaybeUnknown != null;
+                _unknownEnumerator = _hasUnknown
+                    ? collection.MaybeUnknown.GetEnumerator()
+                    : default;
+            }
+
+            public KeyValuePair<string, StringValues> Current => _current;
+
+            object IEnumerator.Current => _current;
+
+            public void Dispose()
+            {
+            }
+
+            public void Reset()
+            {
+                _state = 0;
+            }
+        }
+
+    }
+}

+ 172 - 0
src/Servers/Kestrel/Core/src/Internal/Http/HttpResponseStream.cs

@@ -0,0 +1,172 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
+using Microsoft.AspNetCore.Http.Features;
+
+namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
+{
+    internal class HttpResponseStream : WriteOnlyStream
+    {
+        private readonly IHttpBodyControlFeature _bodyControl;
+        private readonly IHttpResponseControl _httpResponseControl;
+        private HttpStreamState _state;
+
+        public HttpResponseStream(IHttpBodyControlFeature bodyControl, IHttpResponseControl httpResponseControl)
+        {
+            _bodyControl = bodyControl;
+            _httpResponseControl = httpResponseControl;
+            _state = HttpStreamState.Closed;
+        }
+
+        public override bool CanSeek => false;
+
+        public override long Length
+            => throw new NotSupportedException();
+
+        public override long Position
+        {
+            get => throw new NotSupportedException();
+            set => throw new NotSupportedException();
+        }
+
+        public override void Flush()
+        {
+            FlushAsync(default(CancellationToken)).GetAwaiter().GetResult();
+        }
+
+        public override Task FlushAsync(CancellationToken cancellationToken)
+        {
+            ValidateState(cancellationToken);
+
+            return _httpResponseControl.FlushAsync(cancellationToken);
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            if (!_bodyControl.AllowSynchronousIO)
+            {
+                throw new InvalidOperationException(CoreStrings.SynchronousWritesDisallowed);
+            }
+
+            WriteAsync(buffer, offset, count, default(CancellationToken)).GetAwaiter().GetResult();
+        }
+
+        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
+        {
+            var task = WriteAsync(buffer, offset, count, default(CancellationToken), state);
+            if (callback != null)
+            {
+                task.ContinueWith(t => callback.Invoke(t));
+            }
+            return task;
+        }
+
+        public override void EndWrite(IAsyncResult asyncResult)
+        {
+            ((Task<object>)asyncResult).GetAwaiter().GetResult();
+        }
+
+        private Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken, object state)
+        {
+            var tcs = new TaskCompletionSource<object>(state);
+            var task = WriteAsync(buffer, offset, count, cancellationToken);
+            task.ContinueWith((task2, state2) =>
+            {
+                var tcs2 = (TaskCompletionSource<object>)state2;
+                if (task2.IsCanceled)
+                {
+                    tcs2.SetCanceled();
+                }
+                else if (task2.IsFaulted)
+                {
+                    tcs2.SetException(task2.Exception);
+                }
+                else
+                {
+                    tcs2.SetResult(null);
+                }
+            }, tcs, cancellationToken);
+            return tcs.Task;
+        }
+
+        public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+        {
+            ValidateState(cancellationToken);
+
+            return _httpResponseControl.WriteAsync(new ReadOnlyMemory<byte>(buffer, offset, count), cancellationToken);
+        }
+
+#if NETCOREAPP2_1
+        public override ValueTask WriteAsync(ReadOnlyMemory<byte> source, CancellationToken cancellationToken = default)
+        {
+            ValidateState(cancellationToken);
+
+            return new ValueTask(_httpResponseControl.WriteAsync(source, cancellationToken));
+        }
+#elif NETSTANDARD2_0
+#else
+#error TFMs need to be updated
+#endif
+
+        public void StartAcceptingWrites()
+        {
+            // Only start if not aborted
+            if (_state == HttpStreamState.Closed)
+            {
+                _state = HttpStreamState.Open;
+            }
+        }
+
+        public void StopAcceptingWrites()
+        {
+            // Can't use dispose (or close) as can be disposed too early by user code
+            // As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
+            _state = HttpStreamState.Closed;
+        }
+
+        public void Abort()
+        {
+            // We don't want to throw an ODE until the app func actually completes.
+            if (_state != HttpStreamState.Closed)
+            {
+                _state = HttpStreamState.Aborted;
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private void ValidateState(CancellationToken cancellationToken)
+        {
+            var state = _state;
+            if (state == HttpStreamState.Open || state == HttpStreamState.Aborted)
+            {
+                // Aborted state only throws on write if cancellationToken requests it
+                cancellationToken.ThrowIfCancellationRequested();
+            }
+            else
+            {
+                ThrowObjectDisposedException();
+            }
+
+            void ThrowObjectDisposedException()
+            {
+                throw new ObjectDisposedException(nameof(HttpResponseStream), CoreStrings.WritingToResponseBodyAfterResponseCompleted);
+            }
+        }
+    }
+}

Some files were not shown because too many files changed in this diff