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