Bug 55872 - [New Web Stack] BCL HttpClientHandler sometimes throws invalid HttpRequestException on cancellation.
Summary: [New Web Stack] BCL HttpClientHandler sometimes throws invalid HttpRequestExc...
Status: ASSIGNED
Alias: None
Product: Android
Classification: Xamarin
Component: BCL Class Libraries ()
Version: 7.2 (15.1)
Hardware: PC Windows
: Normal normal
Target Milestone: abi-break-future
Assignee: Martin Baulig
URL:
Depends on: 58141
Blocks:
  Show dependency tree
 
Reported: 2017-05-01 21:09 UTC by Greg DeStigter
Modified: 2017-10-09 20:45 UTC (History)
16 users (show)

Tags: xamexttriage, xamextfollowed
Is this bug a regression?: ---
Last known good build:


Attachments
Reproducer for invalid Android HTTP exception issue. (13.01 KB, application/x-zip-compressed)
2017-05-01 21:09 UTC, Greg DeStigter
Details
New simple test project (32.87 KB, application/zip)
2017-05-18 01:31 UTC, Jon Goldberger [MSFT]
Details
new simple test project (33.03 KB, application/zip)
2017-05-18 01:53 UTC, Jon Goldberger [MSFT]
Details
Updated new simple test project (33.08 KB, application/zip)
2017-05-18 02:09 UTC, Jon Goldberger [MSFT]
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report for Bug 55872 on Developer Community or GitHub if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: Developer Community HTML or GitHub Markdown
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:
Status:
ASSIGNED

Description Greg DeStigter 2017-05-01 21:09:13 UTC
Created attachment 21910 [details]
Reproducer for invalid Android HTTP exception issue.

In Xamarin.Android, when submitting and cancelling HTTP requests via `HttpClient.SendAsync(requestMessage, cancellationToken)` an `HttpRequestException` is sometimes thrown that appears to be invalid (exception should not happen).

Example Exception stack:
System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: Error: SecureChannelFailure (The authentication or decryption has failed.) ---> System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: The authentication or decryption has failed.
  at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord (System.IAsyncResult asyncResult) [0x0003a] in /Users/builder/data/lanes/4468/f913a78a/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:430 
  at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord (System.IAsyncResult ar, System.Boolean ignoreEmpty) [0x00000] in /Users/builder/data/lanes/4468/f913a78a/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:256 
  at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker (System.IAsyncResult result) [0x00071] in /Users/builder/data/lanes/4468/f913a78a/source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs:418

Notes:
  - Exception: 'HttpRequestException: An error occurred while sending the request' with InnerException: 'Error: SecureChannelFailure(The authentication or decryption has failed.)' does not seem legitimate in this scenario as previous calls to the same service are completing OK.
  - This issue does not occur if using `AndroidClientHandler`.
  - Issue does not occur if requests are not cancelled.

To reproduce:
  - Create client handler: `HttpClientHAndler`
  - For each batch of requests
    - Send individual HTTP requests (`HttpClient::SendAsync`) with a short delay between each
    - Cancel the entire batch via `CancellationToken`.
  - Wait for all requests to finish (succeed, fail or cancel)
  - Exceptions should be thrown. It may take a few request batches for this to happen.

Reproducer application is attached:
  - Open the app (device or emulator)
  - Set run options in the UI and click the 'Run Test' button
  - Wait for the test to finish and view the excption list
  - This application should run with no exceptions (all requests either succeeded or cancelled)

Tested on Xamarin.Android 7.2.0.7 with 6.0 Emulator and 6.0.1 device.
Comment 1 Chris Miller 2017-05-02 11:05:39 UTC
We are using ESRI's ArcGIS SDK and we get this error when trying to scroll a mao
Comment 3 Jon Goldberger [MSFT] 2017-05-18 01:52:43 UTC
Setting as confirmed as I could reproduce this in a completely new and simple test project. The issue does not happen every time, in fact I had to launch the new simple test project 4 or 5 times before the issue occurred. This test project uses only one HttpClient and one HttpClientHandler for all requests. It sends 10 get requests to google.com. Every other request, i.e. the 2nd, 4th, etc. request, is cancelled. After a few tries, I got the exception as noted in the bug description. This is what I got with full stack trace:

