Configure enabled protocols per endpoint and add HTTP/2 w/ prior knowledge support (#2067).
This commit is contained in:
parent
eb9417b577
commit
551c1ebc0b
|
|
@ -351,4 +351,13 @@
|
||||||
<data name="PositiveFiniteTimeSpanRequired" xml:space="preserve">
|
<data name="PositiveFiniteTimeSpanRequired" xml:space="preserve">
|
||||||
<value>Timespan must be positive and finite.</value>
|
<value>Timespan must be positive and finite.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="EndPointRequiresAtLeastOneProtocol" xml:space="preserve">
|
||||||
|
<value>An endpoint must be configured to serve at least one protocol.</value>
|
||||||
|
</data>
|
||||||
|
<data name="EndPointRequiresTlsForHttp1AndHttp2" xml:space="preserve">
|
||||||
|
<value>Using both HTTP/1.x and HTTP/2 on the same endpoint requires the use of TLS.</value>
|
||||||
|
</data>
|
||||||
|
<data name="EndPointHttp2NotNegotiated" xml:space="preserve">
|
||||||
|
<value>HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
|
|
@ -135,8 +136,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
adaptedPipelineTask = adaptedPipeline.RunAsync(stream);
|
adaptedPipelineTask = adaptedPipeline.RunAsync(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_http1Connection.ConnectionFeatures.Get<ITlsApplicationProtocolFeature>()?.ApplicationProtocol == "h2" &&
|
var protocol = SelectProtocol();
|
||||||
Interlocked.CompareExchange(ref _http2ConnectionState, Http2ConnectionStarted, Http2ConnectionNotStarted) == Http2ConnectionNotStarted)
|
|
||||||
|
if (protocol == HttpProtocols.None)
|
||||||
|
{
|
||||||
|
Abort(ex: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One of these has to run even if no protocol was selected so the abort propagates and everything completes properly
|
||||||
|
if (protocol == HttpProtocols.Http2 && Interlocked.CompareExchange(ref _http2ConnectionState, Http2ConnectionStarted, Http2ConnectionNotStarted) == Http2ConnectionNotStarted)
|
||||||
{
|
{
|
||||||
await _http2Connection.ProcessAsync(httpApplication);
|
await _http2Connection.ProcessAsync(httpApplication);
|
||||||
}
|
}
|
||||||
|
|
@ -207,6 +215,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
public Task StopProcessingNextRequestAsync()
|
public Task StopProcessingNextRequestAsync()
|
||||||
{
|
{
|
||||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||||
|
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||||
|
|
||||||
if (Interlocked.Exchange(ref _http2ConnectionState, Http2ConnectionClosed) == Http2ConnectionStarted)
|
if (Interlocked.Exchange(ref _http2ConnectionState, Http2ConnectionClosed) == Http2ConnectionStarted)
|
||||||
{
|
{
|
||||||
|
|
@ -223,6 +232,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
public void Abort(Exception ex)
|
public void Abort(Exception ex)
|
||||||
{
|
{
|
||||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||||
|
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||||
|
|
||||||
// Abort the connection (if not already aborted)
|
// Abort the connection (if not already aborted)
|
||||||
if (Interlocked.Exchange(ref _http2ConnectionState, Http2ConnectionClosed) == Http2ConnectionStarted)
|
if (Interlocked.Exchange(ref _http2ConnectionState, Http2ConnectionClosed) == Http2ConnectionStarted)
|
||||||
|
|
@ -245,6 +255,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
public void SendTimeoutResponse()
|
public void SendTimeoutResponse()
|
||||||
{
|
{
|
||||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||||
|
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||||
|
|
||||||
RequestTimedOut = true;
|
RequestTimedOut = true;
|
||||||
_http1Connection.SendTimeoutResponse();
|
_http1Connection.SendTimeoutResponse();
|
||||||
|
|
@ -253,6 +264,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
public void StopProcessingNextRequest()
|
public void StopProcessingNextRequest()
|
||||||
{
|
{
|
||||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||||
|
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||||
|
|
||||||
_http1Connection.StopProcessingNextRequest();
|
_http1Connection.StopProcessingNextRequest();
|
||||||
}
|
}
|
||||||
|
|
@ -260,10 +272,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
private async Task<Stream> ApplyConnectionAdaptersAsync()
|
private async Task<Stream> ApplyConnectionAdaptersAsync()
|
||||||
{
|
{
|
||||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||||
|
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||||
|
|
||||||
var connectionAdapters = _context.ConnectionAdapters;
|
var connectionAdapters = _context.ConnectionAdapters;
|
||||||
var stream = new RawStream(_context.Transport.Input, _context.Transport.Output);
|
var stream = new RawStream(_context.Transport.Input, _context.Transport.Output);
|
||||||
var adapterContext = new ConnectionAdapterContext(_http1Connection.ConnectionFeatures, stream);
|
var adapterContext = new ConnectionAdapterContext(_context.ConnectionFeatures, stream);
|
||||||
_adaptedConnections = new List<IAdaptedConnection>(connectionAdapters.Count);
|
_adaptedConnections = new List<IAdaptedConnection>(connectionAdapters.Count);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -272,7 +285,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
var adaptedConnection = await connectionAdapters[i].OnConnectionAsync(adapterContext);
|
var adaptedConnection = await connectionAdapters[i].OnConnectionAsync(adapterContext);
|
||||||
_adaptedConnections.Add(adaptedConnection);
|
_adaptedConnections.Add(adaptedConnection);
|
||||||
adapterContext = new ConnectionAdapterContext(_http1Connection.ConnectionFeatures, adaptedConnection.ConnectionStream);
|
adapterContext = new ConnectionAdapterContext(_context.ConnectionFeatures, adaptedConnection.ConnectionStream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -290,16 +303,50 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
var adaptedConnections = _adaptedConnections;
|
var adaptedConnections = _adaptedConnections;
|
||||||
if (adaptedConnections != null)
|
if (adaptedConnections != null)
|
||||||
{
|
{
|
||||||
for (int i = adaptedConnections.Count - 1; i >= 0; i--)
|
for (var i = adaptedConnections.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
adaptedConnections[i].Dispose();
|
adaptedConnections[i].Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HttpProtocols SelectProtocol()
|
||||||
|
{
|
||||||
|
var hasTls = _context.ConnectionFeatures.Get<ITlsConnectionFeature>() != null;
|
||||||
|
var applicationProtocol = _context.ConnectionFeatures.Get<ITlsApplicationProtocolFeature>()?.ApplicationProtocol;
|
||||||
|
var http1Enabled = (_context.Protocols & HttpProtocols.Http1) == HttpProtocols.Http1;
|
||||||
|
var http2Enabled = (_context.Protocols & HttpProtocols.Http2) == HttpProtocols.Http2;
|
||||||
|
|
||||||
|
string error = null;
|
||||||
|
|
||||||
|
if (_context.Protocols == HttpProtocols.None)
|
||||||
|
{
|
||||||
|
error = CoreStrings.EndPointRequiresAtLeastOneProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasTls && http1Enabled && http2Enabled)
|
||||||
|
{
|
||||||
|
error = CoreStrings.EndPointRequiresTlsForHttp1AndHttp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!http1Enabled && http2Enabled && hasTls && applicationProtocol != "h2")
|
||||||
|
{
|
||||||
|
error = CoreStrings.EndPointHttp2NotNegotiated;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
Log.LogError(0, error);
|
||||||
|
return HttpProtocols.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return http2Enabled && (!hasTls || applicationProtocol == "h2") ? HttpProtocols.Http2 : HttpProtocols.Http1;
|
||||||
|
}
|
||||||
|
|
||||||
public void Tick(DateTimeOffset now)
|
public void Tick(DateTimeOffset now)
|
||||||
{
|
{
|
||||||
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
Debug.Assert(_http1Connection != null, $"{nameof(_http1Connection)} is null");
|
||||||
|
Debug.Assert(_http2Connection != null, $"{nameof(_http2Connection)} is null");
|
||||||
|
|
||||||
var timestamp = now.Ticks;
|
var timestamp = now.Ticks;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
// 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.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNetCore.Hosting.Server;
|
using Microsoft.AspNetCore.Hosting.Server;
|
||||||
using Microsoft.AspNetCore.Protocols;
|
using Microsoft.AspNetCore.Protocols;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
||||||
|
|
@ -9,14 +11,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
public static class HttpConnectionBuilderExtensions
|
public static class HttpConnectionBuilderExtensions
|
||||||
{
|
{
|
||||||
public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, ServiceContext serviceContext, IHttpApplication<TContext> application)
|
public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols)
|
||||||
{
|
{
|
||||||
return builder.UseHttpServer(Array.Empty<IConnectionAdapter>(), serviceContext, application);
|
return builder.UseHttpServer(Array.Empty<IConnectionAdapter>(), serviceContext, application, protocols);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, IList<IConnectionAdapter> adapters, ServiceContext serviceContext, IHttpApplication<TContext> application)
|
public static IConnectionBuilder UseHttpServer<TContext>(this IConnectionBuilder builder, IList<IConnectionAdapter> adapters, ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols)
|
||||||
{
|
{
|
||||||
var middleware = new HttpConnectionMiddleware<TContext>(adapters, serviceContext, application);
|
var middleware = new HttpConnectionMiddleware<TContext>(adapters, serviceContext, application, protocols);
|
||||||
return builder.Use(next =>
|
return builder.Use(next =>
|
||||||
{
|
{
|
||||||
return middleware.OnConnectionAsync;
|
return middleware.OnConnectionAsync;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
public string ConnectionId { get; set; }
|
public string ConnectionId { get; set; }
|
||||||
public long HttpConnectionId { get; set; }
|
public long HttpConnectionId { get; set; }
|
||||||
|
public HttpProtocols Protocols { get; set; }
|
||||||
public ServiceContext ServiceContext { get; set; }
|
public ServiceContext ServiceContext { get; set; }
|
||||||
public IFeatureCollection ConnectionFeatures { get; set; }
|
public IFeatureCollection ConnectionFeatures { get; set; }
|
||||||
public IList<IConnectionAdapter> ConnectionAdapters { get; set; }
|
public IList<IConnectionAdapter> ConnectionAdapters { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO.Pipelines;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -8,6 +9,8 @@ using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Protocols;
|
using Microsoft.AspNetCore.Protocols;
|
||||||
using Microsoft.AspNetCore.Protocols.Features;
|
using Microsoft.AspNetCore.Protocols.Features;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
|
|
@ -20,11 +23,13 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
private readonly IList<IConnectionAdapter> _connectionAdapters;
|
private readonly IList<IConnectionAdapter> _connectionAdapters;
|
||||||
private readonly ServiceContext _serviceContext;
|
private readonly ServiceContext _serviceContext;
|
||||||
private readonly IHttpApplication<TContext> _application;
|
private readonly IHttpApplication<TContext> _application;
|
||||||
|
private readonly HttpProtocols _protocols;
|
||||||
|
|
||||||
public HttpConnectionMiddleware(IList<IConnectionAdapter> adapters, ServiceContext serviceContext, IHttpApplication<TContext> application)
|
public HttpConnectionMiddleware(IList<IConnectionAdapter> adapters, ServiceContext serviceContext, IHttpApplication<TContext> application, HttpProtocols protocols)
|
||||||
{
|
{
|
||||||
_serviceContext = serviceContext;
|
_serviceContext = serviceContext;
|
||||||
_application = application;
|
_application = application;
|
||||||
|
_protocols = protocols;
|
||||||
|
|
||||||
// Keeping these around for now so progress can be made without updating tests
|
// Keeping these around for now so progress can be made without updating tests
|
||||||
_connectionAdapters = adapters;
|
_connectionAdapters = adapters;
|
||||||
|
|
@ -42,6 +47,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal
|
||||||
{
|
{
|
||||||
ConnectionId = connectionContext.ConnectionId,
|
ConnectionId = connectionContext.ConnectionId,
|
||||||
HttpConnectionId = httpConnectionId,
|
HttpConnectionId = httpConnectionId,
|
||||||
|
Protocols = _protocols,
|
||||||
ServiceContext = _serviceContext,
|
ServiceContext = _serviceContext,
|
||||||
ConnectionFeatures = connectionContext.Features,
|
ConnectionFeatures = connectionContext.Features,
|
||||||
PipeFactory = connectionContext.PipeFactory,
|
PipeFactory = connectionContext.PipeFactory,
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
||||||
async Task OnBind(ListenOptions endpoint)
|
async Task OnBind(ListenOptions endpoint)
|
||||||
{
|
{
|
||||||
// Add the HTTP middleware as the terminal connection middleware
|
// Add the HTTP middleware as the terminal connection middleware
|
||||||
endpoint.UseHttpServer(endpoint.ConnectionAdapters, ServiceContext, application);
|
endpoint.UseHttpServer(endpoint.ConnectionAdapters, ServiceContext, application, endpoint.Protocols);
|
||||||
|
|
||||||
var connectionDelegate = endpoint.Build();
|
var connectionDelegate = endpoint.Build();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public bool NoDelay { get; set; } = true;
|
public bool NoDelay { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The protocols enabled on this endpoint.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Defaults to HTTP/1.x only.</remarks>
|
||||||
|
public HttpProtocols Protocols { get; set; } = HttpProtocols.Http1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="List{IConnectionAdapter}"/> that allows each connection <see cref="System.IO.Stream"/>
|
/// Gets the <see cref="List{IConnectionAdapter}"/> that allows each connection <see cref="System.IO.Stream"/>
|
||||||
/// to be intercepted and transformed.
|
/// to be intercepted and transformed.
|
||||||
|
|
|
||||||
|
|
@ -1102,6 +1102,48 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
|
||||||
internal static string FormatPositiveFiniteTimeSpanRequired()
|
internal static string FormatPositiveFiniteTimeSpanRequired()
|
||||||
=> GetString("PositiveFiniteTimeSpanRequired");
|
=> GetString("PositiveFiniteTimeSpanRequired");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An endpoint must be configured to serve at least one protocol.
|
||||||
|
/// </summary>
|
||||||
|
internal static string EndPointRequiresAtLeastOneProtocol
|
||||||
|
{
|
||||||
|
get => GetString("EndPointRequiresAtLeastOneProtocol");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An endpoint must be configured to serve at least one protocol.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatEndPointRequiresAtLeastOneProtocol()
|
||||||
|
=> GetString("EndPointRequiresAtLeastOneProtocol");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using both HTTP/1.x and HTTP/2 on the same endpoint requires the use of TLS.
|
||||||
|
/// </summary>
|
||||||
|
internal static string EndPointRequiresTlsForHttp1AndHttp2
|
||||||
|
{
|
||||||
|
get => GetString("EndPointRequiresTlsForHttp1AndHttp2");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Using both HTTP/1.x and HTTP/2 on the same endpoint requires the use of TLS.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatEndPointRequiresTlsForHttp1AndHttp2()
|
||||||
|
=> GetString("EndPointRequiresTlsForHttp1AndHttp2");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.
|
||||||
|
/// </summary>
|
||||||
|
internal static string EndPointHttp2NotNegotiated
|
||||||
|
{
|
||||||
|
get => GetString("EndPointHttp2NotNegotiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HTTP/2 over TLS was not negotiated on an HTTP/2-only endpoint.
|
||||||
|
/// </summary>
|
||||||
|
internal static string FormatEndPointHttp2NotNegotiated()
|
||||||
|
=> GetString("EndPointHttp2NotNegotiated");
|
||||||
|
|
||||||
private static string GetString(string name, params string[] formatterNames)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ namespace Microsoft.AspNetCore.Hosting
|
||||||
return listenOptions.UseTls(new TlsConnectionAdapterOptions
|
return listenOptions.UseTls(new TlsConnectionAdapterOptions
|
||||||
{
|
{
|
||||||
CertificatePath = certificatePath,
|
CertificatePath = certificatePath,
|
||||||
PrivateKeyPath = privateKeyPath
|
PrivateKeyPath = privateKeyPath,
|
||||||
|
Protocols = listenOptions.Protocols
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tls
|
||||||
public class TlsConnectionAdapter : IConnectionAdapter
|
public class TlsConnectionAdapter : IConnectionAdapter
|
||||||
{
|
{
|
||||||
private static readonly ClosedAdaptedConnection _closedAdaptedConnection = new ClosedAdaptedConnection();
|
private static readonly ClosedAdaptedConnection _closedAdaptedConnection = new ClosedAdaptedConnection();
|
||||||
private static readonly HashSet<string> _serverProtocols = new HashSet<string>(new[] { "h2", "http/1.1" });
|
private static readonly List<string> _serverProtocols = new List<string>();
|
||||||
|
|
||||||
private readonly TlsConnectionAdapterOptions _options;
|
private readonly TlsConnectionAdapterOptions _options;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
|
|
@ -47,6 +47,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tls
|
||||||
|
|
||||||
_options = options;
|
_options = options;
|
||||||
_logger = loggerFactory?.CreateLogger(nameof(TlsConnectionAdapter));
|
_logger = loggerFactory?.CreateLogger(nameof(TlsConnectionAdapter));
|
||||||
|
|
||||||
|
// Order is important. If HTTP/2 is enabled, we prefer it over HTTP/1.1. So add it first.
|
||||||
|
if ((options.Protocols & HttpProtocols.Http2) == HttpProtocols.Http2)
|
||||||
|
{
|
||||||
|
_serverProtocols.Add("h2");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((options.Protocols & HttpProtocols.Http1) == HttpProtocols.Http1)
|
||||||
|
{
|
||||||
|
_serverProtocols.Add("http/1.1");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsHttps => true;
|
public bool IsHttps => true;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Tls
|
namespace Microsoft.AspNetCore.Server.Kestrel.Tls
|
||||||
{
|
{
|
||||||
public class TlsConnectionAdapterOptions
|
public class TlsConnectionAdapterOptions
|
||||||
|
|
@ -8,5 +10,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Tls
|
||||||
public string CertificatePath { get; set; } = string.Empty;
|
public string CertificatePath { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string PrivateKeyPath { get; set; } = string.Empty;
|
public string PrivateKeyPath { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public HttpProtocols Protocols { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
mockDebugger.SetupGet(g => g.IsAttached).Returns(true);
|
mockDebugger.SetupGet(g => g.IsAttached).Returns(true);
|
||||||
_httpConnection.Debugger = mockDebugger.Object;
|
_httpConnection.Debugger = mockDebugger.Object;
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
|
||||||
var now = DateTimeOffset.Now;
|
var now = DateTimeOffset.Now;
|
||||||
_httpConnection.Tick(now);
|
_httpConnection.Tick(now);
|
||||||
|
|
@ -103,6 +104,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = logger;
|
_httpConnectionContext.ServiceContext.Log = logger;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
|
|
||||||
// Initialize timestamp
|
// Initialize timestamp
|
||||||
|
|
@ -130,6 +132,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
|
|
||||||
// Initialize timestamp
|
// Initialize timestamp
|
||||||
|
|
@ -172,6 +175,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
|
|
||||||
// Initialize timestamp
|
// Initialize timestamp
|
||||||
|
|
@ -249,6 +253,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
|
|
||||||
// Initialize timestamp
|
// Initialize timestamp
|
||||||
|
|
@ -317,6 +322,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
|
|
||||||
// Initialize timestamp
|
// Initialize timestamp
|
||||||
|
|
@ -379,6 +385,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
|
|
||||||
var startTime = systemClock.UtcNow;
|
var startTime = systemClock.UtcNow;
|
||||||
|
|
@ -420,6 +427,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
||||||
{
|
{
|
||||||
|
|
@ -454,6 +462,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
||||||
{
|
{
|
||||||
|
|
@ -496,6 +505,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
_httpConnectionContext.ServiceContext.Log = mockLogger.Object;
|
||||||
|
|
||||||
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
_httpConnection.CreateHttp1Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
|
_httpConnection.CreateHttp2Connection(new DummyApplication(), _httpConnectionContext.Transport, _httpConnectionContext.Application);
|
||||||
_httpConnection.Http1Connection.Reset();
|
_httpConnection.Http1Connection.Reset();
|
||||||
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
_httpConnection.Http1Connection.RequestAborted.Register(() =>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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.Net;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
|
||||||
|
{
|
||||||
|
public class ListenOptionsTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ProtocolsDefault()
|
||||||
|
{
|
||||||
|
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
|
||||||
|
Assert.Equal(HttpProtocols.Http1, listenOptions.Protocols);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2;
|
||||||
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
|
{
|
||||||
|
public class HttpProtocolSelectionTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public Task Server_NoProtocols_Error()
|
||||||
|
{
|
||||||
|
return TestError<InvalidOperationException>(HttpProtocols.None, CoreStrings.EndPointRequiresAtLeastOneProtocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task Server_Http1AndHttp2_Cleartext_Error()
|
||||||
|
{
|
||||||
|
return TestError<InvalidOperationException>(HttpProtocols.Http1AndHttp2, CoreStrings.EndPointRequiresTlsForHttp1AndHttp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task Server_Http1Only_Cleartext_Success()
|
||||||
|
{
|
||||||
|
return TestSuccess(HttpProtocols.Http1, "GET / HTTP/1.1\r\nHost:\r\n\r\n", "HTTP/1.1 200 OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public Task Server_Http2Only_Cleartext_Success()
|
||||||
|
{
|
||||||
|
// Expect a SETTINGS frame (type 0x4) with no payload and no flags
|
||||||
|
return TestSuccess(HttpProtocols.Http2, Encoding.ASCII.GetString(Http2Connection.ClientPreface), "\x00\x00\x00\x04\x00\x00\x00\x00\x00");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task TestSuccess(HttpProtocols serverProtocols, string request, string expectedResponse)
|
||||||
|
{
|
||||||
|
var builder = new WebHostBuilder()
|
||||||
|
.UseKestrel(options =>
|
||||||
|
{
|
||||||
|
options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols);
|
||||||
|
})
|
||||||
|
.Configure(app => app.Run(context => Task.CompletedTask));
|
||||||
|
|
||||||
|
using (var host = builder.Build())
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
|
||||||
|
using (var connection = new TestConnection(host.GetPort()))
|
||||||
|
{
|
||||||
|
await connection.Send(request);
|
||||||
|
await connection.Receive(expectedResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task TestError<TException>(HttpProtocols serverProtocols, string expectedErrorMessage)
|
||||||
|
where TException : Exception
|
||||||
|
{
|
||||||
|
var logger = new TestApplicationErrorLogger();
|
||||||
|
var loggerProvider = new Mock<ILoggerProvider>();
|
||||||
|
loggerProvider
|
||||||
|
.Setup(provider => provider.CreateLogger(It.IsAny<string>()))
|
||||||
|
.Returns(logger);
|
||||||
|
|
||||||
|
var builder = new WebHostBuilder()
|
||||||
|
.ConfigureLogging(loggingBuilder => loggingBuilder.AddProvider(loggerProvider.Object))
|
||||||
|
.UseKestrel(options => options.Listen(IPAddress.Loopback, 0, listenOptions => listenOptions.Protocols = serverProtocols))
|
||||||
|
.Configure(app => app.Run(context => Task.CompletedTask));
|
||||||
|
|
||||||
|
using (var host = builder.Build())
|
||||||
|
{
|
||||||
|
host.Start();
|
||||||
|
|
||||||
|
using (var connection = new TestConnection(host.GetPort()))
|
||||||
|
{
|
||||||
|
await connection.WaitForConnectionClose().TimeoutAfter(TimeSpan.FromSeconds(30));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Single(logger.Messages, message => message.LogLevel == LogLevel.Error
|
||||||
|
&& message.EventId.Id == 0
|
||||||
|
&& message.Message == expectedErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
public async Task ConnectionCanReadAndWrite(ListenOptions listenOptions)
|
public async Task ConnectionCanReadAndWrite(ListenOptions listenOptions)
|
||||||
{
|
{
|
||||||
var serviceContext = new TestServiceContext();
|
var serviceContext = new TestServiceContext();
|
||||||
listenOptions.UseHttpServer(listenOptions.ConnectionAdapters, serviceContext, new DummyApplication(TestApp.EchoApp));
|
listenOptions.UseHttpServer(listenOptions.ConnectionAdapters, serviceContext, new DummyApplication(TestApp.EchoApp), HttpProtocols.Http1);
|
||||||
|
|
||||||
var transportContext = new TestLibuvTransportContext()
|
var transportContext = new TestLibuvTransportContext()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,12 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
var serviceContextPrimary = new TestServiceContext();
|
var serviceContextPrimary = new TestServiceContext();
|
||||||
var transportContextPrimary = new TestLibuvTransportContext();
|
var transportContextPrimary = new TestLibuvTransportContext();
|
||||||
var builderPrimary = new ConnectionBuilder();
|
var builderPrimary = new ConnectionBuilder();
|
||||||
builderPrimary.UseHttpServer(serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
|
builderPrimary.UseHttpServer(serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")), HttpProtocols.Http1);
|
||||||
transportContextPrimary.ConnectionHandler = new ConnectionHandler(serviceContextPrimary, builderPrimary.Build());
|
transportContextPrimary.ConnectionHandler = new ConnectionHandler(serviceContextPrimary, builderPrimary.Build());
|
||||||
|
|
||||||
var serviceContextSecondary = new TestServiceContext();
|
var serviceContextSecondary = new TestServiceContext();
|
||||||
var builderSecondary = new ConnectionBuilder();
|
var builderSecondary = new ConnectionBuilder();
|
||||||
builderSecondary.UseHttpServer(serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
|
builderSecondary.UseHttpServer(serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")), HttpProtocols.Http1);
|
||||||
var transportContextSecondary = new TestLibuvTransportContext();
|
var transportContextSecondary = new TestLibuvTransportContext();
|
||||||
transportContextSecondary.ConnectionHandler = new ConnectionHandler(serviceContextSecondary, builderSecondary.Build());
|
transportContextSecondary.ConnectionHandler = new ConnectionHandler(serviceContextSecondary, builderSecondary.Build());
|
||||||
|
|
||||||
|
|
@ -101,7 +101,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
|
|
||||||
var serviceContextPrimary = new TestServiceContext();
|
var serviceContextPrimary = new TestServiceContext();
|
||||||
var builderPrimary = new ConnectionBuilder();
|
var builderPrimary = new ConnectionBuilder();
|
||||||
builderPrimary.UseHttpServer(serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
|
builderPrimary.UseHttpServer(serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")), HttpProtocols.Http1);
|
||||||
var transportContextPrimary = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) };
|
var transportContextPrimary = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) };
|
||||||
transportContextPrimary.ConnectionHandler = new ConnectionHandler(serviceContextPrimary, builderPrimary.Build());
|
transportContextPrimary.ConnectionHandler = new ConnectionHandler(serviceContextPrimary, builderPrimary.Build());
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
|
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
|
||||||
};
|
};
|
||||||
var builderSecondary = new ConnectionBuilder();
|
var builderSecondary = new ConnectionBuilder();
|
||||||
builderSecondary.UseHttpServer(serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
|
builderSecondary.UseHttpServer(serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")), HttpProtocols.Http1);
|
||||||
var transportContextSecondary = new TestLibuvTransportContext();
|
var transportContextSecondary = new TestLibuvTransportContext();
|
||||||
transportContextSecondary.ConnectionHandler = new ConnectionHandler(serviceContextSecondary, builderSecondary.Build());
|
transportContextSecondary.ConnectionHandler = new ConnectionHandler(serviceContextSecondary, builderSecondary.Build());
|
||||||
|
|
||||||
|
|
@ -212,7 +212,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
|
|
||||||
var serviceContextPrimary = new TestServiceContext();
|
var serviceContextPrimary = new TestServiceContext();
|
||||||
var builderPrimary = new ConnectionBuilder();
|
var builderPrimary = new ConnectionBuilder();
|
||||||
builderPrimary.UseHttpServer(serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
|
builderPrimary.UseHttpServer(serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")), HttpProtocols.Http1);
|
||||||
var transportContextPrimary = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) };
|
var transportContextPrimary = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) };
|
||||||
transportContextPrimary.ConnectionHandler = new ConnectionHandler(serviceContextPrimary, builderPrimary.Build());
|
transportContextPrimary.ConnectionHandler = new ConnectionHandler(serviceContextPrimary, builderPrimary.Build());
|
||||||
|
|
||||||
|
|
@ -224,7 +224,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
|
||||||
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
|
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
|
||||||
};
|
};
|
||||||
var builderSecondary = new ConnectionBuilder();
|
var builderSecondary = new ConnectionBuilder();
|
||||||
builderSecondary.UseHttpServer(serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
|
builderSecondary.UseHttpServer(serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")), HttpProtocols.Http1);
|
||||||
var transportContextSecondary = new TestLibuvTransportContext();
|
var transportContextSecondary = new TestLibuvTransportContext();
|
||||||
transportContextSecondary.ConnectionHandler = new ConnectionHandler(serviceContextSecondary, builderSecondary.Build());
|
transportContextSecondary.ConnectionHandler = new ConnectionHandler(serviceContextSecondary, builderSecondary.Build());
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue