Serialize WebsitePoliciesData instead of WebsitePolicies
[WebKit-https.git] / Source / WebKit / UIProcess / Cocoa / NavigationState.mm
1 /*
2  * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "NavigationState.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIFrameInfo.h"
32 #import "APINavigationData.h"
33 #import "APINavigationResponse.h"
34 #import "APIString.h"
35 #import "APIURL.h"
36 #import "AuthenticationDecisionListener.h"
37 #import "CompletionHandlerCallChecker.h"
38 #import "Logging.h"
39 #import "NavigationActionData.h"
40 #import "PageLoadState.h"
41 #import "WKBackForwardListInternal.h"
42 #import "WKBackForwardListItemInternal.h"
43 #import "WKFrameInfoInternal.h"
44 #import "WKHistoryDelegatePrivate.h"
45 #import "WKNSDictionary.h"
46 #import "WKNSURLAuthenticationChallenge.h"
47 #import "WKNSURLExtras.h"
48 #import "WKNSURLRequest.h"
49 #import "WKNavigationActionInternal.h"
50 #import "WKNavigationDataInternal.h"
51 #import "WKNavigationDelegatePrivate.h"
52 #import "WKNavigationInternal.h"
53 #import "WKNavigationResponseInternal.h"
54 #import "WKReloadFrameErrorRecoveryAttempter.h"
55 #import "WKWebViewInternal.h"
56 #import "WebCredential.h"
57 #import "WebFrameProxy.h"
58 #import "WebNavigationState.h"
59 #import "WebPageProxy.h"
60 #import "WebProcessProxy.h"
61 #import "WebProtectionSpace.h"
62 #import "_WKErrorRecoveryAttempting.h"
63 #import "_WKFrameHandleInternal.h"
64 #import "_WKRenderingProgressEventsInternal.h"
65 #import "_WKSameDocumentNavigationTypeInternal.h"
66 #import "_WKWebsitePoliciesInternal.h"
67 #import <WebCore/Credential.h>
68 #import <WebCore/SecurityOriginData.h>
69 #import <WebCore/SerializedCryptoKeyWrap.h>
70 #import <WebCore/URL.h>
71 #import <wtf/BlockPtr.h>
72 #import <wtf/NeverDestroyed.h>
73
74 #if HAVE(APP_LINKS)
75 #import <pal/spi/cocoa/LaunchServicesSPI.h>
76 #endif
77
78 #if USE(QUICK_LOOK)
79 #import "QuickLookDocumentData.h"
80 #endif
81
82 using namespace WebCore;
83
84 namespace WebKit {
85
86 static HashMap<WebPageProxy*, NavigationState*>& navigationStates()
87 {
88     static NeverDestroyed<HashMap<WebPageProxy*, NavigationState*>> navigationStates;
89
90     return navigationStates;
91 }
92
93 NavigationState::NavigationState(WKWebView *webView)
94     : m_webView(webView)
95     , m_navigationDelegateMethods()
96     , m_historyDelegateMethods()
97 #if PLATFORM(IOS)
98     , m_releaseActivityTimer(RunLoop::current(), this, &NavigationState::releaseNetworkActivityToken)
99 #endif
100 {
101     ASSERT(m_webView->_page);
102     ASSERT(!navigationStates().contains(m_webView->_page.get()));
103
104     navigationStates().add(m_webView->_page.get(), this);
105     m_webView->_page->pageLoadState().addObserver(*this);
106 }
107
108 NavigationState::~NavigationState()
109 {
110     ASSERT(navigationStates().get(m_webView->_page.get()) == this);
111
112     navigationStates().remove(m_webView->_page.get());
113     m_webView->_page->pageLoadState().removeObserver(*this);
114 }
115
116 NavigationState& NavigationState::fromWebPage(WebPageProxy& webPageProxy)
117 {
118     ASSERT(navigationStates().contains(&webPageProxy));
119
120     return *navigationStates().get(&webPageProxy);
121 }
122
123 std::unique_ptr<API::NavigationClient> NavigationState::createNavigationClient()
124 {
125     return std::make_unique<NavigationClient>(*this);
126 }
127     
128 std::unique_ptr<API::HistoryClient> NavigationState::createHistoryClient()
129 {
130     return std::make_unique<HistoryClient>(*this);
131 }
132
133 RetainPtr<id <WKNavigationDelegate> > NavigationState::navigationDelegate()
134 {
135     return m_navigationDelegate.get();
136 }
137
138 void NavigationState::setNavigationDelegate(id <WKNavigationDelegate> delegate)
139 {
140     m_navigationDelegate = delegate;
141
142     m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandler = [delegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)];
143     m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandlerWebsitePolicies = [delegate respondsToSelector:@selector(_webView:decidePolicyForNavigationAction:decisionHandler:)];
144     m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionUserInfoDecisionHandlerWebsitePolicies = [delegate respondsToSelector:@selector(_webView:decidePolicyForNavigationAction:userInfo:decisionHandler:)];
145     m_navigationDelegateMethods.webViewDecidePolicyForNavigationResponseDecisionHandler = [delegate respondsToSelector:@selector(webView:decidePolicyForNavigationResponse:decisionHandler:)];
146
147     m_navigationDelegateMethods.webViewDidStartProvisionalNavigation = [delegate respondsToSelector:@selector(webView:didStartProvisionalNavigation:)];
148     m_navigationDelegateMethods.webViewDidStartProvisionalNavigationUserInfo = [delegate respondsToSelector:@selector(_webView:didStartProvisionalNavigation:userInfo:)];
149     m_navigationDelegateMethods.webViewDidReceiveServerRedirectForProvisionalNavigation = [delegate respondsToSelector:@selector(webView:didReceiveServerRedirectForProvisionalNavigation:)];
150     m_navigationDelegateMethods.webViewDidFailProvisionalNavigationWithError = [delegate respondsToSelector:@selector(webView:didFailProvisionalNavigation:withError:)];
151     m_navigationDelegateMethods.webViewDidCommitNavigation = [delegate respondsToSelector:@selector(webView:didCommitNavigation:)];
152     m_navigationDelegateMethods.webViewDidFinishNavigation = [delegate respondsToSelector:@selector(webView:didFinishNavigation:)];
153     m_navigationDelegateMethods.webViewDidFailNavigationWithError = [delegate respondsToSelector:@selector(webView:didFailNavigation:withError:)];
154     m_navigationDelegateMethods.webViewDidFailNavigationWithErrorUserInfo = [delegate respondsToSelector:@selector(_webView:didFailNavigation:withError:userInfo:)];
155
156     m_navigationDelegateMethods.webViewNavigationDidFailProvisionalLoadInSubframeWithError = [delegate respondsToSelector:@selector(_webView:navigation:didFailProvisionalLoadInSubframe:withError:)];
157     m_navigationDelegateMethods.webViewWillPerformClientRedirect = [delegate respondsToSelector:@selector(_webView:willPerformClientRedirectToURL:delay:)];
158     m_navigationDelegateMethods.webViewDidCancelClientRedirect = [delegate respondsToSelector:@selector(_webViewDidCancelClientRedirect:)];
159     m_navigationDelegateMethods.webViewNavigationDidFinishDocumentLoad = [delegate respondsToSelector:@selector(_webView:navigationDidFinishDocumentLoad:)];
160     m_navigationDelegateMethods.webViewNavigationDidSameDocumentNavigation = [delegate respondsToSelector:@selector(_webView:navigation:didSameDocumentNavigation:)];
161     m_navigationDelegateMethods.webViewRenderingProgressDidChange = [delegate respondsToSelector:@selector(_webView:renderingProgressDidChange:)];
162     m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler = [delegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)];
163     m_navigationDelegateMethods.webViewWebContentProcessDidTerminate = [delegate respondsToSelector:@selector(webViewWebContentProcessDidTerminate:)];
164     m_navigationDelegateMethods.webViewCanAuthenticateAgainstProtectionSpace = [delegate respondsToSelector:@selector(_webView:canAuthenticateAgainstProtectionSpace:)];
165     m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallenge = [delegate respondsToSelector:@selector(_webView:didReceiveAuthenticationChallenge:)];
166     m_navigationDelegateMethods.webViewWebProcessDidCrash = [delegate respondsToSelector:@selector(_webViewWebProcessDidCrash:)];
167     m_navigationDelegateMethods.webViewWebProcessDidBecomeResponsive = [delegate respondsToSelector:@selector(_webViewWebProcessDidBecomeResponsive:)];
168     m_navigationDelegateMethods.webViewWebProcessDidBecomeUnresponsive = [delegate respondsToSelector:@selector(_webViewWebProcessDidBecomeUnresponsive:)];
169     m_navigationDelegateMethods.webCryptoMasterKeyForWebView = [delegate respondsToSelector:@selector(_webCryptoMasterKeyForWebView:)];
170     m_navigationDelegateMethods.webViewDidBeginNavigationGesture = [delegate respondsToSelector:@selector(_webViewDidBeginNavigationGesture:)];
171     m_navigationDelegateMethods.webViewWillEndNavigationGestureWithNavigationToBackForwardListItem = [delegate respondsToSelector:@selector(_webViewWillEndNavigationGesture:withNavigationToBackForwardListItem:)];
172     m_navigationDelegateMethods.webViewDidEndNavigationGestureWithNavigationToBackForwardListItem = [delegate respondsToSelector:@selector(_webViewDidEndNavigationGesture:withNavigationToBackForwardListItem:)];
173     m_navigationDelegateMethods.webViewWillSnapshotBackForwardListItem = [delegate respondsToSelector:@selector(_webView:willSnapshotBackForwardListItem:)];
174     m_navigationDelegateMethods.webViewNavigationGestureSnapshotWasRemoved = [delegate respondsToSelector:@selector(_webViewDidRemoveNavigationGestureSnapshot:)];
175     m_navigationDelegateMethods.webViewURLContentRuleListIdentifiersNotifications = [delegate respondsToSelector:@selector(_webView:URL:contentRuleListIdentifiers:notifications:)];
176 #if USE(QUICK_LOOK)
177     m_navigationDelegateMethods.webViewDidStartLoadForQuickLookDocumentInMainFrame = [delegate respondsToSelector:@selector(_webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:)];
178     m_navigationDelegateMethods.webViewDidFinishLoadForQuickLookDocumentInMainFrame = [delegate respondsToSelector:@selector(_webView:didFinishLoadForQuickLookDocumentInMainFrame:)];
179     m_navigationDelegateMethods.webViewDidRequestPasswordForQuickLookDocument = [delegate respondsToSelector:@selector(_webViewDidRequestPasswordForQuickLookDocument:)];
180 #endif
181 #if PLATFORM(MAC)
182     m_navigationDelegateMethods.webViewWebGLLoadPolicyForURL = [delegate respondsToSelector:@selector(_webView:webGLLoadPolicyForURL:decisionHandler:)];
183     m_navigationDelegateMethods.webViewResolveWebGLLoadPolicyForURL = [delegate respondsToSelector:@selector(_webView:resolveWebGLLoadPolicyForURL:decisionHandler:)];
184     m_navigationDelegateMethods.webViewWillGoToBackForwardListItemInPageCache = [delegate respondsToSelector:@selector(_webView:willGoToBackForwardListItem:inPageCache:)];
185     m_navigationDelegateMethods.webViewDidFailToInitializePlugInWithInfo = [delegate respondsToSelector:@selector(_webView:didFailToInitializePlugInWithInfo:)];
186     m_navigationDelegateMethods.webViewBackForwardListItemAddedRemoved = [delegate respondsToSelector:@selector(_webView:backForwardListItemAdded:removed:)];
187 #endif
188 }
189
190 RetainPtr<id <WKHistoryDelegatePrivate> > NavigationState::historyDelegate()
191 {
192     return m_historyDelegate.get();
193 }
194
195 void NavigationState::setHistoryDelegate(id <WKHistoryDelegatePrivate> historyDelegate)
196 {
197     m_historyDelegate = historyDelegate;
198
199     m_historyDelegateMethods.webViewDidNavigateWithNavigationData = [historyDelegate respondsToSelector:@selector(_webView:didNavigateWithNavigationData:)];
200     m_historyDelegateMethods.webViewDidPerformClientRedirectFromURLToURL = [historyDelegate respondsToSelector:@selector(_webView:didPerformClientRedirectFromURL:toURL:)];
201     m_historyDelegateMethods.webViewDidPerformServerRedirectFromURLToURL = [historyDelegate respondsToSelector:@selector(_webView:didPerformServerRedirectFromURL:toURL:)];
202     m_historyDelegateMethods.webViewDidUpdateHistoryTitleForURL = [historyDelegate respondsToSelector:@selector(_webView:didUpdateHistoryTitle:forURL:)];
203 }
204
205 void NavigationState::navigationGestureDidBegin()
206 {
207     if (!m_navigationDelegateMethods.webViewDidBeginNavigationGesture)
208         return;
209
210     auto navigationDelegate = m_navigationDelegate.get();
211     if (!navigationDelegate)
212         return;
213
214     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webViewDidBeginNavigationGesture:m_webView];
215 }
216
217 void NavigationState::navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem& item)
218 {
219     if (!m_navigationDelegateMethods.webViewWillEndNavigationGestureWithNavigationToBackForwardListItem)
220         return;
221
222     auto navigationDelegate = m_navigationDelegate.get();
223     if (!navigationDelegate)
224         return;
225
226     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webViewWillEndNavigationGesture:m_webView withNavigationToBackForwardListItem:willNavigate ? wrapper(item) : nil];
227 }
228
229 void NavigationState::navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem& item)
230 {
231     if (!m_navigationDelegateMethods.webViewDidEndNavigationGestureWithNavigationToBackForwardListItem)
232         return;
233
234     auto navigationDelegate = m_navigationDelegate.get();
235     if (!navigationDelegate)
236         return;
237
238     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webViewDidEndNavigationGesture:m_webView withNavigationToBackForwardListItem:willNavigate ? wrapper(item) : nil];
239 }
240
241 void NavigationState::willRecordNavigationSnapshot(WebBackForwardListItem& item)
242 {
243     if (!m_navigationDelegateMethods.webViewWillSnapshotBackForwardListItem)
244         return;
245
246     auto navigationDelegate = m_navigationDelegate.get();
247     if (!navigationDelegate)
248         return;
249
250     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webView:m_webView willSnapshotBackForwardListItem:wrapper(item)];
251 }
252
253 void NavigationState::navigationGestureSnapshotWasRemoved()
254 {
255     if (!m_navigationDelegateMethods.webViewNavigationGestureSnapshotWasRemoved)
256         return;
257
258     auto navigationDelegate = m_navigationDelegate.get();
259     if (!navigationDelegate)
260         return;
261
262     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webViewDidRemoveNavigationGestureSnapshot:m_webView];
263 }
264
265 #if USE(QUICK_LOOK)
266 void NavigationState::didRequestPasswordForQuickLookDocument()
267 {
268     if (!m_navigationDelegateMethods.webViewDidRequestPasswordForQuickLookDocument)
269         return;
270
271     auto navigationDelegate = m_navigationDelegate.get();
272     if (!navigationDelegate)
273         return;
274
275     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webViewDidRequestPasswordForQuickLookDocument:m_webView];
276 }
277 #endif
278
279 void NavigationState::didFirstPaint()
280 {
281     if (!m_navigationDelegateMethods.webViewRenderingProgressDidChange)
282         return;
283
284     auto navigationDelegate = m_navigationDelegate.get();
285     if (!navigationDelegate)
286         return;
287
288     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webView:m_webView renderingProgressDidChange:_WKRenderingProgressEventFirstPaint];
289 }
290
291 NavigationState::NavigationClient::NavigationClient(NavigationState& navigationState)
292     : m_navigationState(navigationState)
293 {
294 }
295
296 NavigationState::NavigationClient::~NavigationClient()
297 {
298 }
299
300 #if PLATFORM(MAC)
301 bool NavigationState::NavigationClient::didFailToInitializePlugIn(WebPageProxy&, API::Dictionary& info)
302 {
303     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFailToInitializePlugInWithInfo)
304         return false;
305     
306     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
307     if (!navigationDelegate)
308         return false;
309     
310     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView didFailToInitializePlugInWithInfo:wrapper(info)];
311     return true;
312 }
313
314 inline WebCore::WebGLLoadPolicy toWebCoreWebGLLoadPolicy(_WKWebGLLoadPolicy policy)
315 {
316     switch (policy) {
317     case _WKWebGLLoadPolicyAllowCreation:
318         return WebCore::WebGLAllowCreation;
319     case _WKWebGLLoadPolicyBlockCreation:
320         return WebCore::WebGLBlockCreation;
321     case _WKWebGLLoadPolicyPendingCreation:
322         return WebCore::WebGLPendingCreation;
323     }
324     
325     ASSERT_NOT_REACHED();
326     return WebCore::WebGLAllowCreation;
327 }
328
329 void NavigationState::NavigationClient::webGLLoadPolicy(WebPageProxy&, const WebCore::URL& url, WTF::Function<void(WebCore::WebGLLoadPolicy)>&& completionHandler) const
330 {
331     if (!m_navigationState.m_navigationDelegateMethods.webViewWebGLLoadPolicyForURL) {
332         completionHandler(WebGLAllowCreation);
333         return;
334     }
335
336     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
337     Ref<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(_webView:webGLLoadPolicyForURL:decisionHandler:));
338     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView webGLLoadPolicyForURL:(NSURL *)url decisionHandler:BlockPtr<void(_WKWebGLLoadPolicy)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](_WKWebGLLoadPolicy policy) {
339         if (checker->completionHandlerHasBeenCalled())
340             return;
341         checker->didCallCompletionHandler();
342         completionHandler(toWebCoreWebGLLoadPolicy(policy));
343     }).get()];
344 }
345
346 void NavigationState::NavigationClient::resolveWebGLLoadPolicy(WebPageProxy&, const WebCore::URL& url, WTF::Function<void(WebCore::WebGLLoadPolicy)>&& completionHandler) const
347 {
348     if (!m_navigationState.m_navigationDelegateMethods.webViewResolveWebGLLoadPolicyForURL) {
349         completionHandler(WebGLAllowCreation);
350         return;
351     }
352     
353     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
354     Ref<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(_webView:resolveWebGLLoadPolicyForURL:decisionHandler:));
355     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView resolveWebGLLoadPolicyForURL:(NSURL *)url decisionHandler:BlockPtr<void(_WKWebGLLoadPolicy)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](_WKWebGLLoadPolicy policy) {
356         if (checker->completionHandlerHasBeenCalled())
357             return;
358         checker->didCallCompletionHandler();
359         completionHandler(toWebCoreWebGLLoadPolicy(policy));
360     }).get()];
361 }
362
363 bool NavigationState::NavigationClient::didChangeBackForwardList(WebPageProxy&, WebBackForwardListItem* added, const Vector<Ref<WebBackForwardListItem>>& removed)
364 {
365     if (!m_navigationState.m_navigationDelegateMethods.webViewBackForwardListItemAddedRemoved)
366         return false;
367
368     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
369     if (!navigationDelegate)
370         return false;
371
372     NSMutableArray<WKBackForwardListItem *> *removedItems = nil;
373     if (removed.size()) {
374         removedItems = [[[NSMutableArray alloc] initWithCapacity:removed.size()] autorelease];
375         for (auto& removedItem : removed)
376             [removedItems addObject:wrapper(removedItem.get())];
377     }
378     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView backForwardListItemAdded:added ? wrapper(*added) : nil removed:removedItems];
379     return true;
380 }
381
382 bool NavigationState::NavigationClient::willGoToBackForwardListItem(WebPageProxy&, WebBackForwardListItem& item, bool inPageCache, API::Object*)
383 {
384     if (!m_navigationState.m_navigationDelegateMethods.webViewWillGoToBackForwardListItemInPageCache)
385         return false;
386
387     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
388     if (!navigationDelegate)
389         return false;
390
391     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView willGoToBackForwardListItem:wrapper(item) inPageCache:inPageCache];
392     return true;
393 }
394 #endif
395
396 static void tryAppLink(Ref<API::NavigationAction>&& navigationAction, const String& currentMainFrameURL, WTF::Function<void(bool)>&& completionHandler)
397 {
398 #if HAVE(APP_LINKS)
399     if (!navigationAction->shouldOpenAppLinks()) {
400         completionHandler(false);
401         return;
402     }
403
404     auto* localCompletionHandler = new WTF::Function<void (bool)>(WTFMove(completionHandler));
405     [LSAppLink openWithURL:navigationAction->request().url() completionHandler:[localCompletionHandler](BOOL success, NSError *) {
406         dispatch_async(dispatch_get_main_queue(), [localCompletionHandler, success] {
407             (*localCompletionHandler)(success);
408             delete localCompletionHandler;
409         });
410     }];
411 #else
412     completionHandler(false);
413 #endif
414 }
415
416 void NavigationState::NavigationClient::decidePolicyForNavigationAction(WebPageProxy& webPageProxy, Ref<API::NavigationAction>&& navigationAction, Ref<WebFramePolicyListenerProxy>&& listener, API::Object* userInfo)
417 {
418     String mainFrameURLString = webPageProxy.mainFrame()->url();
419
420     if (!m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandler
421         && !m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandlerWebsitePolicies
422         && !m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionUserInfoDecisionHandlerWebsitePolicies) {
423         auto completionHandler = [webPage = makeRef(webPageProxy), listener = WTFMove(listener), navigationAction = navigationAction.copyRef()] (bool followedLinkToApp) {
424             if (followedLinkToApp) {
425                 listener->ignore();
426                 return;
427             }
428
429             if (!navigationAction->targetFrame()) {
430                 listener->use(std::nullopt);
431                 return;
432             }
433
434             RetainPtr<NSURLRequest> nsURLRequest = adoptNS(wrapper(API::URLRequest::create(navigationAction->request()).leakRef()));
435             if ([NSURLConnection canHandleRequest:nsURLRequest.get()] || webPage->urlSchemeHandlerForScheme([nsURLRequest URL].scheme)) {
436                 if (navigationAction->shouldPerformDownload())
437                     listener->download();
438                 else
439                     listener->use(std::nullopt);
440                 return;
441             }
442
443 #if PLATFORM(MAC)
444             // A file URL shouldn't fall through to here, but if it did,
445             // it would be a security risk to open it.
446             if (![[nsURLRequest URL] isFileURL])
447                 [[NSWorkspace sharedWorkspace] openURL:[nsURLRequest URL]];
448 #endif
449             listener->ignore();
450         };
451         tryAppLink(WTFMove(navigationAction), mainFrameURLString, WTFMove(completionHandler));
452         return;
453     }
454
455     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
456     if (!navigationDelegate)
457         return;
458
459     bool delegateHasWebsitePolicies = m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandlerWebsitePolicies || m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionUserInfoDecisionHandlerWebsitePolicies;
460     
461     auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), delegateHasWebsitePolicies ? @selector(_webView:decidePolicyForNavigationAction:decisionHandler:) : @selector(webView:decidePolicyForNavigationAction:decisionHandler:));
462     
463     auto decisionHandlerWithPolicies = [localListener = WTFMove(listener), navigationAction = navigationAction.copyRef(), checker = WTFMove(checker), mainFrameURLString](WKNavigationActionPolicy actionPolicy, _WKWebsitePolicies *websitePolicies) mutable {
464         if (checker->completionHandlerHasBeenCalled())
465             return;
466         checker->didCallCompletionHandler();
467
468         std::optional<WebsitePoliciesData> data;
469         if (websitePolicies)
470             data = WebsitePoliciesData::fromWebsitePolicies(*websitePolicies->_websitePolicies);
471
472         switch (actionPolicy) {
473         case WKNavigationActionPolicyAllow:
474             tryAppLink(WTFMove(navigationAction), mainFrameURLString, [localListener = WTFMove(localListener), data = WTFMove(data)](bool followedLinkToApp) mutable {
475                 if (followedLinkToApp) {
476                     localListener->ignore();
477                     return;
478                 }
479
480                 localListener->use(WTFMove(data));
481             });
482         
483             break;
484
485         case WKNavigationActionPolicyCancel:
486             localListener->ignore();
487             break;
488
489 // FIXME: Once we have a new enough compiler everywhere we don't need to ignore -Wswitch.
490 #pragma clang diagnostic push
491 #pragma clang diagnostic ignored "-Wswitch"
492         case _WKNavigationActionPolicyDownload:
493             localListener->download();
494             break;
495         case _WKNavigationActionPolicyAllowWithoutTryingAppLink:
496 #pragma clang diagnostic pop
497             localListener->use(WTFMove(data));
498             break;
499         }
500     };
501     
502     if (delegateHasWebsitePolicies) {
503         auto decisionHandler = BlockPtr<void(WKNavigationActionPolicy, _WKWebsitePolicies *)>::fromCallable(WTFMove(decisionHandlerWithPolicies));
504         if (m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionUserInfoDecisionHandlerWebsitePolicies)
505             [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView decidePolicyForNavigationAction:wrapper(navigationAction) userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil decisionHandler:decisionHandler.get()];
506         else
507             [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView decidePolicyForNavigationAction:wrapper(navigationAction) decisionHandler:decisionHandler.get()];
508     } else {
509         auto decisionHandlerWithoutPolicies = [decisionHandlerWithPolicies = WTFMove(decisionHandlerWithPolicies)] (WKNavigationActionPolicy actionPolicy) mutable {
510             decisionHandlerWithPolicies(actionPolicy, nil);
511         };
512         [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationAction:wrapper(navigationAction) decisionHandler:BlockPtr<void(WKNavigationActionPolicy)>::fromCallable(WTFMove(decisionHandlerWithoutPolicies)).get()];
513     }
514 }
515
516 void NavigationState::NavigationClient::contentRuleListNotification(WebPageProxy&, WebCore::URL&& url, Vector<String>&& listIdentifiers, Vector<String>&& notifications)
517 {
518     if (!m_navigationState.m_navigationDelegateMethods.webViewURLContentRuleListIdentifiersNotifications)
519         return;
520
521     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
522     if (!navigationDelegate)
523         return;
524
525     ASSERT(listIdentifiers.size() == notifications.size());
526
527     auto identifiers = adoptNS([[NSMutableArray alloc] initWithCapacity:listIdentifiers.size()]);
528     for (auto& identifier : listIdentifiers)
529         [identifiers addObject:identifier];
530
531     auto nsNotifications = adoptNS([[NSMutableArray alloc] initWithCapacity:notifications.size()]);
532     for (auto& notification : notifications)
533         [nsNotifications addObject:notification];
534     
535     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView URL:url contentRuleListIdentifiers:identifiers.get() notifications:nsNotifications.get()];
536 }
537     
538 void NavigationState::NavigationClient::decidePolicyForNavigationResponse(WebPageProxy&, Ref<API::NavigationResponse>&& navigationResponse, Ref<WebFramePolicyListenerProxy>&& listener, API::Object* userData)
539 {
540     if (!m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationResponseDecisionHandler) {
541         NSURL *url = navigationResponse->response().nsURLResponse().URL;
542         if ([url isFileURL]) {
543             BOOL isDirectory = NO;
544             BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory];
545
546             if (exists && !isDirectory && navigationResponse->canShowMIMEType())
547                 listener->use(std::nullopt);
548             else
549                 listener->ignore();
550             return;
551         }
552
553         if (navigationResponse->canShowMIMEType())
554             listener->use(std::nullopt);
555         else
556             listener->ignore();
557         return;
558     }
559
560     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
561     if (!navigationDelegate)
562         return;
563
564     RefPtr<WebFramePolicyListenerProxy> localListener = WTFMove(listener);
565     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:decidePolicyForNavigationResponse:decisionHandler:));
566     [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationResponse:wrapper(navigationResponse) decisionHandler:[localListener, checker](WKNavigationResponsePolicy responsePolicy) {
567         if (checker->completionHandlerHasBeenCalled())
568             return;
569         checker->didCallCompletionHandler();
570
571         switch (responsePolicy) {
572         case WKNavigationResponsePolicyAllow:
573             localListener->use(std::nullopt);
574             break;
575
576         case WKNavigationResponsePolicyCancel:
577             localListener->ignore();
578             break;
579
580 // FIXME: Once we have a new enough compiler everywhere we don't need to ignore -Wswitch.
581 #pragma clang diagnostic push
582 #pragma clang diagnostic ignored "-Wswitch"
583         case _WKNavigationResponsePolicyBecomeDownload:
584 #pragma clang diagnostic pop
585             localListener->download();
586             break;
587         }
588     }];
589 }
590
591 void NavigationState::NavigationClient::didStartProvisionalNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object* userInfo)
592 {
593     if (!m_navigationState.m_navigationDelegateMethods.webViewDidStartProvisionalNavigation
594         && !m_navigationState.m_navigationDelegateMethods.webViewDidStartProvisionalNavigationUserInfo)
595         return;
596
597     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
598     if (!navigationDelegate)
599         return;
600
601     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
602     WKNavigation *wkNavigation = nil;
603     if (navigation)
604         wkNavigation = wrapper(*navigation);
605
606     if (m_navigationState.m_navigationDelegateMethods.webViewDidStartProvisionalNavigationUserInfo)
607         [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView didStartProvisionalNavigation:wkNavigation userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil];
608     else
609         [navigationDelegate webView:m_navigationState.m_webView didStartProvisionalNavigation:wkNavigation];
610 }
611
612 void NavigationState::NavigationClient::didReceiveServerRedirectForProvisionalNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object*)
613 {
614     if (!m_navigationState.m_navigationDelegateMethods.webViewDidReceiveServerRedirectForProvisionalNavigation)
615         return;
616
617     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
618     if (!navigationDelegate)
619         return;
620
621     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
622     WKNavigation *wkNavigation = nil;
623     if (navigation)
624         wkNavigation = wrapper(*navigation);
625
626     [navigationDelegate webView:m_navigationState.m_webView didReceiveServerRedirectForProvisionalNavigation:wkNavigation];
627 }
628
629 void NavigationState::NavigationClient::willPerformClientRedirect(WebPageProxy& page, const WTF::String& urlString, double delay)
630 {
631     if (!m_navigationState.m_navigationDelegateMethods.webViewWillPerformClientRedirect)
632         return;
633
634     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
635     if (!navigationDelegate)
636         return;
637
638     WebCore::URL url(WebCore::URL(), urlString);
639
640     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webView:m_navigationState.m_webView willPerformClientRedirectToURL:url delay:delay];
641 }
642
643 void NavigationState::NavigationClient::didCancelClientRedirect(WebPageProxy& page)
644 {
645     if (!m_navigationState.m_navigationDelegateMethods.webViewDidCancelClientRedirect)
646         return;
647
648     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
649     if (!navigationDelegate)
650         return;
651
652     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webViewDidCancelClientRedirect:m_navigationState.m_webView];
653 }
654
655 static RetainPtr<NSError> createErrorWithRecoveryAttempter(WKWebView *webView, WebFrameProxy& webFrameProxy, NSError *originalError)
656 {
657     RefPtr<API::FrameHandle> frameHandle = API::FrameHandle::create(webFrameProxy.frameID());
658
659     auto recoveryAttempter = adoptNS([[WKReloadFrameErrorRecoveryAttempter alloc] initWithWebView:webView frameHandle:wrapper(*frameHandle) urlString:originalError.userInfo[NSURLErrorFailingURLStringErrorKey]]);
660
661     auto userInfo = adoptNS([[NSMutableDictionary alloc] initWithObjectsAndKeys:recoveryAttempter.get(), _WKRecoveryAttempterErrorKey, nil]);
662
663     if (NSDictionary *originalUserInfo = originalError.userInfo)
664         [userInfo addEntriesFromDictionary:originalUserInfo];
665
666     return adoptNS([[NSError alloc] initWithDomain:originalError.domain code:originalError.code userInfo:userInfo.get()]);
667 }
668
669 // FIXME: Shouldn't need to pass the WebFrameProxy in here. At most, a FrameHandle.
670 void NavigationState::NavigationClient::didFailProvisionalNavigationWithError(WebPageProxy& page, WebFrameProxy& webFrameProxy, API::Navigation* navigation, const WebCore::ResourceError& error, API::Object*)
671 {
672     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
673     RetainPtr<WKNavigation> wkNavigation;
674     if (navigation)
675         wkNavigation = wrapper(*navigation);
676     
677     // FIXME: Set the error on the navigation object.
678
679     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFailProvisionalNavigationWithError)
680         return;
681
682     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
683     if (!navigationDelegate)
684         return;
685
686     auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, webFrameProxy, error);
687     [navigationDelegate webView:m_navigationState.m_webView didFailProvisionalNavigation:wkNavigation.get() withError:errorWithRecoveryAttempter.get()];
688 }
689
690 // FIXME: Shouldn't need to pass the WebFrameProxy in here. At most, a FrameHandle.
691 void NavigationState::NavigationClient::didFailProvisionalLoadInSubframeWithError(WebPageProxy& page, WebFrameProxy& webFrameProxy, const SecurityOriginData& securityOrigin, API::Navigation* navigation, const WebCore::ResourceError& error, API::Object*)
692 {
693     // FIXME: We should assert that navigation is not null here, but it's currently null because WebPageProxy::didFailProvisionalLoadForFrame passes null.
694     RetainPtr<WKNavigation> wkNavigation;
695     if (navigation)
696         wkNavigation = wrapper(*navigation);
697
698     if (!m_navigationState.m_navigationDelegateMethods.webViewNavigationDidFailProvisionalLoadInSubframeWithError)
699         return;
700
701     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
702     auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, webFrameProxy, error);
703
704     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView navigation:nil didFailProvisionalLoadInSubframe:wrapper(API::FrameInfo::create(webFrameProxy, securityOrigin.securityOrigin())) withError:errorWithRecoveryAttempter.get()];
705 }
706
707 void NavigationState::NavigationClient::didCommitNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object*)
708 {
709     if (!m_navigationState.m_navigationDelegateMethods.webViewDidCommitNavigation)
710         return;
711
712     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
713     if (!navigationDelegate)
714         return;
715
716     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
717     WKNavigation *wkNavigation = nil;
718     if (navigation)
719         wkNavigation = wrapper(*navigation);
720
721     [navigationDelegate webView:m_navigationState.m_webView didCommitNavigation:wkNavigation];
722 }
723
724 void NavigationState::NavigationClient::didFinishDocumentLoad(WebPageProxy& page, API::Navigation* navigation, API::Object*)
725 {
726     if (!m_navigationState.m_navigationDelegateMethods.webViewNavigationDidFinishDocumentLoad)
727         return;
728
729     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
730     if (!navigationDelegate)
731         return;
732
733     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
734     WKNavigation *wkNavigation = nil;
735     if (navigation)
736         wkNavigation = wrapper(*navigation);
737
738     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView navigationDidFinishDocumentLoad:wkNavigation];
739 }
740
741 void NavigationState::NavigationClient::didFinishNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object*)
742 {
743     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFinishNavigation)
744         return;
745
746     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
747     if (!navigationDelegate)
748         return;
749
750     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
751     WKNavigation *wkNavigation = nil;
752     if (navigation)
753         wkNavigation = wrapper(*navigation);
754
755     [navigationDelegate webView:m_navigationState.m_webView didFinishNavigation:wkNavigation];
756 }
757
758 // FIXME: Shouldn't need to pass the WebFrameProxy in here. At most, a FrameHandle.
759 void NavigationState::NavigationClient::didFailNavigationWithError(WebPageProxy& page, WebFrameProxy& webFrameProxy, API::Navigation* navigation, const WebCore::ResourceError& error, API::Object* userInfo)
760 {
761     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFailNavigationWithError
762         && !m_navigationState.m_navigationDelegateMethods.webViewDidFailNavigationWithErrorUserInfo)
763         return;
764
765     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
766     if (!navigationDelegate)
767         return;
768
769     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
770     WKNavigation *wkNavigation = nil;
771     if (navigation)
772         wkNavigation = wrapper(*navigation);
773
774     auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, webFrameProxy, error);
775     if (m_navigationState.m_navigationDelegateMethods.webViewDidFailNavigationWithErrorUserInfo)
776         [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView didFailNavigation:wkNavigation withError:errorWithRecoveryAttempter.get() userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil];
777     else
778         [navigationDelegate webView:m_navigationState.m_webView didFailNavigation:wkNavigation withError:errorWithRecoveryAttempter.get()];
779 }
780
781 void NavigationState::NavigationClient::didSameDocumentNavigation(WebPageProxy&, API::Navigation* navigation, SameDocumentNavigationType navigationType, API::Object*)
782 {
783     if (!m_navigationState.m_navigationDelegateMethods.webViewNavigationDidSameDocumentNavigation)
784         return;
785
786     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
787     if (!navigationDelegate)
788         return;
789
790     // FIXME: We should assert that navigationID is not zero here, but it's currently zero for some navigations through the page cache.
791     WKNavigation *wkNavigation = nil;
792     if (navigation)
793         wkNavigation = wrapper(*navigation);
794
795     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView navigation:wkNavigation didSameDocumentNavigation:toWKSameDocumentNavigationType(navigationType)];
796 }
797
798 void NavigationState::NavigationClient::renderingProgressDidChange(WebPageProxy&, WebCore::LayoutMilestones layoutMilestones)
799 {
800     if (!m_navigationState.m_navigationDelegateMethods.webViewRenderingProgressDidChange)
801         return;
802
803     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
804     if (!navigationDelegate)
805         return;
806
807     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView renderingProgressDidChange:renderingProgressEvents(layoutMilestones)];
808 }
809
810 bool NavigationState::NavigationClient::canAuthenticateAgainstProtectionSpace(WebPageProxy&, WebProtectionSpace* protectionSpace)
811 {
812     if (m_navigationState.m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler)
813         return true;
814
815     if (!m_navigationState.m_navigationDelegateMethods.webViewCanAuthenticateAgainstProtectionSpace)
816         return false;
817
818     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
819     if (!navigationDelegate)
820         return false;
821
822 #pragma clang diagnostic push
823 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
824     return [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView canAuthenticateAgainstProtectionSpace:protectionSpace->protectionSpace().nsSpace()];
825 #pragma clang diagnostic pop
826 }
827
828 void NavigationState::NavigationClient::didReceiveAuthenticationChallenge(WebPageProxy&, AuthenticationChallengeProxy& authenticationChallenge)
829 {
830     if (m_navigationState.m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler) {
831         auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
832         if (!navigationDelegate) {
833             authenticationChallenge.listener()->performDefaultHandling();
834             return;
835         }
836
837         auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:didReceiveAuthenticationChallenge:completionHandler:));
838         [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) webView:m_navigationState.m_webView didReceiveAuthenticationChallenge:wrapper(authenticationChallenge) completionHandler:BlockPtr<void(NSURLSessionAuthChallengeDisposition, NSURLCredential *)>::fromCallable([challenge = makeRef(authenticationChallenge), checker = WTFMove(checker)](NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential) {
839             if (checker->completionHandlerHasBeenCalled())
840                 return;
841             checker->didCallCompletionHandler();
842
843             switch (disposition) {
844             case NSURLSessionAuthChallengeUseCredential: {
845                 RefPtr<WebCredential> webCredential;
846                 if (credential)
847                     webCredential = WebCredential::create(WebCore::Credential(credential));
848
849                 challenge->listener()->useCredential(webCredential.get());
850                 break;
851             }
852
853             case NSURLSessionAuthChallengePerformDefaultHandling:
854                 challenge->listener()->performDefaultHandling();
855                 break;
856
857             case NSURLSessionAuthChallengeCancelAuthenticationChallenge:
858                 challenge->listener()->cancel();
859                 break;
860
861             case NSURLSessionAuthChallengeRejectProtectionSpace:
862                 challenge->listener()->rejectProtectionSpaceAndContinue();
863                 break;
864
865             default:
866                 [NSException raise:NSInvalidArgumentException format:@"Invalid NSURLSessionAuthChallengeDisposition (%ld)", (long)disposition];
867             }
868         }).get()];
869         return;
870     }
871
872     if (!m_navigationState.m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallenge)
873         return;
874
875     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
876     if (!navigationDelegate)
877         return;
878
879 #pragma clang diagnostic push
880 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
881     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didReceiveAuthenticationChallenge:wrapper(authenticationChallenge)];
882 #pragma clang diagnostic pop
883 }
884
885 void NavigationState::NavigationClient::processDidTerminate(WebPageProxy& page, ProcessTerminationReason)
886 {
887     if (!m_navigationState.m_navigationDelegateMethods.webViewWebContentProcessDidTerminate && !m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidCrash)
888         return;
889
890     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
891     if (!navigationDelegate)
892         return;
893
894     // We prefer webViewWebContentProcessDidTerminate: over _webViewWebProcessDidCrash:.
895     if (m_navigationState.m_navigationDelegateMethods.webViewWebContentProcessDidTerminate) {
896         [navigationDelegate webViewWebContentProcessDidTerminate:m_navigationState.m_webView];
897         return;
898     }
899
900     if (m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidCrash)
901         [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webViewWebProcessDidCrash:m_navigationState.m_webView];
902 }
903
904 void NavigationState::NavigationClient::processDidBecomeResponsive(WebPageProxy& page)
905 {
906     if (!m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidBecomeResponsive)
907         return;
908
909     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
910     if (!navigationDelegate)
911         return;
912
913     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webViewWebProcessDidBecomeResponsive:m_navigationState.m_webView];
914 }
915
916 void NavigationState::NavigationClient::processDidBecomeUnresponsive(WebPageProxy& page)
917 {
918     if (!m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidBecomeUnresponsive)
919         return;
920
921     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
922     if (!navigationDelegate)
923         return;
924
925     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webViewWebProcessDidBecomeUnresponsive:m_navigationState.m_webView];
926 }
927
928 RefPtr<API::Data> NavigationState::NavigationClient::webCryptoMasterKey(WebPageProxy&)
929 {
930     if (!m_navigationState.m_navigationDelegateMethods.webCryptoMasterKeyForWebView) {
931         Vector<uint8_t> masterKey;
932         if (!getDefaultWebCryptoMasterKey(masterKey))
933             return nullptr;
934
935         return API::Data::create(masterKey.data(), masterKey.size());
936     }
937
938     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
939     if (!navigationDelegate)
940         return nullptr;
941
942     RetainPtr<NSData> data = [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webCryptoMasterKeyForWebView:m_navigationState.m_webView];
943
944     return API::Data::createWithoutCopying((const unsigned char*)[data bytes], [data length], [] (unsigned char*, const void* data) {
945         [(NSData *)data release];
946     }, data.leakRef());
947 }
948
949 #if USE(QUICK_LOOK)
950 void NavigationState::NavigationClient::didStartLoadForQuickLookDocumentInMainFrame(const String& fileName, const String& uti)
951 {
952     if (!m_navigationState.m_navigationDelegateMethods.webViewDidStartLoadForQuickLookDocumentInMainFrame)
953         return;
954
955     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
956     if (!navigationDelegate)
957         return;
958
959     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:fileName uti:uti];
960 }
961
962 void NavigationState::NavigationClient::didFinishLoadForQuickLookDocumentInMainFrame(const QuickLookDocumentData& data)
963 {
964     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFinishLoadForQuickLookDocumentInMainFrame)
965         return;
966
967     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
968     if (!navigationDelegate)
969         return;
970
971     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didFinishLoadForQuickLookDocumentInMainFrame:(NSData *)data.decodedData()];
972 }
973 #endif
974
975 // HistoryDelegatePrivate support
976     
977 NavigationState::HistoryClient::HistoryClient(NavigationState& navigationState)
978     : m_navigationState(navigationState)
979 {
980 }
981
982 NavigationState::HistoryClient::~HistoryClient()
983 {
984 }
985
986 void NavigationState::HistoryClient::didNavigateWithNavigationData(WebPageProxy&, const WebNavigationDataStore& navigationDataStore)
987 {
988     if (!m_navigationState.m_historyDelegateMethods.webViewDidNavigateWithNavigationData)
989         return;
990
991     auto historyDelegate = m_navigationState.m_historyDelegate.get();
992     if (!historyDelegate)
993         return;
994
995     [historyDelegate _webView:m_navigationState.m_webView didNavigateWithNavigationData:wrapper(API::NavigationData::create(navigationDataStore))];
996 }
997
998 void NavigationState::HistoryClient::didPerformClientRedirect(WebPageProxy&, const WTF::String& sourceURL, const WTF::String& destinationURL)
999 {
1000     if (!m_navigationState.m_historyDelegateMethods.webViewDidPerformClientRedirectFromURLToURL)
1001         return;
1002
1003     auto historyDelegate = m_navigationState.m_historyDelegate.get();
1004     if (!historyDelegate)
1005         return;
1006
1007     [historyDelegate _webView:m_navigationState.m_webView didPerformClientRedirectFromURL:[NSURL _web_URLWithWTFString:sourceURL] toURL:[NSURL _web_URLWithWTFString:destinationURL]];
1008 }
1009
1010 void NavigationState::HistoryClient::didPerformServerRedirect(WebPageProxy&, const WTF::String& sourceURL, const WTF::String& destinationURL)
1011 {
1012     if (!m_navigationState.m_historyDelegateMethods.webViewDidPerformServerRedirectFromURLToURL)
1013         return;
1014
1015     auto historyDelegate = m_navigationState.m_historyDelegate.get();
1016     if (!historyDelegate)
1017         return;
1018
1019     [historyDelegate _webView:m_navigationState.m_webView didPerformServerRedirectFromURL:[NSURL _web_URLWithWTFString:sourceURL] toURL:[NSURL _web_URLWithWTFString:destinationURL]];
1020 }
1021
1022 void NavigationState::HistoryClient::didUpdateHistoryTitle(WebPageProxy&, const WTF::String& title, const WTF::String& url)
1023 {
1024     if (!m_navigationState.m_historyDelegateMethods.webViewDidUpdateHistoryTitleForURL)
1025         return;
1026
1027     auto historyDelegate = m_navigationState.m_historyDelegate.get();
1028     if (!historyDelegate)
1029         return;
1030
1031     [historyDelegate _webView:m_navigationState.m_webView didUpdateHistoryTitle:title forURL:[NSURL _web_URLWithWTFString:url]];
1032 }
1033
1034 void NavigationState::willChangeIsLoading()
1035 {
1036     [m_webView willChangeValueForKey:@"loading"];
1037 }
1038
1039 #if PLATFORM(IOS)
1040 void NavigationState::releaseNetworkActivityToken()
1041 {
1042     RELEASE_LOG_IF(m_webView->_page->isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p UIProcess is releasing a background assertion because a page load completed", this);
1043     ASSERT(m_activityToken);
1044     m_activityToken = nullptr;
1045 }
1046 #endif
1047
1048 void NavigationState::didChangeIsLoading()
1049 {
1050 #if PLATFORM(IOS)
1051     if (m_webView->_page->pageLoadState().isLoading()) {
1052         if (m_releaseActivityTimer.isActive())
1053             m_releaseActivityTimer.stop();
1054         else {
1055             RELEASE_LOG_IF(m_webView->_page->isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - UIProcess is taking a background assertion because a page load started", this);
1056             ASSERT(!m_activityToken);
1057             m_activityToken = m_webView->_page->process().throttler().backgroundActivityToken();
1058         }
1059     } else {
1060         // Delay releasing the background activity for 3 seconds to give the application a chance to start another navigation
1061         // before suspending the WebContent process <rdar://problem/27910964>.
1062         m_releaseActivityTimer.startOneShot(3_s);
1063     }
1064 #endif
1065
1066     [m_webView didChangeValueForKey:@"loading"];
1067 }
1068
1069 void NavigationState::willChangeTitle()
1070 {
1071     [m_webView willChangeValueForKey:@"title"];
1072 }
1073
1074 void NavigationState::didChangeTitle()
1075 {
1076     [m_webView didChangeValueForKey:@"title"];
1077 }
1078
1079 void NavigationState::willChangeActiveURL()
1080 {
1081     [m_webView willChangeValueForKey:@"URL"];
1082 }
1083
1084 void NavigationState::didChangeActiveURL()
1085 {
1086     [m_webView didChangeValueForKey:@"URL"];
1087 }
1088
1089 void NavigationState::willChangeHasOnlySecureContent()
1090 {
1091     [m_webView willChangeValueForKey:@"hasOnlySecureContent"];
1092 }
1093
1094 void NavigationState::didChangeHasOnlySecureContent()
1095 {
1096     [m_webView didChangeValueForKey:@"hasOnlySecureContent"];
1097 }
1098
1099 void NavigationState::willChangeEstimatedProgress()
1100 {
1101     [m_webView willChangeValueForKey:@"estimatedProgress"];
1102 }
1103
1104 void NavigationState::didChangeEstimatedProgress()
1105 {
1106     [m_webView didChangeValueForKey:@"estimatedProgress"];
1107 }
1108
1109 void NavigationState::willChangeCanGoBack()
1110 {
1111     [m_webView willChangeValueForKey:@"canGoBack"];
1112 }
1113
1114 void NavigationState::didChangeCanGoBack()
1115 {
1116     [m_webView didChangeValueForKey:@"canGoBack"];
1117 }
1118
1119 void NavigationState::willChangeCanGoForward()
1120 {
1121     [m_webView willChangeValueForKey:@"canGoForward"];
1122 }
1123
1124 void NavigationState::didChangeCanGoForward()
1125 {
1126     [m_webView didChangeValueForKey:@"canGoForward"];
1127 }
1128
1129 void NavigationState::willChangeNetworkRequestsInProgress()
1130 {
1131     [m_webView willChangeValueForKey:@"_networkRequestsInProgress"];
1132 }
1133
1134 void NavigationState::didChangeNetworkRequestsInProgress()
1135 {
1136     [m_webView didChangeValueForKey:@"_networkRequestsInProgress"];
1137 }
1138
1139 void NavigationState::willChangeCertificateInfo()
1140 {
1141     [m_webView willChangeValueForKey:@"serverTrust"];
1142     [m_webView willChangeValueForKey:@"certificateChain"];
1143 }
1144
1145 void NavigationState::didChangeCertificateInfo()
1146 {
1147     [m_webView didChangeValueForKey:@"certificateChain"];
1148     [m_webView didChangeValueForKey:@"serverTrust"];
1149 }
1150
1151 void NavigationState::willChangeWebProcessIsResponsive()
1152 {
1153     [m_webView willChangeValueForKey:@"_webProcessIsResponsive"];
1154 }
1155
1156 void NavigationState::didChangeWebProcessIsResponsive()
1157 {
1158     [m_webView didChangeValueForKey:@"_webProcessIsResponsive"];
1159 }
1160
1161 } // namespace WebKit
1162
1163 #endif