>System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: Error: SecureChannelFailure (The authentication or decryption has failed.) ---> System.IO.IOException: The authentication or decryption has failed. ---> System.IO.IOException: Error while sending TLS Alert (Fatal:InternalError): System.IO.IOException: Unable to write data to the transport connection: Cannot access a disposed object.
>Object name: 'System.Net.Sockets.Socket'.. ---> System.ObjectDisposedException: Cannot access a disposed object.
>Object name: 'System.Net.Sockets.Socket'.
>  at System.Net.Sockets.Socket.ThrowIfDisposedAndClosed () [0x0001b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
>  at System.Net.Sockets.Socket.BeginSend (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags, System.Net.Sockets.SocketError& errorCode, System.AsyncCallback callback, System.Object state) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
>  at System.Net.Sockets.Socket.BeginSend (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags, System.AsyncCallback callback, System.Object state) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
>  at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback callback, System.Object state) [0x0009b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
>   --- End of inner exception stack trace ---
>  at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback callback, System.Object state) [0x000e6] in <1a27f8ea09e3480db932cbde0eaedfb2>:0 
>  at Mono.Security.Protocol.Tls.RecordProtocol.BeginSendRecord (Mono.Security.Protocol.Tls.ContentType contentType, System.Byte[] recordData, System.AsyncCallback callback, System.Object state) [0x00023] in <2940be14d5a1446694e2193e9029b558>:0 
>  at Mono.Security.Protocol.Tls.RecordProtocol.BeginSendRecord (Mono.Security.Protocol.Tls.Handshake.HandshakeType handshakeType, System.AsyncCallback callback, System.Object state) [0x00024] in <2940be14d5a1446694e2193e9029b558>:0 
>  at Mono.Security.Protocol.Tls.SslClientStream.BeginNegotiateHandshake (System.AsyncCallback callback, System.Object state) [0x00049] in <2940be14d5a1446694e2193e9029b558>:0 
>  at Mono.Security.Protocol.Tls.SslStreamBase.BeginNegotiateHandshake (Mono.Security.Protocol.Tls.SslStreamBase+InternalAsyncResult asyncResult) [0x0001e] in <2940be14d5a1446694e2193e9029b558>:0  ---> System.IO.IOException: Unable to write data to the transport connection: Cannot access a disposed object.
>Object name: 'System.Net.Sockets.Socket'.. ---> System.ObjectDisposedException: Cannot access a disposed object.
>Object name: 'System.Net.Sockets.Socket'.
>  at System.Net.Sockets.Socket.ThrowIfDisposedAndClosed () [0x0001b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at System.Net.Sockets.Socket.BeginSend (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags, System.Net.Sockets.SocketError& errorCode, System.AsyncCallback callback, System.Object state) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at System.Net.Sockets.Socket.BeginSend (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.Net.Sockets.SocketFlags socketFlags, System.AsyncCallback callback, System.Object state) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback callback, System.Object state) [0x0009b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  --- End of inner exception stack trace ---
>  at System.Net.Sockets.NetworkStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 size, System.AsyncCallback callback, System.Object state) [0x000e6] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at Mono.Security.Protocol.Tls.RecordProtocol.BeginSendRecord (Mono.Security.Protocol.Tls.ContentType contentType, System.Byte[] recordData, System.AsyncCallback callback, System.Object state) [0x00023] in <2940be14d5a1446694e2193e9029b558>:0
>  at Mono.Security.Protocol.Tls.RecordProtocol.SendRecord (Mono.Security.Protocol.Tls.ContentType contentType, System.Byte[] recordData) [0x00000] in <2940be14d5a1446694e2193e9029b558>:0
>  at Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (Mono.Security.Protocol.Tls.Alert alert) [0x00021] in <2940be14d5a1446694e2193e9029b558>:0
>  at Mono.Security.Protocol.Tls.RecordProtocol.SendAlert (System.Exception& ex) [0x0001b] in <2940be14d5a1446694e2193e9029b558>:0
>  --- End of inner exception stack trace ---
>  --- End of inner exception stack trace ---
>  at Mono.Security.Protocol.Tls.SslStreamBase.BeginNegotiateHandshake (Mono.Security.Protocol.Tls.SslStreamBase+InternalAsyncResult asyncResult) [0x00069] in <2940be14d5a1446694e2193e9029b558>:0
>  at Mono.Security.Protocol.Tls.SslStreamBase.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 count, System.AsyncCallback callback, System.Object state) [0x0006d] in <2940be14d5a1446694e2193e9029b558>:0
>  at Mono.Net.Security.Private.LegacySslStream.BeginWrite (System.Byte[] buffer, System.Int32 offset, System.Int32 count, System.AsyncCallback asyncCallback, System.Object asyncState) [0x00006] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at Mono.Net.Security.Private.LegacySslStream.BeginAuthenticateAsClient (System.String targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation, System.AsyncCallback asyncCallback, System.Object asyncState) [0x0009b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at Mono.Net.Security.Private.LegacySslStream.AuthenticateAsClient (System.String targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) [0x00000] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at Mono.Net.Security.MonoTlsStream.CreateStream (System.Byte[] buffer) [0x0007b] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at System.Net.WebConnection.CreateStream (System.Net.HttpWebRequest request) [0x00073] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  --- End of inner exception stack trace ---
>  at System.Net.HttpWebRequest.EndGetResponse (System.IAsyncResult asyncResult) [0x00058] in <1a27f8ea09e3480db932cbde0eaedfb2>:0
>  at System.Threading.Tasks.TaskFactory`1[TResult].FromAsyncCoreLogic (System.IAsyncResult iar, System.Func`2[T,TResult] endFunction, System.Action`1[T] endAction, System.Threading.Tasks.Task`1[TResult] promise, System.Boolean requiresSynchronization) [0x0000f] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Net.Http.HttpClientHandler+<SendAsync>d__63.MoveNext () [0x003e6] in <94e5e9aa81954a7eb1b5fb3cce8bf65c>:0
>  --- End of inner exception stack trace ---
>  at System.Net.Http.HttpClientHandler+<SendAsync>d__63.MoveNext () [0x00449] in <94e5e9aa81954a7eb1b5fb3cce8bf65c>:0
>  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Net.Http.HttpClient+<SendAsyncWorker>d__49.MoveNext () [0x000ca] in <94e5e9aa81954a7eb1b5fb3cce8bf65c>:0
>  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at TestHttpException.MainActivity+<<OnCreate>b__6_0>d.MoveNext () [0x000f5] in /Users/jongoldberger/Downloads/TestHttpException/TestHttpException/MainActivity.cs:47
>  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) [0x00000] in <d18287e1d683419a8ec3216fd78947b9>:0
>  at Android.App.SyncContext+<>c__DisplayClass2_0.<Post>b__0 () [0x00000] in <33e6e739ac344166b157e323586f11a1>:0
>  at Java.Lang.Thread+RunnableImplementor.Run () [0x00008] in <33e6e739ac344166b157e323586f11a1>:0
>  at Java.Lang.IRunnableInvoker.n_Run (System.IntPtr jnienv, System.IntPtr native__this) [0x00008] in <33e6e739ac344166b157e323586f11a1>:0
>  at at (wrapper dynamic-method) System.Object:93ea7cd4-2046-4ccb-b6c7-2544bc547668 (intptr,intptr)


