diff options
author | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-03-18 16:39:54 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-03-18 16:39:54 +0300 |
commit | 5521ad349fdfa7e32ba3aa243a08127ece87810e (patch) | |
tree | cd177f3ce2d4823880527e07a46bf3737429446b /mcs/class/System.Net.Http | |
parent | e0326df7c6ff746fe8ab1105cced92f8ba8cb87e (diff) |
[System.Net.Http] Port https://github.com/xamarin/xamarin-macios/pull/5769 to mono
Diffstat (limited to 'mcs/class/System.Net.Http')
-rw-r--r-- | mcs/class/System.Net.Http/NSUrlSessionHandler.cs | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/mcs/class/System.Net.Http/NSUrlSessionHandler.cs b/mcs/class/System.Net.Http/NSUrlSessionHandler.cs index e48129c0877..17835da99f6 100644 --- a/mcs/class/System.Net.Http/NSUrlSessionHandler.cs +++ b/mcs/class/System.Net.Http/NSUrlSessionHandler.cs @@ -204,7 +204,12 @@ namespace Foundation { void RemoveInflightData (NSUrlSessionTask task, bool cancel = true) { lock (inflightRequestsLock) { - inflightRequests.Remove (task); + if (inflightRequests.TryGetValue (task, out var data)) { + if (cancel) + data.CancellationTokenSource.Cancel (); + data.Dispose (); + inflightRequests.Remove (task); + } #if !MONOMAC && !MONOTOUCH_WATCH // do we need to be notified? If we have not inflightData, we do not if (inflightRequests.Count == 0) @@ -228,6 +233,7 @@ namespace Foundation { foreach (var pair in inflightRequests) { pair.Key?.Cancel (); pair.Key?.Dispose (); + pair.Value?.Dispose (); } inflightRequests.Clear (); @@ -307,6 +313,7 @@ namespace Foundation { RequestUrl = request.RequestUri.AbsoluteUri, CompletionSource = tcs, CancellationToken = cancellationToken, + CancellationTokenSource = new CancellationTokenSource (), Stream = new NSUrlSessionDataTaskStream (), Request = request }); @@ -385,7 +392,7 @@ namespace Foundation { inflight.Stream.TrySetException (new ObjectDisposedException ("The content stream was disposed.")); sessionHandler.RemoveInflightData (dataTask); - }, inflight.CancellationToken); + }, inflight.CancellationTokenSource.Token); // NB: The double cast is because of a Xamarin compiler bug var httpResponse = new HttpResponseMessage ((HttpStatusCode)status) { @@ -449,6 +456,8 @@ namespace Foundation { // send the error or send the response back if (error != null) { + // got an error, cancel the stream operatios before we do anything + inflight.CancellationTokenSource.Cancel (); inflight.Errored = true; var exc = createExceptionForNSError (error); @@ -469,6 +478,9 @@ namespace Foundation { if (inflight.ResponseSent) return; + if (inflight.CancellationTokenSource.Token.IsCancellationRequested) + return; + if (inflight.CompletionSource.Task.IsCompleted) return; @@ -566,13 +578,14 @@ namespace Foundation { // Needed since we strip during linking since we're inside a product assembly. [Preserve (AllMembers = true)] #endif - class InflightData + class InflightData : IDisposable { public readonly object Lock = new object (); public string RequestUrl { get; set; } public TaskCompletionSource<HttpResponseMessage> CompletionSource { get; set; } public CancellationToken CancellationToken { get; set; } + public CancellationTokenSource CancellationTokenSource { get; set; } public NSUrlSessionDataTaskStream Stream { get; set; } public HttpRequestMessage Request { get; set; } public HttpResponseMessage Response { get; set; } @@ -582,6 +595,24 @@ namespace Foundation { public bool Disposed { get; set; } public bool Completed { get; set; } public bool Done { get { return Errored || Disposed || Completed || CancellationToken.IsCancellationRequested; } } + + public void Dispose() + { + Dispose (true); + GC.SuppressFinalize(this); + } + + // The bulk of the clean-up code is implemented in Dispose(bool) + protected virtual void Dispose (bool disposing) + { + if (disposing) { + if (CancellationTokenSource != null) { + CancellationTokenSource.Dispose (); + CancellationTokenSource = null; + } + } + } + } #if MONOMAC @@ -678,7 +709,13 @@ namespace Foundation { } } - await Task.Delay (50).ConfigureAwait (false); + try { + await Task.Delay (50, cancellationToken).ConfigureAwait (false); + } catch (TaskCanceledException ex) { + // add a nicer exception for the user to catch, add the cancelation exception + // to have a decent stack + throw new TimeoutException ("The request timed out.", ex); + } } // try to throw again before read |