Bug 20134 - Hanging writing to Chunked HttpWebRequest
Summary: Hanging writing to Chunked HttpWebRequest
Status: RESOLVED FIXED
Alias: None
Product: iOS
Classification: Xamarin
Component: BCL Class Libraries ()
Version: 7.2.3
Hardware: Macintosh Mac OS
: High major
Target Milestone: Untriaged
Assignee: Martin Baulig
URL:
Depends on:
Blocks:
 
Reported: 2014-05-29 10:24 UTC by Justin Caldicott
Modified: 2016-11-11 10:02 UTC (History)
7 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 Justin Caldicott 2014-05-29 10:24:56 UTC
Hi,

I just took the latest Xamarin 3 update, and I'm getting frequent hanging writing to an chunked, unbuffered HttpWebRequest, on iOS.  (Simulator, 7.2.3.39 Business Edition)  I notice this update includes Mono 3.4 which has a number of changes in this area.  I therefore expect this to be an issue not just on iOS.

The request is being written on a threadpool thread, and there are no other threads involved AFAIK.  The code:

    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(m_serviceEndpoint);

    const int timeout = 1000000;  // High timeout probably irrelevant, but included for completeness
    webRequest.Timeout = timeout;
    webRequest.ReadWriteTimeout = timeout;
    webRequest.Method = "POST";
    webRequest.ContentType = "application/octet-stream";
    webRequest.AllowWriteStreamBuffering = false;
    webRequest.SendChunked = true;

    using(Stream requestStream = webRequest.GetRequestStream())
    {
        ....
    }

The hanging happens in WebConnectionStream.cs, waiting for a ManualResetEvent here:

    public override void Close ()
    {
        ....
        pending.WaitOne ();

The current value of pendingWrites is -1, which explains the hang.  From a brief look, it should only be possible if either:
 - A call to EndWrite() is made before a corresponding call to BeginWrite().
 - SendChunked is changed.  I couldn't see anywhere in WebConnectionStream.cs where the value is changed, but there is a property marked internal.

For now, I've enabled buffering and disabled chunking, which works perfectly again.  But our apps will run out of memory doing this, so we really need a proper solution.

Best wishes,

Justin
Comment 1 Justin Caldicott 2014-06-17 05:53:43 UTC
Hi,

We also hit bug 18944 in Xamarin 3, so we've rolled back to releases made on 10th March for everything.

Just wanted to confirm that chunked http requests seem to work fine on these older builds, both on Android and iOS.

Any estimates on when this will be addressed?  We cannot take any updates until it is fixed.

Best wishes,

Justin
Comment 2 Jonathan Mitchell 2014-08-08 14:01:57 UTC
This also affects OSX with Xamarin 5.2 installed.
A simple XML POST leaves or dies according to whether chunking is enabled or not.

public void SimplePost(string xml, string uri) 
		{
			Console.WriteLine("Post Request...");

			try {
				var bytes = Encoding.UTF8.GetBytes(xml);
				var request = (HttpWebRequest) WebRequest.Create(uri);
				bool doPost = true;

				if (doPost) {
					request.Method = "POST";
					request.ContentType = "text/xml; charset=utf-8";
					request.ContentLength = bytes.Length;
					request.SendChunked = true;	// Live or die on OS X according to whether we chunk : true == die
					request.Proxy = null;
				}

				request.GetRequestStream().Write(bytes, 0, bytes.Length);

				HttpWebResponse response = (HttpWebResponse) request.GetResponse();
				Encoding responseEncoding = Encoding.GetEncoding(response.CharacterSet);
				string result = null;
				using (StreamReader sr = new StreamReader(response.GetResponseStream(), responseEncoding))
				{
					result = sr.ReadToEnd();
				}

				Console.WriteLine("Post Response : \n");
				Console.WriteLine(result);
				Console.WriteLine("");

			} catch (Exception exception) {
				Console.WriteLine(exception.Message);
				Console.WriteLine(exception.StackTrace);
			}
		}
Comment 3 Justin Caldicott 2014-08-30 09:59:50 UTC
Hi,

I've just installed Xamarin 3.5 (I think it was 3.5.55, but I can't find how to check the installed version number), which I assumed would have the fix, but no joy.

I assumed it would have the fix, as I found this commit:
https://github.com/mono/mono/commit/288489d63707e17134cc8857ca59937f703fa8e0

That references another chunk related bug:
https://bugzilla.xamarin.com/show_bug.cgi?id=20583

That was included in Xamarin.Android 4.16:
http://developer.xamarin.com/releases/android/xamarin.android_4/xamarin.android_4.16/#Xamarin.Android_4.16.0

I saw no mention of this bug number directly, and this seemed the most likely candidate.

So either:
 - The 3.5 universal installer I downloaded didn't include 4.16 (I've just posted a thread asking how to find out what android version I've got installed http://forums.xamarin.com/discussion/23228/version-numbers?new=1), or
 - This is a different bug and it wasn't actually resolved.

Martin, can you help here?  Did you reproduce and fix this *particular* problem?

For now I'll have to rollback to a build from 10th March.  This is a big problem for us, as we're hoping to ship very soon and are seeing issues in our Release builds that I was hoping newer versions would fix...

Thanks,

Justin

ps. As a side note, it's really hard to work out what I need to download to get a particular fix.
Comment 4 Martin Baulig 2014-09-01 14:29:13 UTC
Hmm, I run chunked POST tests as part of my new test suite and they're working just fine with the new code.

From your test case in Comment #2, it seems like you're not actually closing the request stream anywhere.  Simply calling

    request.GetRequestStream().Write(bytes, 0, bytes.Length);

may also not immediately flush the data.

Can you try wrapping this in a "using" statement?

While working on my new test suite, I found that not closing the request stream may cause such hangs because the server may think that you'll send more data on that stream.
Comment 5 Justin Caldicott 2014-09-01 19:27:40 UTC
Thanks for the response.  Unfortunately the code you mention is from another user.    Our code is in the first post, and has the request & response streams wrapped in using.

I'm sure there's something happening in the mono code, as the same assemblies runs fine on Android, iOS (using older builds) & Windows (using MS .NET framework).

Do your tests also cover AllowWriteStreamBuffering = false?  There's about 25x requests, returning between 1-20MB of gzipped json in the responses.
Comment 6 Martin Baulig 2016-11-11 10:02:00 UTC
Closing ancient bugs, please reopen if you're still having this problem.