What seems odd is that the exception always seems to occur on the 4th request. Subsequent requests succeed. 

If you run the new simple test project, there is a text view that will output the status of each request. If all is working you should see every other request succeed and every other request cancelled, and you will see the exception message if an exception occurs in the TextView. Again I am only getting the issue intermittently.
Comment 5 Jon Goldberger [MSFT] 2017-05-18 01:53:53 UTC
Created attachment 22246 [details]
new simple test project

Updated simple test project
Comment 6 Jon Goldberger [MSFT] 2017-05-18 02:09:37 UTC
Created attachment 22247 [details]
Updated new simple test project

Oops, made error in last iteration
Comment 9 Jonathan Pryor 2017-05-26 19:12:07 UTC
> an `HttpRequestException` is sometimes thrown 

That's *weird*. The `SecureChannelFailure` that is reported *sounds like* it would be due to accessing a TLS 1.2 URL, but if that were the case, that would *always* happen.

*By default*, HttpClient is not able to access URLs using TLS 1.2.

Also odd is that, afaict, the URL that Attachment #21910 [details] is hitting is a TLS 1.0 URL:

> curl -o o.txt --tlsv1.0 https://server.arcgisonline.com/ArcGIS/rest/services

The above command completes without error, suggesting that it is accessible with TLS 1.0 and doesn't require TLS 1.2. The normal HttpClient handler *should* be able to handle TLS 1.0, which would explain why it works at all...but doesn't explain why it sometimes fails.

