Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions src/Foundation/NSUrlSessionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,9 @@ public NSUrlSessionHandler (NSUrlSessionConfiguration configuration)
void RemoveInflightData (NSUrlSessionTask task, bool cancel = true)
{
lock (inflightRequestsLock) {
if (inflightRequests.TryGetValue (task, out var data)) {
if (inflightRequests.Remove (task, out var data)) {
if (cancel)
data.CancellationTokenSource.Cancel ();
inflightRequests.Remove (task);
}
}

Expand All @@ -192,14 +191,16 @@ void RemoveInflightData (NSUrlSessionTask task, bool cancel = true)
/// <inheritdoc />
protected override void Dispose (bool disposing)
{
var tasks = new List<NSUrlSessionTask> ();
lock (inflightRequestsLock) {
foreach (var pair in inflightRequests) {
pair.Key?.Cancel ();
pair.Key?.Dispose ();
}

tasks.AddRange (inflightRequests.Keys);
inflightRequests.Clear ();
}
foreach (var task in tasks) {
task.Cancel ();
task.Dispose ();
}
Comment on lines +194 to +202
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Dispose, inflightRequests.Clear () happens before canceling tasks, so any subsequent DidCompleteWithError / DidReceiveData delegate callbacks won’t be able to retrieve the corresponding InflightData from inflightRequests. Since InflightData.CompletionSource is only completed when GetInflightData finds an entry, this can leave callers awaiting SendAsync permanently blocked if the handler is disposed while requests are in-flight. Consider capturing the InflightData instances (not just the tasks) while holding the lock and explicitly completing/canceling their CompletionSource (and canceling InflightData.CancellationTokenSource / faulting the stream) as part of Dispose, instead of relying on delegate callbacks after the dictionary is cleared.

Copilot uses AI. Check for mistakes.

session.InvalidateAndCancel ();
base.Dispose (disposing);
}
Expand Down
Loading