Merge branch 'release/2.1' into dev
This commit is contained in:
commit
1e65802109
|
|
@ -198,7 +198,6 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
|||
while (true)
|
||||
{
|
||||
#if NETCOREAPP2_1
|
||||
// Do a 0 byte read so that idle connections don't allocate a buffer when waiting for a read
|
||||
var result = await socket.ReceiveAsync(Memory<byte>.Empty, CancellationToken.None);
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Close)
|
||||
|
|
@ -223,7 +222,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
|||
|
||||
// Exceptions are handled above where the send and receive tasks are being run.
|
||||
var receiveResult = await socket.ReceiveAsync(arraySegment, CancellationToken.None);
|
||||
|
||||
#endif
|
||||
// Need to check again for NetCoreApp2.1 because a close can happen between a 0-byte read and the actual read
|
||||
if (receiveResult.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
Log.WebSocketClosed(_logger, _webSocket.CloseStatus);
|
||||
|
|
@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
|
|||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Log.MessageReceived(_logger, receiveResult.MessageType, receiveResult.Count, receiveResult.EndOfMessage);
|
||||
|
||||
_application.Output.Advance(receiveResult.Count);
|
||||
|
|
|
|||
|
|
@ -154,7 +154,6 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal.Transports
|
|||
var memory = _application.Output.GetMemory();
|
||||
|
||||
#if NETCOREAPP2_1
|
||||
// Because we checked the CloseStatus from the 0 byte read above, we don't need to check again after reading
|
||||
var receiveResult = await socket.ReceiveAsync(memory, CancellationToken.None);
|
||||
#else
|
||||
var isArray = MemoryMarshal.TryGetArray<byte>(memory, out var arraySegment);
|
||||
|
|
@ -162,12 +161,13 @@ namespace Microsoft.AspNetCore.Http.Connections.Internal.Transports
|
|||
|
||||
// Exceptions are handled above where the send and receive tasks are being run.
|
||||
var receiveResult = await socket.ReceiveAsync(arraySegment, CancellationToken.None);
|
||||
|
||||
#endif
|
||||
// Need to check again for NetCoreApp2.1 because a close can happen between a 0-byte read and the actual read
|
||||
if (receiveResult.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Log.MessageReceived(_logger, receiveResult.MessageType, receiveResult.Count, receiveResult.EndOfMessage);
|
||||
|
||||
_application.Output.Advance(receiveResult.Count);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
{
|
||||
public class DynamicHub : Hub
|
||||
public abstract class DynamicHub : Hub
|
||||
{
|
||||
private DynamicHubClients _clients;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
{
|
||||
public class Hub : IDisposable
|
||||
public abstract class Hub : IDisposable
|
||||
{
|
||||
private bool _disposed;
|
||||
private IHubCallerClients _clients;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using Microsoft.AspNetCore.SignalR.Internal;
|
|||
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
{
|
||||
public class Hub<T> : Hub where T : class
|
||||
public abstract class Hub<T> : Hub where T : class
|
||||
{
|
||||
private IHubCallerClients<T> _clients;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
// 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.Http;
|
||||
using Microsoft.AspNetCore.Http.Connections.Features;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
{
|
||||
public static class GetHttpContextExtensions
|
||||
{
|
||||
public static HttpContext GetHttpContext(this HubCallerContext connection)
|
||||
{
|
||||
if (connection == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(connection));
|
||||
}
|
||||
return connection.Features.Get<IHttpContextFeature>()?.HttpContext;
|
||||
}
|
||||
|
||||
public static HttpContext GetHttpContext(this HubConnectionContext connection)
|
||||
{
|
||||
if (connection == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(connection));
|
||||
}
|
||||
return connection.Features.Get<IHttpContextFeature>()?.HttpContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
// 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.Http;
|
||||
using Microsoft.AspNetCore.Http.Connections.Features;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR
|
||||
{
|
||||
public static class HubCallerContextExtensions
|
||||
{
|
||||
public static HttpContext GetHttpContext(this HubCallerContext connection)
|
||||
{
|
||||
return connection.Features.Get<IHttpContextFeature>()?.HttpContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
||||
{
|
||||
internal class HeaderUserIdProvider : IUserIdProvider
|
||||
{
|
||||
public static readonly string HeaderName = "Super-Insecure-UserName";
|
||||
|
||||
public string GetUserId(HubConnectionContext connection)
|
||||
{
|
||||
// Super-insecure user id provider :). Don't use this for anything real!
|
||||
return connection.GetHttpContext()?.Request?.Headers?[HeaderName];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -864,15 +864,14 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TransportTypes))]
|
||||
public async Task CheckHttpConnectionFeatures(HttpTransportType transportType)
|
||||
[Fact]
|
||||
public async Task CheckHttpConnectionFeatures()
|
||||
{
|
||||
using (StartVerifableLog(out var loggerFactory, $"{nameof(CheckHttpConnectionFeatures)}_{transportType}"))
|
||||
using (StartVerifableLog(out var loggerFactory))
|
||||
{
|
||||
var hubConnection = new HubConnectionBuilder()
|
||||
.WithLoggerFactory(loggerFactory)
|
||||
.WithUrl(ServerFixture.Url + "/default", transportType)
|
||||
.WithUrl(ServerFixture.Url + "/default")
|
||||
.Build();
|
||||
try
|
||||
{
|
||||
|
|
@ -901,6 +900,37 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserIdProviderCanAccessHttpContext()
|
||||
{
|
||||
using (StartVerifableLog(out var loggerFactory))
|
||||
{
|
||||
var hubConnection = new HubConnectionBuilder()
|
||||
.WithLoggerFactory(loggerFactory)
|
||||
.WithUrl(ServerFixture.Url + "/default", options =>
|
||||
{
|
||||
options.Headers.Add(HeaderUserIdProvider.HeaderName, "SuperAdmin");
|
||||
})
|
||||
.Build();
|
||||
try
|
||||
{
|
||||
await hubConnection.StartAsync().OrTimeout();
|
||||
|
||||
var userIdentifier = await hubConnection.InvokeAsync<string>(nameof(TestHub.GetUserIdentifier)).OrTimeout();
|
||||
Assert.Equal("SuperAdmin", userIdentifier);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
loggerFactory.CreateLogger<HubConnectionTests>().LogError(ex, "{ExceptionType} from test", ex.GetType().FullName);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
await hubConnection.DisposeAsync().OrTimeout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NegotiationSkipsServerSentEventsWhenUsingBinaryProtocol()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
await Clients.Client(Context.ConnectionId).SendAsync("NoClientHandler");
|
||||
}
|
||||
|
||||
public string GetUserIdentifier()
|
||||
{
|
||||
return Context.UserIdentifier;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetHeaderValues(string[] headerNames)
|
||||
{
|
||||
var context = Context.GetHttpContext();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ namespace Microsoft.AspNetCore.SignalR.Client.FunctionalTests
|
|||
options.EnableDetailedErrors = true;
|
||||
})
|
||||
.AddMessagePackProtocol();
|
||||
services.AddSingleton<IUserIdProvider, HeaderUserIdProvider>();
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
|
||||
|
|
|
|||
|
|
@ -31,14 +31,6 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
return true;
|
||||
}
|
||||
|
||||
// Suppress https://github.com/aspnet/SignalR/issues/2069
|
||||
if (writeContext.LoggerName == "Microsoft.AspNetCore.Http.Connections.Internal.HttpConnectionManager" &&
|
||||
writeContext.Message.StartsWith("Failed disposing connection") &&
|
||||
writeContext.Exception is WebSocketException)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,15 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
{
|
||||
public class DefaultHubActivatorTests
|
||||
{
|
||||
public class CreatableHub : Hub
|
||||
{
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HubCreatedIfNotResolvedFromServiceProvider()
|
||||
{
|
||||
Assert.NotNull(
|
||||
new DefaultHubActivator<Hub>(Mock.Of<IServiceProvider>()).Create());
|
||||
new DefaultHubActivator<CreatableHub>(Mock.Of<IServiceProvider>()).Create());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
|
|
|
|||
|
|
@ -1706,6 +1706,57 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ConnectionUserIdIsAssignedByUserIdProvider()
|
||||
{
|
||||
var firstRequest = true;
|
||||
var userIdProvider = new TestUserIdProvider(c =>
|
||||
{
|
||||
if (firstRequest)
|
||||
{
|
||||
firstRequest = false;
|
||||
return "client1";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "client2";
|
||||
}
|
||||
});
|
||||
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(services =>
|
||||
{
|
||||
services.AddSingleton<IUserIdProvider>(userIdProvider);
|
||||
});
|
||||
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<MethodHub>>();
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var connectionHandlerTask1 = await client1.ConnectAsync(connectionHandler);
|
||||
var connectionHandlerTask2 = await client2.ConnectAsync(connectionHandler);
|
||||
|
||||
await client1.Connected.OrTimeout();
|
||||
await client2.Connected.OrTimeout();
|
||||
|
||||
await client2.SendInvocationAsync(nameof(MethodHub.SendToMultipleUsers), new[] { "client1" }, "Hi!").OrTimeout();
|
||||
|
||||
var message = (InvocationMessage)await client1.ReadAsync().OrTimeout();
|
||||
|
||||
Assert.Equal("Send", message.Target);
|
||||
Assert.Collection(message.Arguments, arg => Assert.Equal("Hi!", arg));
|
||||
|
||||
client1.Dispose();
|
||||
client2.Dispose();
|
||||
|
||||
await connectionHandlerTask1.OrTimeout();
|
||||
await connectionHandlerTask2.OrTimeout();
|
||||
|
||||
// Read the completion, then we should have nothing left in client2's queue
|
||||
Assert.IsType<CompletionMessage>(client2.TryRead());
|
||||
Assert.IsType<CloseMessage>(client2.TryRead());
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomFormatter : IFormatterResolver
|
||||
{
|
||||
public IMessagePackFormatter<T> GetFormatter<T>()
|
||||
|
|
@ -2141,5 +2192,17 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
{
|
||||
public HttpContext HttpContext { get; set; }
|
||||
}
|
||||
|
||||
private class TestUserIdProvider : IUserIdProvider
|
||||
{
|
||||
private readonly Func<HubConnectionContext, string> _getUserId;
|
||||
|
||||
public TestUserIdProvider(Func<HubConnectionContext, string> getUserId)
|
||||
{
|
||||
_getUserId = getUserId;
|
||||
}
|
||||
|
||||
public string GetUserId(HubConnectionContext connection) => _getUserId(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue