From 144e1e4b47b5188fc3c18f94acc09d2c038eccd2 Mon Sep 17 00:00:00 2001 From: Brandon-T Date: Fri, 20 Dec 2024 11:02:48 -0500 Subject: [PATCH] [iOS] - Fix alert continuation leak when WebKit automatically cancels the request (#27069) Fix alert continuation leak when WebKit automatically cancels the request. --- .../BVC+WKNavigationDelegate.swift | 25 ++++++++++++++++--- .../Sources/Brave/Frontend/Browser/Tab.swift | 3 +++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ios/brave-ios/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+WKNavigationDelegate.swift b/ios/brave-ios/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+WKNavigationDelegate.swift index cabeb27f43a1..bf7cabb06e6b 100644 --- a/ios/brave-ios/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+WKNavigationDelegate.swift +++ b/ios/brave-ios/Sources/Brave/Frontend/Browser/BrowserViewController/BVC+WKNavigationDelegate.swift @@ -171,6 +171,15 @@ extension BrowserViewController: WKNavigationDelegate { guard var requestURL = navigationAction.request.url else { return (.cancel, preferences) } + + let tab = tab(for: webView) + if tab?.isExternalAppAlertPresented == true { + tab?.externalAppPopup?.dismissWithType(dismissType: .noAnimation) + tab?.externalAppPopupContinuation?.resume(with: .success(false)) + tab?.externalAppPopupContinuation = nil + tab?.externalAppPopup = nil + } + if InternalURL.isValid(url: requestURL) { if navigationAction.navigationType != .backForward, navigationAction.isInternalUnprivileged, navigationAction.sourceFrame != nil || navigationAction.targetFrame?.isMainFrame == false @@ -204,7 +213,6 @@ extension BrowserViewController: WKNavigationDelegate { // First special case are some schemes that are about Calling. We prompt the user to confirm this action. This // gives us the exact same behaviour as Safari. - let tab = tab(for: webView) if ["sms", "tel", "facetime", "facetime-audio"].contains(requestURL.scheme) { let shouldOpen = await handleExternalURL( @@ -1264,6 +1272,8 @@ extension BrowserViewController { titleSize: 21 ) + tab?.externalAppPopup = popup + if isSuppressActive { popup.addButton(title: Strings.suppressAlertsActionTitle, type: .destructive) { [weak tab] () -> PopupViewDismissType in @@ -1322,10 +1332,17 @@ extension BrowserViewController { tab?.externalAppAlertCounter += 1 - return await withCheckedContinuation { continuation in - showExternalSchemeAlert(isSuppressActive: tab?.externalAppAlertCounter ?? 0 > 2) { - continuation.resume(with: .success($0)) + return await withTaskCancellationHandler { + return await withCheckedContinuation { [weak tab] continuation in + tab?.externalAppPopupContinuation = continuation + showExternalSchemeAlert(isSuppressActive: tab?.externalAppAlertCounter ?? 0 > 2) { + tab?.externalAppPopupContinuation = nil + continuation.resume(with: .success($0)) + } } + } onCancel: { [weak tab] in + tab?.externalAppPopupContinuation?.resume(with: .success(false)) + tab?.externalAppPopupContinuation = nil } } } diff --git a/ios/brave-ios/Sources/Brave/Frontend/Browser/Tab.swift b/ios/brave-ios/Sources/Brave/Frontend/Browser/Tab.swift index d7ef6a5a3f7b..5ce4cd8284e5 100644 --- a/ios/brave-ios/Sources/Brave/Frontend/Browser/Tab.swift +++ b/ios/brave-ios/Sources/Brave/Frontend/Browser/Tab.swift @@ -4,6 +4,7 @@ import BraveCore import BraveShields +import BraveUI import BraveWallet import CertificateUtilities import Data @@ -429,6 +430,8 @@ class Tab: NSObject { /// Boolean tracking custom url-scheme alert presented var isExternalAppAlertPresented = false + var externalAppPopup: AlertPopupView? + var externalAppPopupContinuation: CheckedContinuation? var externalAppAlertCounter = 0 var isExternalAppAlertSuppressed = false var externalAppURLDomain: String?