Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Fix #8057: Add Download Delegate to handle PassKit blobs #8588

Merged
merged 1 commit into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions Sources/Brave/Frontend/Browser/BrowserViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ public class BrowserViewController: UIViewController {
var downloadToast: DownloadToast? // A toast that is showing the combined download progress
var addToPlayListActivityItem: (enabled: Bool, item: PlaylistInfo?)? // A boolean to determine If AddToListActivity should be added
var openInPlaylistActivityItem: (enabled: Bool, item: PlaylistInfo?)? // A boolean to determine if OpenInPlaylistActivity should be shown
var shouldDownloadNavigationResponse: Bool = false
var pendingDownloads = [WKDownload: PendingDownload]()

var navigationToolbar: ToolbarProtocol {
return toolbar ?? topToolbar
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2021 The Brave Authors. All rights reserved.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

import Foundation
import WebKit
import PassKit
import Shared

extension BrowserViewController: WKDownloadDelegate {

struct PendingDownload: Hashable, Equatable {
let fileURL: URL
let response: URLResponse
let suggestedFileName: String
}

public func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String) async -> URL? {
let temporaryDir = NSTemporaryDirectory()
let fileName = temporaryDir + "/" + suggestedFilename
let url = URL(fileURLWithPath: fileName)
pendingDownloads[download] = PendingDownload(fileURL: url, response: response, suggestedFileName: suggestedFilename)
return url
}

public func download(_ download: WKDownload, decidedPolicyForHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest) async -> WKDownload.RedirectPolicy {
return .allow
}

public func download(_ download: WKDownload, respondTo challenge: URLAuthenticationChallenge) async -> (URLSession.AuthChallengeDisposition, URLCredential?) {
return (.performDefaultHandling, nil)
}

@MainActor
public func downloadDidFinish(_ download: WKDownload) {
guard let downloadInfo = pendingDownloads[download] else {
return
}

pendingDownloads.removeValue(forKey: download)

let response = URLResponse(url: downloadInfo.fileURL,
mimeType: downloadInfo.response.mimeType,
expectedContentLength: Int(downloadInfo.response.expectedContentLength),
textEncodingName: downloadInfo.response.textEncodingName)

if let passbookHelper = OpenPassBookHelper(request: nil, response: response, canShowInWebView: false, forceDownload: false, browserViewController: self) {
passbookHelper.open()
}

Task {
try FileManager.default.removeItem(at: downloadInfo.fileURL)
}
}

@MainActor
public func download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?) {
// display an error
let alertController = UIAlertController(
title: Strings.unableToAddPassErrorTitle,
message: Strings.unableToAddPassErrorMessage,
preferredStyle: .alert)
alertController.addAction(
UIAlertAction(title: Strings.unableToAddPassErrorDismiss, style: .cancel) { (action) in
// Do nothing.
}
)
present(alertController, animated: true, completion: nil)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,10 @@ extension BrowserViewController: WKNavigationDelegate {
self.tabManager.selectedTab?.blockAllAlerts = false
}

if navigationAction.shouldPerformDownload {
self.shouldDownloadNavigationResponse = true
}

return (.allow, preferences)
}

Expand Down Expand Up @@ -493,6 +497,14 @@ extension BrowserViewController: WKNavigationDelegate {
}

// Check if this response should be handed off to Passbook.
if shouldDownloadNavigationResponse {
shouldDownloadNavigationResponse = false

if response.mimeType == MIMEType.passbook {
return .download
}
}

if let passbookHelper = OpenPassBookHelper(request: request, response: response, canShowInWebView: canShowInWebView, forceDownload: forceDownload, browserViewController: self) {
// Open our helper and cancel this response from the webview.
passbookHelper.open()
Expand Down Expand Up @@ -529,11 +541,23 @@ extension BrowserViewController: WKNavigationDelegate {

tab.mimeType = response.mimeType
}

if canShowInWebView {
return .allow
}

// If none of our helpers are responsible for handling this response,
// just let the webview handle it as normal.
return .allow
}

public func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
Logger.module.error("ERROR: Should Never download NavigationAction since we never return .download from decidePolicyForAction.")
}

public func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
download.delegate = self
}

nonisolated public func webView(_ webView: WKWebView, respondTo challenge: URLAuthenticationChallenge) async -> (URLSession.AuthChallengeDisposition, URLCredential?) {

Expand Down
28 changes: 28 additions & 0 deletions Sources/Brave/Frontend/Browser/TabManagerNavDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ class TabManagerNavDelegate: NSObject, WKNavigationDelegate {
res = policy
}

if policy == .download {
res = policy
}

pref = preferences
}
}
Expand All @@ -127,6 +131,10 @@ class TabManagerNavDelegate: NSObject, WKNavigationDelegate {
if policy == .cancel {
res = policy
}

if policy == .download {
res = policy
}
}
}

Expand All @@ -137,4 +145,24 @@ class TabManagerNavDelegate: NSObject, WKNavigationDelegate {

return res
}

@MainActor
public func webView(_ webView: WKWebView, navigationAction: WKNavigationAction, didBecome download: WKDownload) {
for delegate in delegates {
delegate.webView?(webView, navigationAction: navigationAction, didBecome: download)
if download.delegate != nil {
return
}
}
}

@MainActor
public func webView(_ webView: WKWebView, navigationResponse: WKNavigationResponse, didBecome download: WKDownload) {
for delegate in delegates {
delegate.webView?(webView, navigationResponse: navigationResponse, didBecome: download)
if download.delegate != nil {
return
}
}
}
}