What's perhaps *plausible* is that *sometimes* there is an HTTP redirect being encountered, and the redirect is to TLS 1.2 URL, at which point it fails.

I would suggest trying to enable BTLS use, which allows WebRequest and HttpClient to access TLS 1.2 URLs, and see if that improves matters:

https://developer.xamarin.com/releases/android/xamarin.android_7/xamarin.android_7.3/#TLS_1.2_support_in_WebRequest
Comment 10 Jonathan Pryor 2017-05-26 19:12:28 UTC
@Goldberger: The stack trace in Comment #3 looks completely different from that in Comment #0, so I suspect it's a different issue.
Comment 11 Jon Goldberger [MSFT] 2017-05-26 19:51:53 UTC
@Jonathan Pryor, 

Perhaps, but the end result is the same. To be honest I did not run the initially provided test project. I wanted to see if I could reproduce independently from the description, and I could reproduce the described behavior. IOW one of many https requests failing with the same SecureChannelFailure (The authentication or decryption has failed) message.
Comment 12 Greg DeStigter 2017-05-26 22:07:49 UTC
I tried using BLTS in the original repro app per @Jonathan Pryor suggestion and I still received an assortment of `SecureChannelFailure` exceptions. I see `Mono.Btls` in the exception callstack, so I'm pretty sure it's getting used.

>System.Net.Http.HttpRequestException: An error occurred while sending the request ---> System.Net.WebException: Error: SecureChannelFailure (Ssl error:100000df:SSL routines:OPENSSL_internal:UNEXPECTED_MESSAGE
>  at /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/boringssl/ssl/s3_both.c:390) ---> Mono.Btls.MonoBtlsException: Ssl error:100000df:SSL routines:OPENSSL_internal:UNEXPECTED_MESSAGE
>  at /Users/builder/jenkins/workspace/xamarin-android/xamarin-android/external/mono/external/boringssl/ssl/s3_both.c:390
>  at Mono.Btls.MonoBtlsContext.ProcessHandshake () [0x00038] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncProtocolRequest asyncRequest, Mono.Net.Security.AsyncOperationStatus status) [0x0002a] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (Mono.Net.Security.AsyncOperationStatus status) [0x0006b] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation () [0x0000d] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.AsyncProtocolRequest.StartOperation () [0x0003c] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.AsyncProtocolRequest.StartOperation (Mono.Net.Security.AsyncOperation operation) [0x00024] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.MobileAuthenticatedStream.ProcessAuthentication (System.Net.LazyAsyncResult lazyResult) [0x00057] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>--- End of stack trace from previous location where exception was thrown ---
>  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <3fd174ff54b146228c505f23cf75ce71>:0 
>  at Mono.Net.Security.MobileAuthenticatedStream.ProcessAuthentication (System.Net.LazyAsyncResult lazyResult) [0x00078] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.MobileAuthenticatedStream.AuthenticateAsClient (System.String targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) [0x0000c] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.Private.MonoSslStreamWrapper.AuthenticateAsClient (System.String targetHost, System.Security.Cryptography.X509Certificates.X509CertificateCollection clientCertificates, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) [0x00006] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at Mono.Net.Security.MonoTlsStream.CreateStream (System.Byte[] buffer) [0x0007b] in <a547bd0d78184f26ab08d022f013c1e1>:0 
>  at System.Net.WebConnection.CreateStream (System.Net.HttpWebRequest request) [0x00073] in <a547bd0d78184f26ab08d022f013c1e1>:0
Comment 13 Marek Safar 2017-05-27 06:54:37 UTC
Martin, any insight what could be wrong?
Comment 14 Martin Baulig 2017-05-31 18:33:10 UTC
If I understand this correctly, then you're doing multiple requests and cancel some of them?

