9a17b4c0163253ab9f89a5a437d42f89e110c46c
[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 "AuthenticationChallengeDisposition.h"
38 #import "AuthenticationDecisionListener.h"
39 #import "CompletionHandlerCallChecker.h"
40 #import "Logging.h"
41 #import "NavigationActionData.h"
42 #import "PageLoadState.h"
43 #import "WKBackForwardListInternal.h"
44 #import "WKBackForwardListItemInternal.h"
45 #import "WKFrameInfoInternal.h"
46 #import "WKHistoryDelegatePrivate.h"
47 #import "WKNSDictionary.h"
48 #import "WKNSURLAuthenticationChallenge.h"
49 #import "WKNSURLExtras.h"
50 #import "WKNSURLRequest.h"
51 #import "WKNavigationActionInternal.h"
52 #import "WKNavigationDataInternal.h"
53 #import "WKNavigationDelegatePrivate.h"
54 #import "WKNavigationInternal.h"
55 #import "WKNavigationResponseInternal.h"
56 #import "WKReloadFrameErrorRecoveryAttempter.h"
57 #import "WKWebViewInternal.h"
58 #import "WebCredential.h"
59 #import "WebFrameProxy.h"
60 #import "WebNavigationState.h"
61 #import "WebPageProxy.h"
62 #import "WebProcessProxy.h"
63 #import "WebProtectionSpace.h"
64 #import "_WKErrorRecoveryAttempting.h"
65 #import "_WKFrameHandleInternal.h"
66 #import "_WKRenderingProgressEventsInternal.h"
67 #import "_WKSameDocumentNavigationTypeInternal.h"
68 #import "_WKWebsitePoliciesInternal.h"
69 #import <WebCore/Credential.h>
70 #import <WebCore/SSLKeyGenerator.h>
71 #import <WebCore/SecurityOriginData.h>
72 #import <WebCore/SerializedCryptoKeyWrap.h>
73 #import <WebCore/URL.h>
74 #import <wtf/BlockPtr.h>
75 #import <wtf/NeverDestroyed.h>
76
77 #if HAVE(APP_LINKS)
78 #import <pal/spi/cocoa/LaunchServicesSPI.h>
79 #endif
80
81 #if USE(QUICK_LOOK)
82 #import "QuickLookDocumentData.h"
83 #endif
84
85 namespace WebKit {
86 using namespace WebCore;
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_FAMILY)
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 UniqueRef<API::NavigationClient> NavigationState::createNavigationClient()
126 {
127     return makeUniqueRef<NavigationClient>(*this);
128 }
129     
130 UniqueRef<API::HistoryClient> NavigationState::createHistoryClient()
131 {
132     return makeUniqueRef<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.webViewDidPerformClientRedirect = [delegate respondsToSelector:@selector(_webView:didPerformClientRedirectFromURL:toURL:)];
161     m_navigationDelegateMethods.webViewDidCancelClientRedirect = [delegate respondsToSelector:@selector(_webViewDidCancelClientRedirect:)];
162     m_navigationDelegateMethods.webViewNavigationDidFinishDocumentLoad = [delegate respondsToSelector:@selector(_webView:navigationDidFinishDocumentLoad:)];
163     m_navigationDelegateMethods.webViewNavigationDidSameDocumentNavigation = [delegate respondsToSelector:@selector(_webView:navigation:didSameDocumentNavigation:)];
164     m_navigationDelegateMethods.webViewRenderingProgressDidChange = [delegate respondsToSelector:@selector(_webView:renderingProgressDidChange:)];
165     m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler = [delegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)];
166     m_navigationDelegateMethods.webViewWebContentProcessDidTerminate = [delegate respondsToSelector:@selector(webViewWebContentProcessDidTerminate:)];
167     m_navigationDelegateMethods.webViewWebContentProcessDidTerminateWithReason = [delegate respondsToSelector:@selector(_webView:webContentProcessDidTerminateWithReason:)];
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.webViewDecidePolicyForPluginLoadWithCurrentPolicyPluginInfoCompletionHandler = [delegate respondsToSelector:@selector(_webView:decidePolicyForPluginLoadWithCurrentPolicy:pluginInfo:completionHandler:)];
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 void NavigationState::NavigationClient::decidePolicyForPluginLoad(WebKit::WebPageProxy&, WebKit::PluginModuleLoadPolicy currentPluginLoadPolicy, API::Dictionary& pluginInformation, CompletionHandler<void(WebKit::PluginModuleLoadPolicy, const String&)>&& completionHandler)
364 {
365     if (!m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForPluginLoadWithCurrentPolicyPluginInfoCompletionHandler)
366         completionHandler(currentPluginLoadPolicy, { });
367     
368     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
369     if (!navigationDelegate)
370         completionHandler(currentPluginLoadPolicy, { });
371
372     auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(_webView:decidePolicyForPluginLoadWithCurrentPolicy:pluginInfo:completionHandler:));
373     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView decidePolicyForPluginLoadWithCurrentPolicy:wkPluginModuleLoadPolicy(currentPluginLoadPolicy) pluginInfo:wrapper(pluginInformation) completionHandler:BlockPtr<void(_WKPluginModuleLoadPolicy, NSString *)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](_WKPluginModuleLoadPolicy policy, NSString *unavailabilityDescription) mutable {
374         if (checker->completionHandlerHasBeenCalled())
375             return;
376         checker->didCallCompletionHandler();
377         completionHandler(pluginModuleLoadPolicy(policy), unavailabilityDescription);
378     }).get()];
379 }
380
381 inline WebCore::WebGLLoadPolicy toWebCoreWebGLLoadPolicy(_WKWebGLLoadPolicy policy)
382 {
383     switch (policy) {
384     case _WKWebGLLoadPolicyAllowCreation:
385         return WebCore::WebGLAllowCreation;
386     case _WKWebGLLoadPolicyBlockCreation:
387         return WebCore::WebGLBlockCreation;
388     case _WKWebGLLoadPolicyPendingCreation:
389         return WebCore::WebGLPendingCreation;
390     }
391     
392     ASSERT_NOT_REACHED();
393     return WebCore::WebGLAllowCreation;
394 }
395
396 void NavigationState::NavigationClient::webGLLoadPolicy(WebPageProxy&, const WebCore::URL& url, CompletionHandler<void(WebCore::WebGLLoadPolicy)>&& completionHandler) const
397 {
398     if (!m_navigationState.m_navigationDelegateMethods.webViewWebGLLoadPolicyForURL) {
399         completionHandler(WebGLAllowCreation);
400         return;
401     }
402
403     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
404     auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(_webView:webGLLoadPolicyForURL:decisionHandler:));
405     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView webGLLoadPolicyForURL:(NSURL *)url decisionHandler:BlockPtr<void(_WKWebGLLoadPolicy)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](_WKWebGLLoadPolicy policy) mutable {
406         if (checker->completionHandlerHasBeenCalled())
407             return;
408         checker->didCallCompletionHandler();
409         completionHandler(toWebCoreWebGLLoadPolicy(policy));
410     }).get()];
411 }
412
413 void NavigationState::NavigationClient::resolveWebGLLoadPolicy(WebPageProxy&, const WebCore::URL& url, CompletionHandler<void(WebCore::WebGLLoadPolicy)>&& completionHandler) const
414 {
415     if (!m_navigationState.m_navigationDelegateMethods.webViewResolveWebGLLoadPolicyForURL) {
416         completionHandler(WebGLAllowCreation);
417         return;
418     }
419     
420     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
421     auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(_webView:resolveWebGLLoadPolicyForURL:decisionHandler:));
422     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView resolveWebGLLoadPolicyForURL:(NSURL *)url decisionHandler:BlockPtr<void(_WKWebGLLoadPolicy)>::fromCallable([completionHandler = WTFMove(completionHandler), checker = WTFMove(checker)](_WKWebGLLoadPolicy policy) mutable {
423         if (checker->completionHandlerHasBeenCalled())
424             return;
425         checker->didCallCompletionHandler();
426         completionHandler(toWebCoreWebGLLoadPolicy(policy));
427     }).get()];
428 }
429
430 bool NavigationState::NavigationClient::didChangeBackForwardList(WebPageProxy&, WebBackForwardListItem* added, const Vector<Ref<WebBackForwardListItem>>& removed)
431 {
432     if (!m_navigationState.m_navigationDelegateMethods.webViewBackForwardListItemAddedRemoved)
433         return false;
434
435     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
436     if (!navigationDelegate)
437         return false;
438
439     NSMutableArray<WKBackForwardListItem *> *removedItems = nil;
440     if (removed.size()) {
441         removedItems = [[[NSMutableArray alloc] initWithCapacity:removed.size()] autorelease];
442         for (auto& removedItem : removed)
443             [removedItems addObject:wrapper(removedItem.get())];
444     }
445     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView backForwardListItemAdded:wrapper(added) removed:removedItems];
446     return true;
447 }
448
449 bool NavigationState::NavigationClient::willGoToBackForwardListItem(WebPageProxy&, WebBackForwardListItem& item, bool inPageCache)
450 {
451     if (!m_navigationState.m_navigationDelegateMethods.webViewWillGoToBackForwardListItemInPageCache)
452         return false;
453
454     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
455     if (!navigationDelegate)
456         return false;
457
458     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView willGoToBackForwardListItem:wrapper(item) inPageCache:inPageCache];
459     return true;
460 }
461 #endif
462
463 static void tryAppLink(Ref<API::NavigationAction>&& navigationAction, const String& currentMainFrameURL, WTF::Function<void(bool)>&& completionHandler)
464 {
465 #if HAVE(APP_LINKS)
466     if (!navigationAction->shouldOpenAppLinks()) {
467         completionHandler(false);
468         return;
469     }
470
471     auto* localCompletionHandler = new WTF::Function<void (bool)>(WTFMove(completionHandler));
472     [LSAppLink openWithURL:navigationAction->request().url() completionHandler:[localCompletionHandler](BOOL success, NSError *) {
473         dispatch_async(dispatch_get_main_queue(), [localCompletionHandler, success] {
474             (*localCompletionHandler)(success);
475             delete localCompletionHandler;
476         });
477     }];
478 #else
479     completionHandler(false);
480 #endif
481 }
482
483 void NavigationState::NavigationClient::decidePolicyForNavigationAction(WebPageProxy& webPageProxy, Ref<API::NavigationAction>&& navigationAction, Ref<WebFramePolicyListenerProxy>&& listener, API::Object* userInfo)
484 {
485     ASSERT(webPageProxy.mainFrame());
486     String mainFrameURLString = webPageProxy.mainFrame()->url();
487     bool subframeNavigation = navigationAction->targetFrame() && !navigationAction->targetFrame()->isMainFrame();
488
489     if (!m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandler
490         && !m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandlerWebsitePolicies
491         && !m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionUserInfoDecisionHandlerWebsitePolicies) {
492         auto completionHandler = [webPage = makeRef(webPageProxy), listener = WTFMove(listener), navigationAction = navigationAction.copyRef()] (bool followedLinkToApp) {
493             if (followedLinkToApp) {
494                 listener->ignore();
495                 return;
496             }
497
498             if (!navigationAction->targetFrame()) {
499                 listener->use();
500                 return;
501             }
502
503             NSURLRequest *nsURLRequest = wrapper(API::URLRequest::create(navigationAction->request()));
504             if ([NSURLConnection canHandleRequest:nsURLRequest] || webPage->urlSchemeHandlerForScheme([nsURLRequest URL].scheme)) {
505                 if (navigationAction->shouldPerformDownload())
506                     listener->download();
507                 else
508                     listener->use();
509                 return;
510             }
511
512 #if PLATFORM(MAC)
513             // A file URL shouldn't fall through to here, but if it did,
514             // it would be a security risk to open it.
515             if (![[nsURLRequest URL] isFileURL])
516                 [[NSWorkspace sharedWorkspace] openURL:[nsURLRequest URL]];
517 #endif
518             listener->ignore();
519         };
520         tryAppLink(WTFMove(navigationAction), mainFrameURLString, WTFMove(completionHandler));
521         return;
522     }
523
524     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
525     if (!navigationDelegate)
526         return;
527
528     bool delegateHasWebsitePolicies = m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandlerWebsitePolicies || m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionUserInfoDecisionHandlerWebsitePolicies;
529     
530     auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), delegateHasWebsitePolicies ? @selector(_webView:decidePolicyForNavigationAction:decisionHandler:) : @selector(webView:decidePolicyForNavigationAction:decisionHandler:));
531     
532     auto decisionHandlerWithPolicies = [localListener = WTFMove(listener), navigationAction = navigationAction.copyRef(), checker = WTFMove(checker), mainFrameURLString, webPageProxy = makeRef(webPageProxy), subframeNavigation](WKNavigationActionPolicy actionPolicy, _WKWebsitePolicies *websitePolicies) mutable {
533         if (checker->completionHandlerHasBeenCalled())
534             return;
535         checker->didCallCompletionHandler();
536
537         RefPtr<API::WebsitePolicies> apiWebsitePolicies = websitePolicies ? websitePolicies->_websitePolicies.get() : nullptr;
538         if (apiWebsitePolicies) {
539             if (auto* websiteDataStore = apiWebsitePolicies->websiteDataStore()) {
540                 auto sessionID = websiteDataStore->websiteDataStore().sessionID();
541                 if (!sessionID.isEphemeral() && sessionID != PAL::SessionID::defaultSessionID())
542                     [NSException raise:NSInvalidArgumentException format:@"_WKWebsitePolicies.websiteDataStore must be nil, default, or non-persistent."];
543                 if (subframeNavigation)
544                     [NSException raise:NSInvalidArgumentException format:@"_WKWebsitePolicies.websiteDataStore must be nil for subframe navigations."];
545             }
546         }
547
548         switch (actionPolicy) {
549         case WKNavigationActionPolicyAllow:
550         case _WKNavigationActionPolicyAllowInNewProcess:
551             tryAppLink(WTFMove(navigationAction), mainFrameURLString, [actionPolicy, localListener = WTFMove(localListener), websitePolicies = WTFMove(apiWebsitePolicies)](bool followedLinkToApp) mutable {
552                 if (followedLinkToApp) {
553                     localListener->ignore();
554                     return;
555                 }
556
557                 localListener->use(websitePolicies.get(), actionPolicy == _WKNavigationActionPolicyAllowInNewProcess ? ProcessSwapRequestedByClient::Yes : ProcessSwapRequestedByClient::No);
558             });
559         
560             break;
561
562         case WKNavigationActionPolicyCancel:
563             localListener->ignore();
564             break;
565
566         case _WKNavigationActionPolicyDownload:
567             localListener->download();
568             break;
569         case _WKNavigationActionPolicyAllowWithoutTryingAppLink:
570             localListener->use(apiWebsitePolicies.get());
571             break;
572         }
573     };
574     
575     if (delegateHasWebsitePolicies) {
576         auto decisionHandler = BlockPtr<void(WKNavigationActionPolicy, _WKWebsitePolicies *)>::fromCallable(WTFMove(decisionHandlerWithPolicies));
577         if (m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionUserInfoDecisionHandlerWebsitePolicies)
578             [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView decidePolicyForNavigationAction:wrapper(navigationAction) userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil decisionHandler:decisionHandler.get()];
579         else {
580             ALLOW_DEPRECATED_DECLARATIONS_BEGIN
581             [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView decidePolicyForNavigationAction:wrapper(navigationAction) decisionHandler:decisionHandler.get()];
582             ALLOW_DEPRECATED_DECLARATIONS_END
583         }
584     } else {
585         auto decisionHandlerWithoutPolicies = [decisionHandlerWithPolicies = WTFMove(decisionHandlerWithPolicies)] (WKNavigationActionPolicy actionPolicy) mutable {
586             decisionHandlerWithPolicies(actionPolicy, nil);
587         };
588         [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationAction:wrapper(navigationAction) decisionHandler:BlockPtr<void(WKNavigationActionPolicy)>::fromCallable(WTFMove(decisionHandlerWithoutPolicies)).get()];
589     }
590 }
591
592 void NavigationState::NavigationClient::contentRuleListNotification(WebPageProxy&, WebCore::URL&& url, Vector<String>&& listIdentifiers, Vector<String>&& notifications)
593 {
594     if (!m_navigationState.m_navigationDelegateMethods.webViewURLContentRuleListIdentifiersNotifications)
595         return;
596
597     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
598     if (!navigationDelegate)
599         return;
600
601     ASSERT(listIdentifiers.size() == notifications.size());
602
603     auto identifiers = adoptNS([[NSMutableArray alloc] initWithCapacity:listIdentifiers.size()]);
604     for (auto& identifier : listIdentifiers)
605         [identifiers addObject:identifier];
606
607     auto nsNotifications = adoptNS([[NSMutableArray alloc] initWithCapacity:notifications.size()]);
608     for (auto& notification : notifications)
609         [nsNotifications addObject:notification];
610     
611     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView URL:url contentRuleListIdentifiers:identifiers.get() notifications:nsNotifications.get()];
612 }
613     
614 void NavigationState::NavigationClient::decidePolicyForNavigationResponse(WebPageProxy& page, Ref<API::NavigationResponse>&& navigationResponse, Ref<WebFramePolicyListenerProxy>&& listener, API::Object* userData)
615 {
616     if (!m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationResponseDecisionHandler) {
617         NSURL *url = navigationResponse->response().nsURLResponse().URL;
618         if ([url isFileURL]) {
619             BOOL isDirectory = NO;
620             BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory];
621
622             if (exists && !isDirectory && navigationResponse->canShowMIMEType())
623                 listener->use();
624             else
625                 listener->ignore();
626             return;
627         }
628
629         if (navigationResponse->canShowMIMEType())
630             listener->use();
631         else
632             listener->ignore();
633         return;
634     }
635
636     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
637     if (!navigationDelegate)
638         return;
639
640     auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:decidePolicyForNavigationResponse:decisionHandler:));
641     [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationResponse:wrapper(navigationResponse) decisionHandler:BlockPtr<void(WKNavigationResponsePolicy)>::fromCallable([localListener = WTFMove(listener), checker = WTFMove(checker)](WKNavigationResponsePolicy responsePolicy) {
642         if (checker->completionHandlerHasBeenCalled())
643             return;
644         checker->didCallCompletionHandler();
645
646         switch (responsePolicy) {
647         case WKNavigationResponsePolicyAllow:
648             localListener->use();
649             break;
650
651         case WKNavigationResponsePolicyCancel:
652             localListener->ignore();
653             break;
654
655         case _WKNavigationResponsePolicyBecomeDownload:
656             localListener->download();
657             break;
658         }
659     }).get()];
660 }
661
662 void NavigationState::NavigationClient::didStartProvisionalNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object* userInfo)
663 {
664     if (!m_navigationState.m_navigationDelegateMethods.webViewDidStartProvisionalNavigation
665         && !m_navigationState.m_navigationDelegateMethods.webViewDidStartProvisionalNavigationUserInfo)
666         return;
667
668     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
669     if (!navigationDelegate)
670         return;
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
674     if (m_navigationState.m_navigationDelegateMethods.webViewDidStartProvisionalNavigationUserInfo)
675         [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView didStartProvisionalNavigation:wrapper(navigation) userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil];
676     else
677         [navigationDelegate webView:m_navigationState.m_webView didStartProvisionalNavigation:wrapper(navigation)];
678 }
679
680 void NavigationState::NavigationClient::didReceiveServerRedirectForProvisionalNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object*)
681 {
682     if (!m_navigationState.m_navigationDelegateMethods.webViewDidReceiveServerRedirectForProvisionalNavigation)
683         return;
684
685     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
686     if (!navigationDelegate)
687         return;
688
689     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
690
691     [navigationDelegate webView:m_navigationState.m_webView didReceiveServerRedirectForProvisionalNavigation:wrapper(navigation)];
692 }
693
694 void NavigationState::NavigationClient::willPerformClientRedirect(WebPageProxy& page, const WTF::String& urlString, double delay)
695 {
696     if (!m_navigationState.m_navigationDelegateMethods.webViewWillPerformClientRedirect)
697         return;
698
699     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
700     if (!navigationDelegate)
701         return;
702
703     WebCore::URL url(WebCore::URL(), urlString);
704
705     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webView:m_navigationState.m_webView willPerformClientRedirectToURL:url delay:delay];
706 }
707
708 void NavigationState::NavigationClient::didPerformClientRedirect(WebPageProxy& page, const WTF::String& sourceURLString, const WTF::String& destinationURLString)
709 {
710     if (!m_navigationState.m_navigationDelegateMethods.webViewDidPerformClientRedirect)
711         return;
712
713     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
714     if (!navigationDelegate)
715         return;
716
717     WebCore::URL sourceURL(WebCore::URL(), sourceURLString);
718     WebCore::URL destinationURL(WebCore::URL(), destinationURLString);
719
720     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webView:m_navigationState.m_webView didPerformClientRedirectFromURL:sourceURL toURL:destinationURL];
721 }
722
723 void NavigationState::NavigationClient::didCancelClientRedirect(WebPageProxy& page)
724 {
725     if (!m_navigationState.m_navigationDelegateMethods.webViewDidCancelClientRedirect)
726         return;
727
728     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
729     if (!navigationDelegate)
730         return;
731
732     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate) _webViewDidCancelClientRedirect:m_navigationState.m_webView];
733 }
734
735 static RetainPtr<NSError> createErrorWithRecoveryAttempter(WKWebView *webView, WebFrameProxy& webFrameProxy, NSError *originalError)
736 {
737     RefPtr<API::FrameHandle> frameHandle = API::FrameHandle::create(webFrameProxy.frameID());
738
739     auto recoveryAttempter = adoptNS([[WKReloadFrameErrorRecoveryAttempter alloc] initWithWebView:webView frameHandle:wrapper(*frameHandle) urlString:originalError.userInfo[NSURLErrorFailingURLStringErrorKey]]);
740
741     auto userInfo = adoptNS([[NSMutableDictionary alloc] initWithObjectsAndKeys:recoveryAttempter.get(), _WKRecoveryAttempterErrorKey, nil]);
742
743     if (NSDictionary *originalUserInfo = originalError.userInfo)
744         [userInfo addEntriesFromDictionary:originalUserInfo];
745
746     return adoptNS([[NSError alloc] initWithDomain:originalError.domain code:originalError.code userInfo:userInfo.get()]);
747 }
748
749 // FIXME: Shouldn't need to pass the WebFrameProxy in here. At most, a FrameHandle.
750 void NavigationState::NavigationClient::didFailProvisionalNavigationWithError(WebPageProxy& page, WebFrameProxy& webFrameProxy, API::Navigation* navigation, const WebCore::ResourceError& error, API::Object*)
751 {
752     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
753
754     // FIXME: Set the error on the navigation object.
755
756     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFailProvisionalNavigationWithError)
757         return;
758
759     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
760     if (!navigationDelegate)
761         return;
762
763     auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, webFrameProxy, error);
764     [navigationDelegate webView:m_navigationState.m_webView didFailProvisionalNavigation:wrapper(navigation) withError:errorWithRecoveryAttempter.get()];
765 }
766
767 // FIXME: Shouldn't need to pass the WebFrameProxy in here. At most, a FrameHandle.
768 void NavigationState::NavigationClient::didFailProvisionalLoadInSubframeWithError(WebPageProxy& page, WebFrameProxy& webFrameProxy, const SecurityOriginData& securityOrigin, API::Navigation*, const WebCore::ResourceError& error, API::Object*)
769 {
770     // FIXME: We should assert that navigation is not null here, but it's currently null because WebPageProxy::didFailProvisionalLoadForFrame passes null.
771
772     if (!m_navigationState.m_navigationDelegateMethods.webViewNavigationDidFailProvisionalLoadInSubframeWithError)
773         return;
774
775     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
776     auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, webFrameProxy, error);
777
778     [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView navigation:nil didFailProvisionalLoadInSubframe:wrapper(API::FrameInfo::create(webFrameProxy, securityOrigin.securityOrigin())) withError:errorWithRecoveryAttempter.get()];
779 }
780
781 void NavigationState::NavigationClient::didCommitNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object*)
782 {
783     if (!m_navigationState.m_navigationDelegateMethods.webViewDidCommitNavigation)
784         return;
785
786     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
787     if (!navigationDelegate)
788         return;
789
790     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
791
792     [navigationDelegate webView:m_navigationState.m_webView didCommitNavigation:wrapper(navigation)];
793 }
794
795 void NavigationState::NavigationClient::didFinishDocumentLoad(WebPageProxy& page, API::Navigation* navigation, API::Object*)
796 {
797     if (!m_navigationState.m_navigationDelegateMethods.webViewNavigationDidFinishDocumentLoad)
798         return;
799
800     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
801     if (!navigationDelegate)
802         return;
803
804     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
805
806     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView navigationDidFinishDocumentLoad:wrapper(navigation)];
807 }
808
809 void NavigationState::NavigationClient::didFinishNavigation(WebPageProxy& page, API::Navigation* navigation, API::Object*)
810 {
811     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFinishNavigation)
812         return;
813
814     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
815     if (!navigationDelegate)
816         return;
817
818     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
819
820     [navigationDelegate webView:m_navigationState.m_webView didFinishNavigation:wrapper(navigation)];
821 }
822
823 // FIXME: Shouldn't need to pass the WebFrameProxy in here. At most, a FrameHandle.
824 void NavigationState::NavigationClient::didFailNavigationWithError(WebPageProxy& page, WebFrameProxy& webFrameProxy, API::Navigation* navigation, const WebCore::ResourceError& error, API::Object* userInfo)
825 {
826     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFailNavigationWithError
827         && !m_navigationState.m_navigationDelegateMethods.webViewDidFailNavigationWithErrorUserInfo)
828         return;
829
830     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
831     if (!navigationDelegate)
832         return;
833
834     // FIXME: We should assert that navigation is not null here, but it's currently null for some navigations through the page cache.
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:wrapper(navigation) withError:errorWithRecoveryAttempter.get() userInfo:userInfo ? static_cast<id <NSSecureCoding>>(userInfo->wrapper()) : nil];
839     else
840         [navigationDelegate webView:m_navigationState.m_webView didFailNavigation:wrapper(navigation) 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
854     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView navigation:wrapper(navigation) didSameDocumentNavigation:toWKSameDocumentNavigationType(navigationType)];
855 }
856
857 void NavigationState::NavigationClient::renderingProgressDidChange(WebPageProxy&, OptionSet<WebCore::LayoutMilestone> layoutMilestones)
858 {
859     if (!m_navigationState.m_navigationDelegateMethods.webViewRenderingProgressDidChange)
860         return;
861
862     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
863     if (!navigationDelegate)
864         return;
865
866     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView renderingProgressDidChange:renderingProgressEvents(layoutMilestones)];
867 }
868
869 static AuthenticationChallengeDisposition toAuthenticationChallengeDisposition(NSURLSessionAuthChallengeDisposition disposition)
870 {
871     switch (disposition) {
872     case NSURLSessionAuthChallengeUseCredential:
873         return AuthenticationChallengeDisposition::UseCredential;
874     case NSURLSessionAuthChallengePerformDefaultHandling:
875         return AuthenticationChallengeDisposition::PerformDefaultHandling;
876     case NSURLSessionAuthChallengeCancelAuthenticationChallenge:
877         return AuthenticationChallengeDisposition::Cancel;
878     case NSURLSessionAuthChallengeRejectProtectionSpace:
879         return AuthenticationChallengeDisposition::RejectProtectionSpaceAndContinue;
880     }
881     [NSException raise:NSInvalidArgumentException format:@"Invalid NSURLSessionAuthChallengeDisposition (%ld)", (long)disposition];
882 }
883     
884 void NavigationState::NavigationClient::didReceiveAuthenticationChallenge(WebPageProxy&, AuthenticationChallengeProxy& authenticationChallenge)
885 {
886     if (!m_navigationState.m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler)
887         return authenticationChallenge.listener().completeChallenge(WebKit::AuthenticationChallengeDisposition::PerformDefaultHandling);
888
889     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
890     if (!navigationDelegate)
891         return authenticationChallenge.listener().completeChallenge(WebKit::AuthenticationChallengeDisposition::PerformDefaultHandling);
892
893     auto checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:didReceiveAuthenticationChallenge:completionHandler:));
894     [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) {
895         if (checker->completionHandlerHasBeenCalled())
896             return;
897         checker->didCallCompletionHandler();
898         challenge->listener().completeChallenge(toAuthenticationChallengeDisposition(disposition), Credential(credential));
899     }).get()];
900 }
901
902 static _WKProcessTerminationReason wkProcessTerminationReason(ProcessTerminationReason reason)
903 {
904     switch (reason) {
905     case ProcessTerminationReason::ExceededMemoryLimit:
906         return _WKProcessTerminationReasonExceededMemoryLimit;
907     case ProcessTerminationReason::ExceededCPULimit:
908         return _WKProcessTerminationReasonExceededCPULimit;
909     case ProcessTerminationReason::NavigationSwap:
910         // We probably shouldn't bother coming up with a new API type for process-swapping.
911         // "Requested by client" seems like the best match for existing types.
912         FALLTHROUGH;
913     case ProcessTerminationReason::RequestedByClient:
914         return _WKProcessTerminationReasonRequestedByClient;
915     case ProcessTerminationReason::Crash:
916         return _WKProcessTerminationReasonCrash;
917     }
918     ASSERT_NOT_REACHED();
919     return _WKProcessTerminationReasonCrash;
920 }
921
922 bool NavigationState::NavigationClient::processDidTerminate(WebPageProxy& page, ProcessTerminationReason reason)
923 {
924     if (!m_navigationState.m_navigationDelegateMethods.webViewWebContentProcessDidTerminate
925         && !m_navigationState.m_navigationDelegateMethods.webViewWebContentProcessDidTerminateWithReason
926         && !m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidCrash)
927         return false;
928
929     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
930     if (!navigationDelegate)
931         return false;
932
933     if (m_navigationState.m_navigationDelegateMethods.webViewWebContentProcessDidTerminateWithReason) {
934         [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView webContentProcessDidTerminateWithReason:wkProcessTerminationReason(reason)];
935         return true;
936     }
937
938     // We prefer webViewWebContentProcessDidTerminate: over _webViewWebProcessDidCrash:.
939     if (m_navigationState.m_navigationDelegateMethods.webViewWebContentProcessDidTerminate) {
940         [navigationDelegate webViewWebContentProcessDidTerminate:m_navigationState.m_webView];
941         return true;
942     }
943
944     ASSERT(m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidCrash);
945     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webViewWebProcessDidCrash:m_navigationState.m_webView];
946     return true;
947 }
948
949 void NavigationState::NavigationClient::processDidBecomeResponsive(WebPageProxy& page)
950 {
951     if (!m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidBecomeResponsive)
952         return;
953
954     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
955     if (!navigationDelegate)
956         return;
957
958     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webViewWebProcessDidBecomeResponsive:m_navigationState.m_webView];
959 }
960
961 void NavigationState::NavigationClient::processDidBecomeUnresponsive(WebPageProxy& page)
962 {
963     if (!m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidBecomeUnresponsive)
964         return;
965
966     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
967     if (!navigationDelegate)
968         return;
969
970     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webViewWebProcessDidBecomeUnresponsive:m_navigationState.m_webView];
971 }
972
973 RefPtr<API::Data> NavigationState::NavigationClient::webCryptoMasterKey(WebPageProxy&)
974 {
975     if (!m_navigationState.m_navigationDelegateMethods.webCryptoMasterKeyForWebView) {
976         Vector<uint8_t> masterKey;
977         if (!getDefaultWebCryptoMasterKey(masterKey))
978             return nullptr;
979
980         return API::Data::create(masterKey.data(), masterKey.size());
981     }
982
983     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
984     if (!navigationDelegate)
985         return nullptr;
986
987     NSData *data = [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webCryptoMasterKeyForWebView:m_navigationState.m_webView];
988     return API::Data::createWithoutCopying(data);
989 }
990
991 RefPtr<API::String> NavigationState::NavigationClient::signedPublicKeyAndChallengeString(WebPageProxy& page, unsigned keySizeIndex, const RefPtr<API::String>& challengeString, const WebCore::URL& url)
992 {
993     // WebKitTestRunner uses C API. Hence, no SPI is provided to override the following function.
994     return API::String::create(WebCore::signedPublicKeyAndChallengeString(keySizeIndex, challengeString->string(), url));
995 }
996
997 #if USE(QUICK_LOOK)
998 void NavigationState::NavigationClient::didStartLoadForQuickLookDocumentInMainFrame(const String& fileName, const String& uti)
999 {
1000     if (!m_navigationState.m_navigationDelegateMethods.webViewDidStartLoadForQuickLookDocumentInMainFrame)
1001         return;
1002
1003     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
1004     if (!navigationDelegate)
1005         return;
1006
1007     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:fileName uti:uti];
1008 }
1009
1010 void NavigationState::NavigationClient::didFinishLoadForQuickLookDocumentInMainFrame(const QuickLookDocumentData& data)
1011 {
1012     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFinishLoadForQuickLookDocumentInMainFrame)
1013         return;
1014
1015     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
1016     if (!navigationDelegate)
1017         return;
1018
1019     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didFinishLoadForQuickLookDocumentInMainFrame:(NSData *)data.decodedData()];
1020 }
1021 #endif
1022
1023 // HistoryDelegatePrivate support
1024     
1025 NavigationState::HistoryClient::HistoryClient(NavigationState& navigationState)
1026     : m_navigationState(navigationState)
1027 {
1028 }
1029
1030 NavigationState::HistoryClient::~HistoryClient()
1031 {
1032 }
1033
1034 void NavigationState::HistoryClient::didNavigateWithNavigationData(WebPageProxy&, const WebNavigationDataStore& navigationDataStore)
1035 {
1036     if (!m_navigationState.m_historyDelegateMethods.webViewDidNavigateWithNavigationData)
1037         return;
1038
1039     auto historyDelegate = m_navigationState.m_historyDelegate.get();
1040     if (!historyDelegate)
1041         return;
1042
1043     [historyDelegate _webView:m_navigationState.m_webView didNavigateWithNavigationData:wrapper(API::NavigationData::create(navigationDataStore))];
1044 }
1045
1046 void NavigationState::HistoryClient::didPerformClientRedirect(WebPageProxy&, const WTF::String& sourceURL, const WTF::String& destinationURL)
1047 {
1048     if (!m_navigationState.m_historyDelegateMethods.webViewDidPerformClientRedirectFromURLToURL)
1049         return;
1050
1051     auto historyDelegate = m_navigationState.m_historyDelegate.get();
1052     if (!historyDelegate)
1053         return;
1054
1055     [historyDelegate _webView:m_navigationState.m_webView didPerformClientRedirectFromURL:[NSURL _web_URLWithWTFString:sourceURL] toURL:[NSURL _web_URLWithWTFString:destinationURL]];
1056 }
1057
1058 void NavigationState::HistoryClient::didPerformServerRedirect(WebPageProxy&, const WTF::String& sourceURL, const WTF::String& destinationURL)
1059 {
1060     if (!m_navigationState.m_historyDelegateMethods.webViewDidPerformServerRedirectFromURLToURL)
1061         return;
1062
1063     auto historyDelegate = m_navigationState.m_historyDelegate.get();
1064     if (!historyDelegate)
1065         return;
1066
1067     [historyDelegate _webView:m_navigationState.m_webView didPerformServerRedirectFromURL:[NSURL _web_URLWithWTFString:sourceURL] toURL:[NSURL _web_URLWithWTFString:destinationURL]];
1068 }
1069
1070 void NavigationState::HistoryClient::didUpdateHistoryTitle(WebPageProxy&, const WTF::String& title, const WTF::String& url)
1071 {
1072     if (!m_navigationState.m_historyDelegateMethods.webViewDidUpdateHistoryTitleForURL)
1073         return;
1074
1075     auto historyDelegate = m_navigationState.m_historyDelegate.get();
1076     if (!historyDelegate)
1077         return;
1078
1079     [historyDelegate _webView:m_navigationState.m_webView didUpdateHistoryTitle:title forURL:[NSURL _web_URLWithWTFString:url]];
1080 }
1081
1082 void NavigationState::willChangeIsLoading()
1083 {
1084     [m_webView willChangeValueForKey:@"loading"];
1085 }
1086
1087 #if PLATFORM(IOS_FAMILY)
1088 void NavigationState::releaseNetworkActivityToken(NetworkActivityTokenReleaseReason reason)
1089 {
1090     if (!m_activityToken)
1091         return;
1092
1093     switch (reason) {
1094     case NetworkActivityTokenReleaseReason::LoadCompleted:
1095         RELEASE_LOG_IF(m_webView->_page->isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p NavigationState is releasing background process assertion because a page load completed", this);
1096         break;
1097     case NetworkActivityTokenReleaseReason::ScreenLocked:
1098         RELEASE_LOG_IF(m_webView->_page->isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p NavigationState is releasing background process assertion because the screen was locked", this);
1099         break;
1100     }
1101     m_activityToken = nullptr;
1102     m_releaseActivityTimer.stop();
1103 }
1104 #endif
1105
1106 void NavigationState::didChangeIsLoading()
1107 {
1108 #if PLATFORM(IOS_FAMILY)
1109     if (m_webView->_page->pageLoadState().isLoading()) {
1110         // We do not take a network activity token if a load starts after the screen has been locked.
1111         if ([UIApp isSuspendedUnderLock])
1112             return;
1113
1114         if (m_releaseActivityTimer.isActive()) {
1115             RELEASE_LOG_IF(m_webView->_page->isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - NavigationState keeps its process network assertion because a new page load started", this);
1116             m_releaseActivityTimer.stop();
1117         }
1118         if (!m_activityToken) {
1119             RELEASE_LOG_IF(m_webView->_page->isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - NavigationState is taking a process network assertion because a page load started", this);
1120             m_activityToken = m_webView->_page->process().throttler().backgroundActivityToken();
1121         }
1122     } else if (m_activityToken) {
1123         // The application is visible so we delay releasing the background activity for 3 seconds to give it a chance to start another navigation
1124         // before suspending the WebContent process <rdar://problem/27910964>.
1125         RELEASE_LOG_IF(m_webView->_page->isAlwaysOnLoggingAllowed(), ProcessSuspension, "%p - NavigationState will release its process network assertion soon because the page load completed", this);
1126         m_releaseActivityTimer.startOneShot(3_s);
1127     }
1128 #endif
1129
1130     [m_webView didChangeValueForKey:@"loading"];
1131 }
1132
1133 void NavigationState::willChangeTitle()
1134 {
1135     [m_webView willChangeValueForKey:@"title"];
1136 }
1137
1138 void NavigationState::didChangeTitle()
1139 {
1140     [m_webView didChangeValueForKey:@"title"];
1141 }
1142
1143 void NavigationState::willChangeActiveURL()
1144 {
1145     [m_webView willChangeValueForKey:@"URL"];
1146 }
1147
1148 void NavigationState::didChangeActiveURL()
1149 {
1150     [m_webView didChangeValueForKey:@"URL"];
1151 }
1152
1153 void NavigationState::willChangeHasOnlySecureContent()
1154 {
1155     [m_webView willChangeValueForKey:@"hasOnlySecureContent"];
1156 }
1157
1158 void NavigationState::didChangeHasOnlySecureContent()
1159 {
1160     [m_webView didChangeValueForKey:@"hasOnlySecureContent"];
1161 }
1162
1163 void NavigationState::willChangeEstimatedProgress()
1164 {
1165     [m_webView willChangeValueForKey:@"estimatedProgress"];
1166 }
1167
1168 void NavigationState::didChangeEstimatedProgress()
1169 {
1170     [m_webView didChangeValueForKey:@"estimatedProgress"];
1171 }
1172
1173 void NavigationState::willChangeCanGoBack()
1174 {
1175     [m_webView willChangeValueForKey:@"canGoBack"];
1176 }
1177
1178 void NavigationState::didChangeCanGoBack()
1179 {
1180     [m_webView didChangeValueForKey:@"canGoBack"];
1181 }
1182
1183 void NavigationState::willChangeCanGoForward()
1184 {
1185     [m_webView willChangeValueForKey:@"canGoForward"];
1186 }
1187
1188 void NavigationState::didChangeCanGoForward()
1189 {
1190     [m_webView didChangeValueForKey:@"canGoForward"];
1191 }
1192
1193 void NavigationState::willChangeNetworkRequestsInProgress()
1194 {
1195     [m_webView willChangeValueForKey:@"_networkRequestsInProgress"];
1196 }
1197
1198 void NavigationState::didChangeNetworkRequestsInProgress()
1199 {
1200     [m_webView didChangeValueForKey:@"_networkRequestsInProgress"];
1201 }
1202
1203 void NavigationState::willChangeCertificateInfo()
1204 {
1205     [m_webView willChangeValueForKey:@"serverTrust"];
1206     [m_webView willChangeValueForKey:@"certificateChain"];
1207 }
1208
1209 void NavigationState::didChangeCertificateInfo()
1210 {
1211     [m_webView didChangeValueForKey:@"certificateChain"];
1212     [m_webView didChangeValueForKey:@"serverTrust"];
1213 }
1214
1215 void NavigationState::willChangeWebProcessIsResponsive()
1216 {
1217     [m_webView willChangeValueForKey:@"_webProcessIsResponsive"];
1218 }
1219
1220 void NavigationState::didChangeWebProcessIsResponsive()
1221 {
1222     [m_webView didChangeValueForKey:@"_webProcessIsResponsive"];
1223 }
1224
1225 } // namespace WebKit
1226
1227 #endif