Skip to content

Commit 7c2d9e8

Browse files
authored
Clean up pipe pair on transport start failure (#1836)
1 parent ba0131a commit 7c2d9e8

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

src/Microsoft.AspNetCore.Http.Connections.Client/HttpConnection.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,12 @@ private async Task StartTransport(Uri connectUrl, HttpTransportType transportTyp
345345
catch (Exception ex)
346346
{
347347
Log.ErrorStartingTransport(_logger, transport, ex);
348+
349+
// Clean up pipes and null out transport when we fail to start.
350+
pair.Transport.Input.Complete();
351+
pair.Transport.Output.Complete();
352+
pair.Application.Input.Complete();
353+
pair.Application.Output.Complete();
348354
_transport = null;
349355
throw;
350356
}

test/Microsoft.AspNetCore.SignalR.Client.Tests/HttpConnectionTests.ConnectionLifecycle.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,28 @@ await WithConnectionAsync(
159159
}
160160
}
161161

162+
[Fact]
163+
public async Task PipesAreDisposedAfterTransportFailsToStart()
164+
{
165+
using (StartLog(out var loggerFactory))
166+
{
167+
var writerTcs = new TaskCompletionSource<object>();
168+
var readerTcs = new TaskCompletionSource<object>();
169+
await WithConnectionAsync(
170+
CreateConnection(
171+
loggerFactory: loggerFactory,
172+
transport: new FakeTransport(writerTcs, readerTcs)),
173+
async (connection) =>
174+
{
175+
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => connection.StartAsync(TransferFormat.Text));
176+
Assert.Equal("Unable to connect to the server with any of the available transports.", ex.Message);
177+
178+
Assert.True(writerTcs.Task.IsCompleted);
179+
Assert.True(readerTcs.Task.IsCompleted);
180+
});
181+
}
182+
}
183+
162184
[Fact]
163185
public async Task CanDisposeUnstartedConnection()
164186
{
@@ -356,6 +378,35 @@ await WithConnectionAsync(
356378
}
357379
}
358380

381+
private class FakeTransport : ITransport
382+
{
383+
private IDuplexPipe _application;
384+
private TaskCompletionSource<object> _writerTcs;
385+
private TaskCompletionSource<object> _readerTcs;
386+
387+
public FakeTransport(TaskCompletionSource<object> writerTcs, TaskCompletionSource<object> readerTcs)
388+
{
389+
_writerTcs = writerTcs;
390+
_readerTcs = readerTcs;
391+
}
392+
393+
public Task StartAsync(Uri url, IDuplexPipe application, TransferFormat transferFormat, IConnection connection)
394+
{
395+
_application = application;
396+
Action<Exception, object> onCompletedCallback = (ex, tcs) => { ((TaskCompletionSource<object>)tcs).TrySetResult(null); };
397+
_application.Input.OnWriterCompleted(onCompletedCallback, _writerTcs);
398+
_application.Output.OnReaderCompleted(onCompletedCallback, _readerTcs);
399+
throw new Exception();
400+
}
401+
402+
public Task StopAsync()
403+
{
404+
_application.Output.Complete();
405+
_application.Input.Complete();
406+
return Task.CompletedTask;
407+
}
408+
}
409+
359410
private static async Task AssertDisposedAsync(HttpConnection connection)
360411
{
361412
var exception =

0 commit comments

Comments
 (0)