runtime: SslStream.WriteAsync hangs after updating to CoreFx 4.4

We’ve recently updated package references in Kestrel to CoreFx 4.4 https://github.com/aspnet/KestrelHttpServer/commit/5b8f7c2b2be5744edac8ce3c5a2dea86ed65b8ee.

After this update, Kestrel can’t serve HTTPS anymore. We have a stream that wraps an SslStream, and it’s hanging when writing here:

https://github.com/aspnet/KestrelHttpServer/blob/5b8f7c2b2be5744edac8ce3c5a2dea86ed65b8ee/src/Microsoft.AspNetCore.Server.Kestrel/Filter/Internal/StreamSocketOutput.cs#L59

Reproing is straightforward: just run the Kestrel sample app (under samples/SampleApp in the repo) and hit it with any client, and you will see the hang.

This only happens on .NET Core. Desktop .NET works fine.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 40 (30 by maintainers)

Most upvoted comments

.NET Full Framework 1.1+ had async methods Stream.BeginWrite/Stream.EndWrite and Stream.BeginRead/Stream.EndRead on the base class. This approach to async was depreciated when Tasks became a thing and the new Task based methods Stream.WriteAsync and Stream.ReadAsync became the preferred method of doing async.

The base classes implementation of BeginX/EndX are sync methods to support Streams that don’t actually have async methods. A lot of the conversions for the historic Streams newer XXXAsync methods have wrapped these BeginX/EndX methods to achieve the newer async paths; using helpers that do the conversion.

As these methods were deprecated they were not brought to .NET Core. To reuse the same code that expected BeginX/EndX without doing lots of rewriting to directly implement WriteAsync/ReadAsync; which would be additional replumbing and testing to end up with the same result (although it would be cleaner); extension methods were created to behave as the BeginX/EndX methods. So all was fine…

However, as part of returning the apis for .NET Standard 2.0; this has meant the base class implementations for BeginX/EndX have reappeared. The virtual base class methods take precedence over extension methods; so the behaviour has moved back to sync-blocking on the async methods; rather than actually being async.

Hence this issue has arisen… 😢

The fastest way to fix it is likely to copy paste the extension methods code into SslStream/NetworkStream etc. The best way to fix it would be to actually implement the WriteAsync/ReadAsync methods - though likely that would also be more risky.