Bug 51423 - HttpClient hangs indefinitely when internet connection is lost during a chunked POST transfer
Summary: HttpClient hangs indefinitely when internet connection is lost during a chunk...
Status: RESOLVED FIXED
Alias: None
Product: iOS
Classification: Xamarin
Component: BCL Class Libraries ()
Version: XI 10.4 (C9)
Hardware: PC Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Manuel de la Peña [MSFT]
URL:
Depends on:
Blocks:
 
Reported: 2017-01-11 20:30 UTC by Rob DeRosa
Modified: 2017-04-19 15:39 UTC (History)
9 users (show)

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

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 on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Rob DeRosa 2017-01-11 20:30:30 UTC
When executing a POST chunked transfer request using HttpClient, network disconnect (wifi or cell access is killed) causes no response and HttpClient will hang indefinitely (no exception or response back). This behavior was exhibited using NSUrlSession, Managed and CFNetwork implementations.

This behavior was NOT exhibited when using ModernHttpClient - the network disconnect is reported back right away.

This does not happen on Android, only iOS.

This was experienced on stable and alpha channels

Xamarin   4.3.0.525 (a09a85e)
Xamarin.Android   7.1.0.17 (4833277)
Xamarin.iOS   10.4.0.67 (6a925ff)
Comment 1 Manuel de la Peña [MSFT] 2017-01-16 09:54:42 UTC
Hello,

Can you please post an example on how you are using the HttpClient. What I mean, are you using the async to the sync API. Would be interesting to know since it might be the ase that the disconnection gets notified from the low level API but we might not be reporting the timeout or disconnection correctly. A small example would help us replicate the exact issue and find what is the API that is failing.

Thanks.
Comment 5 PM Lemay 2017-02-21 17:09:59 UTC
Hello, we are also experiencing issues with HttpClient hanging in iOS.

In fact, losing internet while executing the method HttpClient.SendAsync with ResponseContentRead option will hang indefinitely until internet is back up. It will then finish the processing normally and execute the following code. 

Expected behaviour: when going and staying offline, the request should either throw an error or timeout after the current httpClient timeout option and not hang indefinitely.

The test was made in iOS using an iPad and going in airplane mode while doing the request.
In Windows, we turned off the wifi during the request and automatically received the following error: System.Net.Http.HttpRequestException: Error while copying content to a stream. System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

Here is the code:

HttpClient httpClient = new HttpClient();
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
await httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead, cancellationToken).ConfigureAwait(false);

System.Net.Http, Version=4.0.0.0
Comment 6 Manuel de la Peña [MSFT] 2017-02-22 11:41:19 UTC
Hello,

Working on it will post a comment with the PR with the fix ASAP.
Comment 7 Manuel de la Peña [MSFT] 2017-03-20 11:28:19 UTC
A fix for the NSRulrSession handler has been posted here: https://github.com/xamarin/xamarin-macios/pull/1888

The managed version does return an exception when a download is being processed using the async mode:

2017-03-20 11:57:37.150 HttpClientTest[1007:638455] Exception is System.IO.IOException: Unable to read data from the transport connection: Connection timed out. ---> System.Net.Sockets.SocketException: Connection timed out
  at System.Net.Sockets.Socket.EndReceive (System.IAsyncResult result) [0x0002d] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net.Sockets/Socket.cs:2000 
  at System.Net.Sockets.NetworkStream.EndRead (System.IAsyncResult asyncResult) [0x0005f] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/System/net/System/Net/Sockets/NetworkStream.cs:858 
   --- End of inner exception stack trace ---
  at System.Net.Sockets.NetworkStream.EndRead (System.IAsyncResult asyncResult) [0x00092] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/System/net/System/Net/Sockets/NetworkStream.cs:870 
  at System.Net.WebConnection.EndRead (System.Net.HttpWebRequest request, System.IAsyncResult result) [0x000f2] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net/WebConnection.cs:937 
  at System.Net.WebConnectionStream.EndRead (System.IAsyncResult r) [0x0003c] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/System/System.Net/WebConnectionStream.cs:412 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 
  at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1+ConfiguredTaskAwaiter[TResult].GetResult () [0x00000] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:535 
  at System.IO.Stream+<CopyToAsyncInternal>c__async0.MoveNext () [0x000a6] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/io/stream.cs:171 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128 
  at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in /Users/mandel/Xamarin/maccore-master/xamarin-macios/_ios-build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:113 
  at HttpClientTest.ViewController+<GetLargeFile>c__async0.MoveNext () [0x0018c] in /Users/mandel/Projects/HttpClientTest/HttpClientTest/ViewController.cs:28 

The code used to test it is as follows:

static async Task GetLargeFile ()
{
	try {
		using (HttpClient client = new HttpClient ()) {
			client.Timeout = new TimeSpan (0, 0, 5);
			const string url = "http://download.opensuse.org/distribution/13.2/iso/openSUSE-13.2-Addon-Lang-i586.iso";
			using (HttpResponseMessage response = await client.GetAsync (url, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait (false))
			using (Stream streamToReadFrom = await response.Content.ReadAsStreamAsync ()) {
				string fileToWriteTo = Path.GetTempFileName ();
				using (Stream streamToWriteTo = File.Open (fileToWriteTo, FileMode.Create)) {
					await streamToReadFrom.CopyToAsync (streamToWriteTo);
				}
				Console.WriteLine (response);
				Console.WriteLine (response.StatusCode);
			}
		}

		Console.WriteLine ("Download completed!!!!");
	} catch (Exception e) {
		Console.WriteLine ($"Exception is {e}");
	}
}

I'm working on a fix for the CFNetworkHandler to do detect the loss of connection.
Comment 8 Sebastien Pouliot 2017-03-22 13:10:13 UTC
Merged inn master https://github.com/xamarin/xamarin-macios/commit/cea59398712902ac12f85bfd2150aae81dcb3a4a

Keeping open to ensure this is added to our networking test suite.
Comment 9 Manuel de la Peña [MSFT] 2017-04-12 17:11:22 UTC
Closing since we now use https://bugzilla.xamarin.com/show_bug.cgi?id=51423 to track the work on the networking testing.