Exiting SSE transport receive loop when transport is stopping
Fixes: #650
This commit is contained in:
parent
6a1f75a496
commit
a41ef82f19
|
|
@ -71,25 +71,26 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||
|
||||
var stream = await response.Content.ReadAsStreamAsync();
|
||||
|
||||
var pipelineReader = stream.AsPipelineReader();
|
||||
var pipelineReader = stream.AsPipelineReader(cancellationToken);
|
||||
var readCancellationRegistration = cancellationToken.Register(
|
||||
reader => ((IPipeReader)reader).CancelPendingRead(), pipelineReader);
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var result = await pipelineReader.ReadAsync();
|
||||
var input = result.Buffer;
|
||||
if (result.IsCancelled || (input.IsEmpty && result.IsCompleted))
|
||||
{
|
||||
_logger.LogDebug("Server-Sent Event Stream ended");
|
||||
break;
|
||||
}
|
||||
|
||||
var consumed = input.Start;
|
||||
var examined = input.End;
|
||||
|
||||
try
|
||||
{
|
||||
if (input.IsEmpty && result.IsCompleted)
|
||||
{
|
||||
_logger.LogDebug("Server-Sent Event Stream ended");
|
||||
break;
|
||||
}
|
||||
|
||||
var parseResult = _parser.ParseMessage(input, out consumed, out examined, out var buffer);
|
||||
|
||||
switch (parseResult)
|
||||
|
|
@ -114,6 +115,7 @@ namespace Microsoft.AspNetCore.Sockets.Client
|
|||
}
|
||||
finally
|
||||
{
|
||||
readCancellationRegistration.Dispose();
|
||||
_transportCts.Cancel();
|
||||
stream.Dispose();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
|
||||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -74,7 +74,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
try
|
||||
{
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
|
|
@ -127,7 +127,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
try
|
||||
{
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
|
|
@ -163,7 +163,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
|
||||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
try
|
||||
{
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
|
|
@ -199,7 +199,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
|
||||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
try
|
||||
{
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
|
|
@ -240,7 +240,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
|
||||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
try
|
||||
{
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
|
|
@ -289,7 +289,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
|
||||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
try
|
||||
{
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
|
|
@ -347,7 +347,7 @@ namespace Microsoft.AspNetCore.Client.Tests
|
|||
|
||||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
var longPollingTransport = new LongPollingTransport(httpClient, new LoggerFactory());
|
||||
var longPollingTransport = new LongPollingTransport(httpClient);
|
||||
try
|
||||
{
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// 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.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks.Channels;
|
||||
using Microsoft.AspNetCore.SignalR.Tests.Common;
|
||||
using Microsoft.AspNetCore.Sockets.Client;
|
||||
using Microsoft.AspNetCore.Sockets.Internal;
|
||||
using Moq;
|
||||
using Moq.Protected;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Client.Tests
|
||||
{
|
||||
public class ServerSentEventsTransportTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task CanStartStopSSETransport()
|
||||
{
|
||||
var eventStreamTcs = new TaskCompletionSource<object>();
|
||||
var copyToAsyncTcs = new TaskCompletionSource<int>();
|
||||
|
||||
var mockHttpHandler = new Mock<HttpMessageHandler>();
|
||||
mockHttpHandler.Protected()
|
||||
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
|
||||
.Returns<HttpRequestMessage, CancellationToken>(async (request, cancellationToken) =>
|
||||
{
|
||||
await Task.Yield();
|
||||
// Receive loop started - allow stopping the transport
|
||||
eventStreamTcs.SetResult(null);
|
||||
|
||||
// returns unfinished task to block pipelines
|
||||
var mockStream = new Mock<Stream>();
|
||||
mockStream
|
||||
.Setup(s => s.CopyToAsync(It.IsAny<Stream>(), It.IsAny<int>(), It.IsAny<CancellationToken>()))
|
||||
.Returns(copyToAsyncTcs.Task);
|
||||
return new HttpResponseMessage { Content = new StreamContent(mockStream.Object) };
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
using (var httpClient = new HttpClient(mockHttpHandler.Object))
|
||||
{
|
||||
var sseTransport = new ServerSentEventsTransport(httpClient);
|
||||
var connectionToTransport = Channel.CreateUnbounded<SendMessage>();
|
||||
var transportToConnection = Channel.CreateUnbounded<byte[]>();
|
||||
var channelConnection = new ChannelConnection<SendMessage, byte[]>(connectionToTransport, transportToConnection);
|
||||
await sseTransport.StartAsync(new Uri("http://fakeuri.org"), channelConnection).OrTimeout();
|
||||
|
||||
await eventStreamTcs.Task.OrTimeout();
|
||||
await sseTransport.StopAsync().OrTimeout();
|
||||
await sseTransport.Running.OrTimeout();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
copyToAsyncTcs.SetResult(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -249,7 +249,7 @@ namespace Microsoft.AspNetCore.SignalR.Tests
|
|||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TransportTypes() =>
|
||||
public static IEnumerable<object[]> TransportTypes =>
|
||||
new[]
|
||||
{
|
||||
new object[] { TransportType.WebSockets },
|
||||
|
|
|
|||
Loading…
Reference in New Issue