diff --git a/samples/Http2SampleApp/Http2SampleApp.csproj b/samples/Http2SampleApp/Http2SampleApp.csproj index 683e6e4041..cd660a6c80 100644 --- a/samples/Http2SampleApp/Http2SampleApp.csproj +++ b/samples/Http2SampleApp/Http2SampleApp.csproj @@ -15,7 +15,9 @@ - + + PreserveNewest + diff --git a/samples/Http2SampleApp/testCert.pfx b/samples/Http2SampleApp/testCert.pfx new file mode 100644 index 0000000000..7118908c2d Binary files /dev/null and b/samples/Http2SampleApp/testCert.pfx differ diff --git a/src/Kestrel.Core/Features/ITlsApplicationProtocolFeature.cs b/src/Kestrel.Core/Features/ITlsApplicationProtocolFeature.cs index 7ad37730d5..8adca3f0e8 100644 --- a/src/Kestrel.Core/Features/ITlsApplicationProtocolFeature.cs +++ b/src/Kestrel.Core/Features/ITlsApplicationProtocolFeature.cs @@ -1,11 +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 { - // TODO: this should be merged with ITlsConnectionFeature public interface ITlsApplicationProtocolFeature { - string ApplicationProtocol { get; } + ReadOnlyMemory ApplicationProtocol { get; } } } diff --git a/src/Kestrel.Core/Internal/HttpConnection.cs b/src/Kestrel.Core/Internal/HttpConnection.cs index 1ac4945ae4..fcd2c314a8 100644 --- a/src/Kestrel.Core/Internal/HttpConnection.cs +++ b/src/Kestrel.Core/Internal/HttpConnection.cs @@ -23,6 +23,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal { public class HttpConnection : ITimeoutControl, IConnectionTimeoutFeature, IRequestProcessor { + private static readonly ReadOnlyMemory Http2Id = new ReadOnlyMemory(new[] { (byte)'h', (byte)'2' }); + private readonly HttpConnectionContext _context; private readonly TaskCompletionSource _socketClosedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -303,7 +305,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal private HttpProtocols SelectProtocol() { var hasTls = _context.ConnectionFeatures.Get() != null; - var applicationProtocol = _context.ConnectionFeatures.Get()?.ApplicationProtocol; + var applicationProtocol = _context.ConnectionFeatures.Get()?.ApplicationProtocol + ?? new ReadOnlyMemory(); var http1Enabled = (_context.Protocols & HttpProtocols.Http1) == HttpProtocols.Http1; var http2Enabled = (_context.Protocols & HttpProtocols.Http2) == HttpProtocols.Http2; @@ -319,7 +322,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal error = CoreStrings.EndPointRequiresTlsForHttp1AndHttp2; } - if (!http1Enabled && http2Enabled && hasTls && applicationProtocol != "h2") + if (!http1Enabled && http2Enabled && hasTls && !Http2Id.SequenceEqual(applicationProtocol)) { error = CoreStrings.EndPointHttp2NotNegotiated; } @@ -330,7 +333,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal return HttpProtocols.None; } - return http2Enabled && (!hasTls || applicationProtocol == "h2") ? HttpProtocols.Http2 : HttpProtocols.Http1; + return http2Enabled && (!hasTls || Http2Id.SequenceEqual(applicationProtocol)) ? HttpProtocols.Http2 : HttpProtocols.Http1; } public void Tick(DateTimeOffset now) diff --git a/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs b/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs index cae7d60b2f..5022462886 100644 --- a/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs +++ b/src/Kestrel.Core/Internal/HttpsConnectionAdapter.cs @@ -160,20 +160,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https.Internal } #if NETCOREAPP2_1 - // Don't allocate in the common case, see https://github.com/dotnet/corefx/issues/25432 - if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http11) - { - feature.ApplicationProtocol = "http/1.1"; - } - else if (sslStream.NegotiatedApplicationProtocol == SslApplicationProtocol.Http2) - { - feature.ApplicationProtocol = "h2"; - } - else - { - feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.ToString(); - } - + feature.ApplicationProtocol = sslStream.NegotiatedApplicationProtocol.Protocol; context.Features.Set(feature); #endif feature.ClientCertificate = ConvertToX509Certificate2(sslStream.RemoteCertificate); diff --git a/src/Kestrel.Core/Internal/TlsConnectionFeature.cs b/src/Kestrel.Core/Internal/TlsConnectionFeature.cs index d5d7983d8e..a914024131 100644 --- a/src/Kestrel.Core/Internal/TlsConnectionFeature.cs +++ b/src/Kestrel.Core/Internal/TlsConnectionFeature.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Https.Internal { public X509Certificate2 ClientCertificate { get; set; } - public string ApplicationProtocol { get; set; } + public ReadOnlyMemory ApplicationProtocol { get; set; } public Task GetClientCertificateAsync(CancellationToken cancellationToken) { diff --git a/src/Kestrel.Core/Kestrel.Core.csproj b/src/Kestrel.Core/Kestrel.Core.csproj index 2f6ea2a3bb..59b66b7373 100644 --- a/src/Kestrel.Core/Kestrel.Core.csproj +++ b/src/Kestrel.Core/Kestrel.Core.csproj @@ -4,7 +4,7 @@ Microsoft.AspNetCore.Server.Kestrel.Core Microsoft.AspNetCore.Server.Kestrel.Core Core components of ASP.NET Core Kestrel cross-platform web server. - netstandard2.0 + netstandard2.0;netcoreapp2.1 true aspnetcore;kestrel true