diff --git a/samples/Http2SampleApp/Program.cs b/samples/Http2SampleApp/Program.cs
index bdb49b0a50..e95177afe5 100644
--- a/samples/Http2SampleApp/Program.cs
+++ b/samples/Http2SampleApp/Program.cs
@@ -1,4 +1,4 @@
-using System.Globalization;
+using System;
using System.IO;
using System.Net;
using Microsoft.AspNetCore.Hosting;
@@ -13,6 +13,8 @@ namespace Http2SampleApp
{
public static void Main(string[] args)
{
+ AppContext.SetSwitch("Switch.Microsoft.AspNetCore.Server.Kestrel.Experimental.Http2", isEnabled: true);
+
var hostBuilder = new WebHostBuilder()
.ConfigureLogging((_, factory) =>
{
diff --git a/samples/Http2SampleApp/Startup.cs b/samples/Http2SampleApp/Startup.cs
index 6dce6b8a19..904e07cbb8 100644
--- a/samples/Http2SampleApp/Startup.cs
+++ b/samples/Http2SampleApp/Startup.cs
@@ -1,7 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
@@ -11,18 +7,16 @@ namespace Http2SampleApp
{
public class Startup
{
- // This method gets called by the runtime. Use this method to add services to the container.
- // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+
public void ConfigureServices(IServiceCollection services)
{
}
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
- app.Run(async (context) =>
+ app.Run(context =>
{
- await context.Response.WriteAsync("Hello World!");
+ return context.Response.WriteAsync("Hello World! " + context.Request.Protocol);
});
}
}
diff --git a/src/Kestrel.Core/CoreStrings.resx b/src/Kestrel.Core/CoreStrings.resx
index 2babfee801..e369a2d122 100644
--- a/src/Kestrel.Core/CoreStrings.resx
+++ b/src/Kestrel.Core/CoreStrings.resx
@@ -495,4 +495,7 @@
The endpoint {endpointName} specified multiple certificate sources.
+
+ HTTP/2 support is experimental, see https://go.microsoft.com/fwlink/?linkid=866785 to enable it.
+
\ No newline at end of file
diff --git a/src/Kestrel.Core/ListenOptions.cs b/src/Kestrel.Core/ListenOptions.cs
index 08e728a35c..0ed675aac8 100644
--- a/src/Kestrel.Core/ListenOptions.cs
+++ b/src/Kestrel.Core/ListenOptions.cs
@@ -19,13 +19,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
///
public class ListenOptions : IEndPointInformation, IConnectionBuilder
{
+ internal const string Http2ExperimentSwitch = "Switch.Microsoft.AspNetCore.Server.Kestrel.Experimental.Http2";
+
private FileHandleType _handleType;
+ private HttpProtocols _protocols = HttpProtocols.Http1;
+ internal bool _isHttp2Supported;
private readonly List> _components = new List>();
internal ListenOptions(IPEndPoint endPoint)
{
Type = ListenType.IPEndPoint;
IPEndPoint = endPoint;
+ AppContext.TryGetSwitch(Http2ExperimentSwitch, out _isHttp2Supported);
}
internal ListenOptions(string socketPath)
@@ -122,8 +127,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
///
/// The protocols enabled on this endpoint.
///
- /// Defaults to HTTP/1.x only.
- public HttpProtocols Protocols { get; set; } = HttpProtocols.Http1;
+ /// Defaults to HTTP/1.x only. HTTP/2 support is experimental, see
+ /// https://go.microsoft.com/fwlink/?linkid=866785 to enable it.
+ public HttpProtocols Protocols
+ {
+ get => _protocols;
+ set
+ {
+ if (!_isHttp2Supported && (value == HttpProtocols.Http1AndHttp2 || value == HttpProtocols.Http2))
+ {
+ throw new NotSupportedException(CoreStrings.Http2NotSupported);
+ }
+ _protocols = value;
+ }
+ }
///
/// Gets the that allows each connection
diff --git a/src/Kestrel.Core/Properties/CoreStrings.Designer.cs b/src/Kestrel.Core/Properties/CoreStrings.Designer.cs
index ff2732087f..1df67ddf4f 100644
--- a/src/Kestrel.Core/Properties/CoreStrings.Designer.cs
+++ b/src/Kestrel.Core/Properties/CoreStrings.Designer.cs
@@ -1774,6 +1774,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
internal static string FormatMultipleCertificateSources(object endpointName)
=> string.Format(CultureInfo.CurrentCulture, GetString("MultipleCertificateSources", "endpointName"), endpointName);
+ ///
+ /// HTTP/2 support is experimental, see https://go.microsoft.com/fwlink/?linkid=866785 to enable it.
+ ///
+ internal static string Http2NotSupported
+ {
+ get => GetString("Http2NotSupported");
+ }
+
+ ///
+ /// HTTP/2 support is experimental, see https://go.microsoft.com/fwlink/?linkid=866785 to enable it.
+ ///
+ internal static string FormatHttp2NotSupported()
+ => GetString("Http2NotSupported");
+
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
diff --git a/test/Kestrel.Core.Tests/ListenOptionsTests.cs b/test/Kestrel.Core.Tests/ListenOptionsTests.cs
index 89d495876f..808d4e6cdd 100644
--- a/test/Kestrel.Core.Tests/ListenOptionsTests.cs
+++ b/test/Kestrel.Core.Tests/ListenOptionsTests.cs
@@ -1,6 +1,7 @@
// 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;
using Xunit;
@@ -14,5 +15,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
Assert.Equal(HttpProtocols.Http1, listenOptions.Protocols);
}
+
+ [Fact]
+ public void Http2DisabledByDefault()
+ {
+ var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
+ var ex = Assert.Throws(() => listenOptions.Protocols = HttpProtocols.Http1AndHttp2);
+ Assert.Equal(CoreStrings.Http2NotSupported, ex.Message);
+ ex = Assert.Throws(() => listenOptions.Protocols = HttpProtocols.Http2);
+ Assert.Equal(CoreStrings.Http2NotSupported, ex.Message);
+ }
}
}
diff --git a/test/Kestrel.FunctionalTests/HttpProtocolSelectionTests.cs b/test/Kestrel.FunctionalTests/HttpProtocolSelectionTests.cs
index c2dd742c1d..198ba040f3 100644
--- a/test/Kestrel.FunctionalTests/HttpProtocolSelectionTests.cs
+++ b/test/Kestrel.FunctionalTests/HttpProtocolSelectionTests.cs
@@ -48,7 +48,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var builder = TransportSelector.GetWebHostBuilder()
.UseKestrel(options =>
{
- options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols);
+ options.Listen(IPAddress.Loopback, 0, listenOptions =>
+ {
+ listenOptions._isHttp2Supported = true;
+ listenOptions.Protocols = serverProtocols;
+ });
})
.Configure(app => app.Run(context => Task.CompletedTask));
@@ -75,7 +79,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var builder = TransportSelector.GetWebHostBuilder()
.ConfigureLogging(loggingBuilder => loggingBuilder.AddProvider(loggerProvider.Object))
- .UseKestrel(options => options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols))
+ .UseKestrel(options => options.Listen(IPAddress.Loopback, 0, listenOptions =>
+ {
+ listenOptions._isHttp2Supported = true;
+ listenOptions.Protocols = serverProtocols;
+ }))
.Configure(app => app.Run(context => Task.CompletedTask));
using (var host = builder.Build())