Bug 32641 - System.Net.WebClient throws Stack Overflow in UploadBitsWriteCallback on large files (+40MB)
Summary: System.Net.WebClient throws Stack Overflow in UploadBitsWriteCallback on larg...
Status: CONFIRMED
Alias: None
Product: Class Libraries
Classification: Mono
Component: System (show other bugs)
Version: 4.0.0
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2015-07-30 17:03 UTC by Matt Gerega
Modified: 2015-07-31 06:03 UTC (History)
2 users (show)

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


Attachments
Full Stack Trace at Error (53.42 KB, text/plain)
2015-07-30 17:03 UTC, Matt Gerega
Details

Description Matt Gerega 2015-07-30 17:03:24 UTC
Created attachment 12308 [details]
Full Stack Trace at Error

When uploading a large file (+40MB), the WebClient is generating a StackOverflowException.  In Xamarin.iOS in the iOS 8.4 iPad simulator, it's typically in the static private void UploadBitsWriteCallback(IAsyncResult result) function, but the full stack trace is attached.  This behavior seems to be new as of 4.0.0, as previous builds were able to upload large files using this method.

Function Context:
        var client = new WebClient();
	client.UploadProgressChanged += (sender, e) =>
					{
					 // Some notification functionality, but commenting it out still 
                                         // produces the error
					};

					client.UploadFileCompleted += (sender, e) => 
					{
						// never reached
					};
						
					// we include the fileURLPath as a query string parameter to allow the web page to know the file
					//   name that it needs to save the uploaded file as.
					string uploadURL = "some url to push to";

					client.UploadFileAsync(new Uri(uploadURL), "file to push");
				}
Comment 1 Marek Safar 2015-07-31 06:03:47 UTC
This is due WebConnectionStream write buffering not flushing (chunked buffering). Whole input stream is MemoryStream buffered before writing which either stackoverflows in BeginWrite or OOM due to storing whole input data stream to memory.

I am not sure this is worth fixing instead of using reference sources internal ConnectStream.

For a workaround switch to HttpClient which does this much better but it's missing progress reporting. If you need progress reporting you will have to implement it yourself but that should be easy by wrapping input stream.


Code used for testing

	class MainClass
	{
		public static void Main (string[] args)
		{
			var client = new WebClient();
			client.UploadProgressChanged += (sender, e) =>
			{
				// Some notification functionality, but commenting it out still 
				// produces the error
				Console.WriteLine (e.BytesSent);
				return;
			};

			client.UploadFileCompleted += (sender, e) => 
			{
				// never reached
				return;
			};

			// we include the fileURLPath as a query string parameter to allow the web page to know the file
			//   name that it needs to save the uploaded file as.
			string uploadURL = "http://posttestserver.com/post.php";
			var uri = new Uri(uploadURL);
			client.UploadFileAsync(uri, "large.file");
			Console.ReadLine ();
		}
	}

Note You need to log in before you can comment on or make changes to this bug.