diff --git a/src/Foundation/NSUrlSessionHandler.cs b/src/Foundation/NSUrlSessionHandler.cs index 3d348d71decf..e25f6ced2c98 100644 --- a/src/Foundation/NSUrlSessionHandler.cs +++ b/src/Foundation/NSUrlSessionHandler.cs @@ -212,9 +212,15 @@ InflightData GetInflightData (NSUrlSessionTask task) var inflight = default (InflightData); lock (sessionHandler.inflightRequestsLock) - if (sessionHandler.inflightRequests.TryGetValue (task, out inflight)) + if (sessionHandler.inflightRequests.TryGetValue (task, out inflight)) { + // ensure that we did not cancel the request, if we did, do cancel the task + if (inflight.CancellationToken.IsCancellationRequested) + task?.Cancel (); return inflight; + } + // if we did not manage to get the inflight data, we either got an error or have been canceled, lets cancel the task, that will execute DidCompleteWithError + task?.Cancel (); return null; } @@ -222,16 +228,23 @@ public override void DidReceiveResponse (NSUrlSession session, NSUrlSessionDataT { var inflight = GetInflightData (dataTask); + if (inflight == null) + return; + try { var urlResponse = (NSHttpUrlResponse)response; var status = (int)urlResponse.StatusCode; var content = new NSUrlSessionDataTaskStreamContent (inflight.Stream, () => { + if (!inflight.Completed) { + dataTask.Cancel (); + } + inflight.Disposed = true; inflight.Stream.TrySetException (new ObjectDisposedException ("The content stream was disposed.")); sessionHandler.RemoveInflightData (dataTask); - }); + }, inflight.CancellationToken); // NB: The double cast is because of a Xamarin compiler bug var httpResponse = new HttpResponseMessage ((HttpStatusCode)status) { @@ -270,6 +283,9 @@ public override void DidReceiveData (NSUrlSession session, NSUrlSessionDataTask { var inflight = GetInflightData (dataTask); + if (inflight == null) + return; + inflight.Stream.Add (data); SetResponse (inflight); } @@ -278,7 +294,7 @@ public override void DidCompleteWithError (NSUrlSession session, NSUrlSessionTas { var inflight = GetInflightData (task); - // this can happen if the HTTP request times out and it is removed as part of the cancelation process + // this can happen if the HTTP request times out and it is removed as part of the cancellation process if (inflight != null) { // set the stream as finished inflight.Stream.TrySetReceivedAllData (); @@ -329,6 +345,11 @@ public override void WillPerformHttpRedirection (NSUrlSession session, NSUrlSess public override void DidReceiveChallenge (NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action completionHandler) { + var inflight = GetInflightData (task); + + if (inflight == null) + return; + // case for the basic auth failing up front. As per apple documentation: // The URL Loading System is designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers using // the addValue(_:forHTTPHeaderField:) or setValue(_:forHTTPHeaderField:) methods: @@ -343,7 +364,7 @@ public override void DidReceiveChallenge (NSUrlSession session, NSUrlSessionTask // header, it means that we do not have the correct credentials, in any other case just do what it is expected. if (challenge.PreviousFailureCount == 0) { - var authHeader = GetInflightData (task)?.Request?.Headers?.Authorization; + var authHeader = inflight.Request?.Headers?.Authorization; if (!(string.IsNullOrEmpty (authHeader?.Scheme) && string.IsNullOrEmpty (authHeader?.Parameter))) { completionHandler (NSUrlSessionAuthChallengeDisposition.RejectProtectionSpace, null); return; @@ -354,7 +375,7 @@ public override void DidReceiveChallenge (NSUrlSession session, NSUrlSessionTask if (sessionHandler.Credentials != null) { var credentialsToUse = sessionHandler.Credentials as NetworkCredential; if (credentialsToUse == null) { - var uri = GetInflightData (task).Request.RequestUri; + var uri = inflight.Request.RequestUri; credentialsToUse = sessionHandler.Credentials.GetCredential (uri, "NTLM"); } var credential = new NSUrlCredential (credentialsToUse.UserName, credentialsToUse.Password, NSUrlCredentialPersistence.ForSession); @@ -396,7 +417,7 @@ class NSUrlSessionDataTaskStreamContent : StreamContent { Action disposed; - public NSUrlSessionDataTaskStreamContent (NSUrlSessionDataTaskStream source, Action onDisposed) : base (source) + public NSUrlSessionDataTaskStreamContent (NSUrlSessionDataTaskStream source, Action onDisposed, CancellationToken token) : base (source, token) { disposed = onDisposed; }