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