Unfortunately, such cancellation depends on having reliable shutdown / dispose support in the underlying SslStream.  At the moment, that code has several issues.

For instance, an attempt to close the SslStream while you're currently sending or receiving data can have all kinds of funny side-effects.  Sometimes you get lucky, sometimes you may even crash the runtime.

This is part of an ongoing project that I'm currently working on - the goal is to provide correct and reliable shutdown, timeout and cleanup behavior in SslStream while also improving its stability in multi-threaded situations.

The current ETA is to have the code done by the end of this week - then have next week and maybe the week after for testing and bug fixing.

This will affect all our TLS implementations - Legacy, AppleTls and BTLS - as they're all sharing some of the same code in the backend.
Comment 15 Martin Baulig 2017-05-31 18:33:44 UTC
Assigning to me.
Comment 16 Martin Baulig 2017-05-31 22:27:40 UTC
So turns out this is actually not a TLS issue - it's a general limitation in our web stack which may be very hard to fix.  You are also very unlucky to just trigger the circumstances.

If you use HttpClient with the default HttpClientHandler, this will use HttpWebRequest as the backend - and with it the ServicePoint mechanic.

Switching to a different HttpClientHandler backend might help.

What happens in HttpWebRequest is that after successful completion, it will keep the underlying connection open and cache it in the ServicePoint to possibly reuse it later.

If you cancel milliseconds after a successful completion and then immediately send another request to the same server, you may hit a very small window during which the cancellation triggers _after_ the previous connection has already been selected for reuse by the new request.  So in other words, the second request will incorrectly get its connection shut down by the cancellation of the first one.

You should be able to see this in your test case if you add a ~500ms delay after each of your request.

While the underlying ServicePoint mechanic could be very hard to fix - we might be able to work around that by simply making sure that we properly unregister cancellation before returning from HttpClient.SendAsync().
Comment 21 Morten Nielsen 2017-06-01 16:09:25 UTC
I'm good with the workaround if that works. This is a major problem for our stuff and affects a lot of our customers using our library (this is a Map control that makes a lot of tile requests, but when you zoom fast, a lot of tiles might not be needed after all, so we cancel them).
Comment 22 Chris Miller 2017-06-02 13:26:10 UTC
I would be happy with the unregister cancellation workaround from comment #16.  I'm one of the clients using the map control.  Scrolling a map (as opposed to scrolling a mao) is typical behavior and you would also see the problem when you zoomed in and out.
Comment 23 Morten Nielsen 2017-06-08 22:37:10 UTC
Any update on this issue Martin? Did the reordering of unregister not work after all?
Comment 24 Martin Baulig 2017-06-21 17:55:27 UTC
Unfortunately, there won't be any easy solution or workaround for this.

The bug is in the web stack, which has been written a long time ago.

However, the good news is that I spend the last two weeks during major refactoring and cleanups to the relevant code.  This work is nearly complete and we should hopefully be able to do QA testing somewhere next week.