Skip to content

Commit 96ca6d7

Browse files
author
Ignacio Bonafonte
authored
Merge pull request #425 from andraskadar/bugfix/requestMapAccess
Fix: Access requestMap only on the protected queue Accessing the content of the requestMap asynchronously on any thread can lead to concurrency issues and crashes. These changes refactor the code without introducing changes to the behaviour to make sure that even reading of the dictionary happens on the dedicated queue. The root cause of this is that when a task has a delegate the same code is called twice, once in didFinishCollecting and once in didCompleteWithError. The didFinishCollecting was added because in iOS 16 and async network calls the didCompleteWithError was never called, but it ended up being called twice in cases like this.
2 parents 334f00a + 50c0e53 commit 96ca6d7

File tree

1 file changed

+19
-14
lines changed

1 file changed

+19
-14
lines changed

Sources/Instrumentation/URLSession/URLSessionInstrumentation.swift

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -549,22 +549,27 @@ public class URLSessionInstrumentation {
549549

550550
private func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
551551
let taskId = self.idKeyForTask(task)
552-
if (self.requestMap[taskId]?.request) != nil {
553-
/// Code for instrumenting colletion should be written here
554-
var requestState: NetworkRequestState?
555-
queue.sync {
556-
requestState = requestMap[taskId]
557-
if requestState != nil {
558-
requestMap[taskId] = nil
559-
}
560-
}
561-
if let error = task.error {
562-
let status = (task.response as? HTTPURLResponse)?.statusCode ?? 0
563-
URLSessionLogger.logError(error, dataOrFile: requestState?.dataProcessed, statusCode: status, instrumentation: self, sessionTaskId: taskId)
564-
} else if let response = task.response {
565-
URLSessionLogger.logResponse(response, dataOrFile: requestState?.dataProcessed, instrumentation: self, sessionTaskId: taskId)
552+
553+
var requestState: NetworkRequestState?
554+
queue.sync {
555+
requestState = requestMap[taskId]
556+
557+
if requestState?.request != nil {
558+
requestMap[taskId] = nil
566559
}
567560
}
561+
562+
guard requestState?.request != nil else {
563+
return
564+
}
565+
566+
/// Code for instrumenting colletion should be written here
567+
if let error = task.error {
568+
let status = (task.response as? HTTPURLResponse)?.statusCode ?? 0
569+
URLSessionLogger.logError(error, dataOrFile: requestState?.dataProcessed, statusCode: status, instrumentation: self, sessionTaskId: taskId)
570+
} else if let response = task.response {
571+
URLSessionLogger.logResponse(response, dataOrFile: requestState?.dataProcessed, instrumentation: self, sessionTaskId: taskId)
572+
}
568573
}
569574

570575
private func urlSessionTaskWillResume(_ task: URLSessionTask) {

0 commit comments

Comments
 (0)