Add WTF::move()
[WebKit-https.git] / Source / WebKit2 / UIProcess / Cocoa / NavigationState.mm
1 /*
2  * Copyright (C) 2014 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 "APINavigationData.h"
32 #import "APIString.h"
33 #import "APIURL.h"
34 #import "AuthenticationDecisionListener.h"
35 #import "CompletionHandlerCallChecker.h"
36 #import "NavigationActionData.h"
37 #import "PageLoadState.h"
38 #import "WKBackForwardListInternal.h"
39 #import "WKBackForwardListItemInternal.h"
40 #import "WKFrameInfoInternal.h"
41 #import "WKHistoryDelegatePrivate.h"
42 #import "WKNSURLAuthenticationChallenge.h"
43 #import "WKNSURLExtras.h"
44 #import "WKNSURLProtectionSpace.h"
45 #import "WKNSURLRequest.h"
46 #import "WKNavigationActionInternal.h"
47 #import "WKNavigationDataInternal.h"
48 #import "WKNavigationDelegatePrivate.h"
49 #import "WKNavigationInternal.h"
50 #import "WKNavigationResponseInternal.h"
51 #import "WKReloadFrameErrorRecoveryAttempter.h"
52 #import "WKWebViewInternal.h"
53 #import "WebCredential.h"
54 #import "WebFrameProxy.h"
55 #import "WebPageProxy.h"
56 #import "WebProcessProxy.h"
57 #import "_WKErrorRecoveryAttempting.h"
58 #import "_WKFrameHandleInternal.h"
59 #import <WebCore/AuthenticationMac.h>
60 #import <wtf/NeverDestroyed.h>
61
62 #if USE(QUICK_LOOK)
63 #import "QuickLookDocumentData.h"
64 #endif
65
66 namespace WebKit {
67
68 static HashMap<WebPageProxy*, NavigationState*>& navigationStates()
69 {
70     static NeverDestroyed<HashMap<WebPageProxy*, NavigationState*>> navigationStates;
71
72     return navigationStates;
73 }
74
75 NavigationState::NavigationState(WKWebView *webView)
76     : m_webView(webView)
77     , m_navigationDelegateMethods()
78     , m_historyDelegateMethods()
79 {
80     ASSERT(m_webView->_page);
81     ASSERT(!navigationStates().contains(m_webView->_page.get()));
82
83     navigationStates().add(m_webView->_page.get(), this);
84     m_webView->_page->pageLoadState().addObserver(*this);
85 }
86
87 NavigationState::~NavigationState()
88 {
89     ASSERT(navigationStates().get(m_webView->_page.get()) == this);
90
91     navigationStates().remove(m_webView->_page.get());
92     m_webView->_page->pageLoadState().removeObserver(*this);
93 }
94
95 NavigationState& NavigationState::fromWebPage(WebPageProxy& webPageProxy)
96 {
97     ASSERT(navigationStates().contains(&webPageProxy));
98
99     return *navigationStates().get(&webPageProxy);
100 }
101
102 std::unique_ptr<API::LoaderClient> NavigationState::createLoaderClient()
103 {
104     return std::make_unique<LoaderClient>(*this);
105 }
106
107 std::unique_ptr<API::PolicyClient> NavigationState::createPolicyClient()
108 {
109     return std::make_unique<PolicyClient>(*this);
110 }
111
112 RetainPtr<id <WKNavigationDelegate> > NavigationState::navigationDelegate()
113 {
114     return m_navigationDelegate.get();
115 }
116
117 void NavigationState::setNavigationDelegate(id <WKNavigationDelegate> delegate)
118 {
119     m_navigationDelegate = delegate;
120
121     m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandler = [delegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)];
122     m_navigationDelegateMethods.webViewDecidePolicyForNavigationResponseDecisionHandler = [delegate respondsToSelector:@selector(webView:decidePolicyForNavigationResponse:decisionHandler:)];
123
124     m_navigationDelegateMethods.webViewDidStartProvisionalNavigation = [delegate respondsToSelector:@selector(webView:didStartProvisionalNavigation:)];
125     m_navigationDelegateMethods.webViewDidReceiveServerRedirectForProvisionalNavigation = [delegate respondsToSelector:@selector(webView:didReceiveServerRedirectForProvisionalNavigation:)];
126     m_navigationDelegateMethods.webViewDidFailProvisionalNavigationWithError = [delegate respondsToSelector:@selector(webView:didFailProvisionalNavigation:withError:)];
127     m_navigationDelegateMethods.webViewDidCommitNavigation = [delegate respondsToSelector:@selector(webView:didCommitNavigation:)];
128     m_navigationDelegateMethods.webViewDidFinishNavigation = [delegate respondsToSelector:@selector(webView:didFinishNavigation:)];
129     m_navigationDelegateMethods.webViewDidFailNavigationWithError = [delegate respondsToSelector:@selector(webView:didFailNavigation:withError:)];
130
131     m_navigationDelegateMethods.webViewNavigationDidFailProvisionalLoadInSubframeWithError = [delegate respondsToSelector:@selector(_webView:navigation:didFailProvisionalLoadInSubframe:withError:)];
132     m_navigationDelegateMethods.webViewNavigationDidFinishDocumentLoad = [delegate respondsToSelector:@selector(_webView:navigationDidFinishDocumentLoad:)];
133     m_navigationDelegateMethods.webViewRenderingProgressDidChange = [delegate respondsToSelector:@selector(_webView:renderingProgressDidChange:)];
134     m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler = [delegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)];
135     m_navigationDelegateMethods.webViewCanAuthenticateAgainstProtectionSpace = [delegate respondsToSelector:@selector(_webView:canAuthenticateAgainstProtectionSpace:)];
136     m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallenge = [delegate respondsToSelector:@selector(_webView:didReceiveAuthenticationChallenge:)];
137     m_navigationDelegateMethods.webViewWebProcessDidCrash = [delegate respondsToSelector:@selector(_webViewWebProcessDidCrash:)];
138     m_navigationDelegateMethods.webCryptoMasterKeyForWebView = [delegate respondsToSelector:@selector(_webCryptoMasterKeyForWebView:)];
139 #if USE(QUICK_LOOK)
140     m_navigationDelegateMethods.webViewDidStartLoadForQuickLookDocumentInMainFrame = [delegate respondsToSelector:@selector(_webView:didStartLoadForQuickLookDocumentInMainFrameWithFileName:uti:)];
141     m_navigationDelegateMethods.webViewDidFinishLoadForQuickLookDocumentInMainFrame = [delegate respondsToSelector:@selector(_webView:didFinishLoadForQuickLookDocumentInMainFrame:)];
142 #endif
143 }
144
145 RetainPtr<id <WKHistoryDelegatePrivate> > NavigationState::historyDelegate()
146 {
147     return m_historyDelegate.get();
148 }
149
150 void NavigationState::setHistoryDelegate(id <WKHistoryDelegatePrivate> historyDelegate)
151 {
152     m_historyDelegate = historyDelegate;
153
154     m_historyDelegateMethods.webViewDidNavigateWithNavigationData = [historyDelegate respondsToSelector:@selector(_webView:didNavigateWithNavigationData:)];
155     m_historyDelegateMethods.webViewDidPerformClientRedirectFromURLToURL = [historyDelegate respondsToSelector:@selector(_webView:didPerformClientRedirectFromURL:toURL:)];
156     m_historyDelegateMethods.webViewDidPerformServerRedirectFromURLToURL = [historyDelegate respondsToSelector:@selector(_webView:didPerformServerRedirectFromURL:toURL:)];
157     m_historyDelegateMethods.webViewDidUpdateHistoryTitleForURL = [historyDelegate respondsToSelector:@selector(_webView:didUpdateHistoryTitle:forURL:)];
158 }
159
160 RetainPtr<WKNavigation> NavigationState::createLoadRequestNavigation(uint64_t navigationID, NSURLRequest *request)
161 {
162     ASSERT(!m_navigations.contains(navigationID));
163
164     RetainPtr<WKNavigation> navigation = adoptNS([[WKNavigation alloc] init]);
165     [navigation setRequest:request];
166
167     m_navigations.set(navigationID, navigation);
168
169     return navigation;
170 }
171
172 RetainPtr<WKNavigation> NavigationState::createBackForwardNavigation(uint64_t navigationID, const WebBackForwardListItem& item)
173 {
174     ASSERT(!m_navigations.contains(navigationID));
175
176     auto navigation = adoptNS([[WKNavigation alloc] init]);
177
178     m_navigations.set(navigationID, navigation);
179
180     return navigation;
181 }
182
183 RetainPtr<WKNavigation> NavigationState::createReloadNavigation(uint64_t navigationID)
184 {
185     ASSERT(!m_navigations.contains(navigationID));
186
187     auto navigation = adoptNS([[WKNavigation alloc] init]);
188
189     m_navigations.set(navigationID, navigation);
190
191     return navigation;
192 }
193
194 RetainPtr<WKNavigation> NavigationState::createLoadDataNavigation(uint64_t navigationID)
195 {
196     ASSERT(!m_navigations.contains(navigationID));
197
198     auto navigation = adoptNS([[WKNavigation alloc] init]);
199
200     m_navigations.set(navigationID, navigation);
201
202     return navigation;
203 }
204
205 void NavigationState::didNavigateWithNavigationData(const WebKit::WebNavigationDataStore& navigationDataStore)
206 {
207     if (!m_historyDelegateMethods.webViewDidNavigateWithNavigationData)
208         return;
209
210     auto historyDelegate = m_historyDelegate.get();
211     if (!historyDelegate)
212         return;
213
214     [historyDelegate _webView:m_webView didNavigateWithNavigationData:wrapper(*API::NavigationData::create(navigationDataStore))];
215 }
216
217 void NavigationState::didPerformClientRedirect(const WTF::String& sourceURL, const WTF::String& destinationURL)
218 {
219     if (!m_historyDelegateMethods.webViewDidPerformClientRedirectFromURLToURL)
220         return;
221
222     auto historyDelegate = m_historyDelegate.get();
223     if (!historyDelegate)
224         return;
225
226     [historyDelegate _webView:m_webView didPerformClientRedirectFromURL:[NSURL _web_URLWithWTFString:sourceURL] toURL:[NSURL _web_URLWithWTFString:destinationURL]];
227 }
228
229 void NavigationState::didPerformServerRedirect(const WTF::String& sourceURL, const WTF::String& destinationURL)
230 {
231     if (!m_historyDelegateMethods.webViewDidPerformServerRedirectFromURLToURL)
232         return;
233
234     auto historyDelegate = m_historyDelegate.get();
235     if (!historyDelegate)
236         return;
237
238     [historyDelegate _webView:m_webView didPerformServerRedirectFromURL:[NSURL _web_URLWithWTFString:sourceURL] toURL:[NSURL _web_URLWithWTFString:destinationURL]];
239 }
240
241 void NavigationState::didUpdateHistoryTitle(const WTF::String& title, const WTF::String& url)
242 {
243     if (!m_historyDelegateMethods.webViewDidUpdateHistoryTitleForURL)
244         return;
245
246     auto historyDelegate = m_historyDelegate.get();
247     if (!historyDelegate)
248         return;
249
250     [historyDelegate _webView:m_webView didUpdateHistoryTitle:title forURL:[NSURL _web_URLWithWTFString:url]];
251 }
252
253 NavigationState::PolicyClient::PolicyClient(NavigationState& navigationState)
254     : m_navigationState(navigationState)
255 {
256 }
257
258 NavigationState::PolicyClient::~PolicyClient()
259 {
260 }
261
262 void NavigationState::PolicyClient::decidePolicyForNavigationAction(WebPageProxy*, WebFrameProxy* destinationFrame, const NavigationActionData& navigationActionData, WebFrameProxy* sourceFrame, const WebCore::ResourceRequest& originalRequest, const WebCore::ResourceRequest& request, RefPtr<WebFramePolicyListenerProxy> listener, API::Object* userData)
263 {
264     RetainPtr<NSURLRequest> nsURLRequest = adoptNS(wrapper(*API::URLRequest::create(request).leakRef()));
265
266     if (listener->navigationID())
267         m_navigationState.createLoadRequestNavigation(listener->navigationID(), nsURLRequest.get());
268
269     if (!m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationActionDecisionHandler) {
270         if (!destinationFrame) {
271             listener->use();
272             return;
273         }
274
275         if ([NSURLConnection canHandleRequest:nsURLRequest.get()]) {
276             listener->use();
277             return;
278         }
279
280 #if PLATFORM(MAC)
281         // A file URL shouldn't fall through to here, but if it did,
282         // it would be a security risk to open it.
283         if (![[nsURLRequest URL] isFileURL])
284             [[NSWorkspace sharedWorkspace] openURL:[nsURLRequest URL]];
285 #endif
286         listener->ignore();
287         return;
288     }
289
290     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
291     if (!navigationDelegate)
292         return;
293
294     auto navigationAction = adoptNS([[WKNavigationAction alloc] _initWithNavigationActionData:navigationActionData]);
295
296     if (destinationFrame)
297         [navigationAction setTargetFrame:adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*destinationFrame]).get()];
298
299     if (sourceFrame) {
300         if (sourceFrame == destinationFrame)
301             [navigationAction setSourceFrame:[navigationAction targetFrame]];
302         else
303             [navigationAction setSourceFrame:adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*sourceFrame]).get()];
304     }
305
306     [navigationAction setRequest:nsURLRequest.get()];
307     [navigationAction _setOriginalURL:originalRequest.url()];
308
309     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:decidePolicyForNavigationAction:decisionHandler:));
310     [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationAction:navigationAction.get() decisionHandler:[listener, checker](WKNavigationActionPolicy actionPolicy) {
311         checker->didCallCompletionHandler();
312
313         switch (actionPolicy) {
314         case WKNavigationActionPolicyAllow:
315             listener->use();
316             break;
317
318         case WKNavigationActionPolicyCancel:
319             listener->ignore();
320             break;
321
322 // FIXME: Once we have a new enough compiler everywhere we don't need to ignore -Wswitch.
323 #pragma clang diagnostic push
324 #pragma clang diagnostic ignored "-Wswitch"
325         case _WKNavigationActionPolicyDownload:
326 #pragma clang diagnostic pop
327             listener->download();
328             break;
329         }
330     }];
331 }
332
333 void NavigationState::PolicyClient::decidePolicyForNewWindowAction(WebPageProxy* webPageProxy, WebFrameProxy* sourceFrame, const NavigationActionData& navigationActionData, const WebCore::ResourceRequest& request, const WTF::String& frameName, RefPtr<WebFramePolicyListenerProxy> listener, API::Object* userData)
334 {
335     decidePolicyForNavigationAction(webPageProxy, nullptr, navigationActionData, sourceFrame, request, request, WTF::move(listener), userData);
336 }
337
338 void NavigationState::PolicyClient::decidePolicyForResponse(WebPageProxy*, WebFrameProxy* frame, const WebCore::ResourceResponse& resourceResponse, const WebCore::ResourceRequest& resourceRequest, bool canShowMIMEType, RefPtr<WebFramePolicyListenerProxy> listener, API::Object* userData)
339 {
340     if (!m_navigationState.m_navigationDelegateMethods.webViewDecidePolicyForNavigationResponseDecisionHandler) {
341         NSURL *url = resourceResponse.nsURLResponse().URL;
342         if ([url isFileURL]) {
343             BOOL isDirectory = NO;
344             BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory];
345
346             if (exists && !isDirectory && canShowMIMEType)
347                 listener->use();
348             else
349                 listener->ignore();
350             return;
351         }
352
353         if (canShowMIMEType)
354             listener->use();
355         else
356             listener->ignore();
357         return;
358     }
359
360     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
361     if (!navigationDelegate)
362         return;
363
364     auto navigationResponse = adoptNS([[WKNavigationResponse alloc] init]);
365
366     navigationResponse->_frame = adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*frame]);
367     navigationResponse->_request = resourceRequest.nsURLRequest(WebCore::DoNotUpdateHTTPBody);
368     [navigationResponse setResponse:resourceResponse.nsURLResponse()];
369     [navigationResponse setCanShowMIMEType:canShowMIMEType];
370
371     RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:decidePolicyForNavigationResponse:decisionHandler:));
372     [navigationDelegate webView:m_navigationState.m_webView decidePolicyForNavigationResponse:navigationResponse.get() decisionHandler:[listener, checker](WKNavigationResponsePolicy responsePolicy) {
373         checker->didCallCompletionHandler();
374
375         switch (responsePolicy) {
376         case WKNavigationResponsePolicyAllow:
377             listener->use();
378             break;
379
380         case WKNavigationResponsePolicyCancel:
381             listener->ignore();
382             break;
383
384 // FIXME: Once we have a new enough compiler everywhere we don't need to ignore -Wswitch.
385 #pragma clang diagnostic push
386 #pragma clang diagnostic ignored "-Wswitch"
387         case _WKNavigationResponsePolicyBecomeDownload:
388 #pragma clang diagnostic pop
389             listener->download();
390             break;
391         }
392     }];
393 }
394
395 NavigationState::LoaderClient::LoaderClient(NavigationState& navigationState)
396     : m_navigationState(navigationState)
397 {
398 }
399
400 NavigationState::LoaderClient::~LoaderClient()
401 {
402 }
403
404 void NavigationState::LoaderClient::didStartProvisionalLoadForFrame(WebPageProxy*, WebFrameProxy* webFrameProxy, uint64_t navigationID, API::Object*)
405 {
406     if (!webFrameProxy->isMainFrame())
407         return;
408
409     if (!m_navigationState.m_navigationDelegateMethods.webViewDidStartProvisionalNavigation)
410         return;
411
412     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
413     if (!navigationDelegate)
414         return;
415
416     ASSERT(navigationID);
417     WKNavigation *navigation = m_navigationState.m_navigations.get(navigationID).get();
418     ASSERT(navigation);
419
420     [navigationDelegate webView:m_navigationState.m_webView didStartProvisionalNavigation:navigation];
421 }
422
423 void NavigationState::LoaderClient::didReceiveServerRedirectForProvisionalLoadForFrame(WebKit::WebPageProxy*, WebKit::WebFrameProxy* webFrameProxy, uint64_t navigationID, API::Object*)
424 {
425     if (!webFrameProxy->isMainFrame())
426         return;
427
428     if (!m_navigationState.m_navigationDelegateMethods.webViewDidReceiveServerRedirectForProvisionalNavigation)
429         return;
430
431     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
432     if (!navigationDelegate)
433         return;
434
435     ASSERT(navigationID);
436     WKNavigation *navigation = m_navigationState.m_navigations.get(navigationID).get();
437     ASSERT(navigation);
438
439     [navigationDelegate webView:m_navigationState.m_webView didReceiveServerRedirectForProvisionalNavigation:navigation];
440 }
441
442 static RetainPtr<NSError> createErrorWithRecoveryAttempter(WKWebView *webView, WebFrameProxy& webFrameProxy, NSError *originalError)
443 {
444     RefPtr<API::FrameHandle> frameHandle = API::FrameHandle::create(webFrameProxy.frameID());
445
446     auto recoveryAttempter = adoptNS([[WKReloadFrameErrorRecoveryAttempter alloc] initWithWebView:webView frameHandle:wrapper(*frameHandle) urlString:originalError.userInfo[NSURLErrorFailingURLStringErrorKey]]);
447
448     auto userInfo = adoptNS([[NSMutableDictionary alloc] initWithObjectsAndKeys:recoveryAttempter.get(), _WKRecoveryAttempterErrorKey, nil]);
449
450     if (NSDictionary *originalUserInfo = originalError.userInfo)
451         [userInfo addEntriesFromDictionary:originalUserInfo];
452
453     return adoptNS([[NSError alloc] initWithDomain:originalError.domain code:originalError.code userInfo:userInfo.get()]);
454 }
455
456 void NavigationState::LoaderClient::didFailProvisionalLoadWithErrorForFrame(WebPageProxy*, WebFrameProxy* webFrameProxy, uint64_t navigationID, const WebCore::ResourceError& error, API::Object*)
457 {
458     if (!webFrameProxy->isMainFrame()) {
459         if (!m_navigationState.m_navigationDelegateMethods.webViewNavigationDidFailProvisionalLoadInSubframeWithError)
460             return;
461
462         auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
463         auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, *webFrameProxy, error);
464         // FIXME: Get the main frame's current navigation.
465         [(id <WKNavigationDelegatePrivate>)navigationDelegate _webView:m_navigationState.m_webView navigation:nil didFailProvisionalLoadInSubframe:adoptNS([[WKFrameInfo alloc] initWithWebFrameProxy:*webFrameProxy]).get() withError:errorWithRecoveryAttempter.get()];
466
467         return;
468     }
469
470     ASSERT(navigationID);
471     RetainPtr<WKNavigation> navigation = m_navigationState.m_navigations.take(navigationID).get();
472     ASSERT(navigation);
473
474     // FIXME: Set the error on the navigation object.
475
476     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFailProvisionalNavigationWithError)
477         return;
478
479     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
480     if (!navigationDelegate)
481         return;
482
483     auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, *webFrameProxy, error);
484     [navigationDelegate webView:m_navigationState.m_webView didFailProvisionalNavigation:navigation.get() withError:errorWithRecoveryAttempter.get()];
485 }
486
487 void NavigationState::LoaderClient::didCommitLoadForFrame(WebPageProxy*, WebFrameProxy* webFrameProxy, uint64_t navigationID, API::Object*)
488 {
489     if (!webFrameProxy->isMainFrame())
490         return;
491
492     if (!m_navigationState.m_navigationDelegateMethods.webViewDidCommitNavigation)
493         return;
494
495     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
496     if (!navigationDelegate)
497         return;
498
499     ASSERT(navigationID);
500     WKNavigation *navigation = m_navigationState.m_navigations.get(navigationID).get();
501     ASSERT(navigation);
502
503     [navigationDelegate webView:m_navigationState.m_webView didCommitNavigation:navigation];
504 }
505
506 void NavigationState::LoaderClient::didFinishDocumentLoadForFrame(WebPageProxy*, WebFrameProxy* webFrameProxy, uint64_t navigationID, API::Object*)
507 {
508     if (!webFrameProxy->isMainFrame())
509         return;
510
511     if (!m_navigationState.m_navigationDelegateMethods.webViewNavigationDidFinishDocumentLoad)
512         return;
513
514     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
515     if (!navigationDelegate)
516         return;
517
518     ASSERT(navigationID);
519     WKNavigation *navigation = m_navigationState.m_navigations.get(navigationID).get();
520     ASSERT(navigation);
521
522     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView navigationDidFinishDocumentLoad:navigation];
523 }
524
525 void NavigationState::LoaderClient::didFinishLoadForFrame(WebPageProxy*, WebFrameProxy* webFrameProxy, uint64_t navigationID, API::Object*)
526 {
527     if (!webFrameProxy->isMainFrame())
528         return;
529
530     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFinishNavigation)
531         return;
532
533     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
534     if (!navigationDelegate)
535         return;
536
537     ASSERT(navigationID);
538     WKNavigation *navigation = m_navigationState.m_navigations.get(navigationID).get();
539     ASSERT(navigation);
540
541     [navigationDelegate webView:m_navigationState.m_webView didFinishNavigation:navigation];
542 }
543
544 void NavigationState::LoaderClient::didFailLoadWithErrorForFrame(WebPageProxy*, WebFrameProxy* webFrameProxy, uint64_t navigationID, const WebCore::ResourceError& error, API::Object* userData)
545 {
546     if (!webFrameProxy->isMainFrame())
547         return;
548
549     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFailNavigationWithError)
550         return;
551
552     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
553     if (!navigationDelegate)
554         return;
555
556     ASSERT(navigationID);
557     WKNavigation *navigation = m_navigationState.m_navigations.get(navigationID).get();
558     ASSERT(navigation);
559
560     auto errorWithRecoveryAttempter = createErrorWithRecoveryAttempter(m_navigationState.m_webView, *webFrameProxy, error);
561     [navigationDelegate webView:m_navigationState.m_webView didFailNavigation:navigation withError:errorWithRecoveryAttempter.get()];
562 }
563
564 void NavigationState::LoaderClient::didDestroyNavigation(WebPageProxy*, uint64_t navigationID)
565 {
566     m_navigationState.m_navigations.remove(navigationID);
567 }
568
569 static _WKRenderingProgressEvents renderingProgressEvents(WebCore::LayoutMilestones milestones)
570 {
571     _WKRenderingProgressEvents events = 0;
572
573     if (milestones & WebCore::DidFirstLayout)
574         events |= _WKRenderingProgressEventFirstLayout;
575
576     if (milestones & WebCore::DidHitRelevantRepaintedObjectsAreaThreshold)
577         events |= _WKRenderingProgressEventFirstPaintWithSignificantArea;
578
579     return events;
580 }
581
582 void NavigationState::LoaderClient::didLayout(WebKit::WebPageProxy*, WebCore::LayoutMilestones layoutMilestones, API::Object*)
583 {
584     if (!m_navigationState.m_navigationDelegateMethods.webViewRenderingProgressDidChange)
585         return;
586
587     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
588     if (!navigationDelegate)
589         return;
590
591     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView renderingProgressDidChange:renderingProgressEvents(layoutMilestones)];
592 }
593
594 bool NavigationState::LoaderClient::canAuthenticateAgainstProtectionSpaceInFrame(WebKit::WebPageProxy*, WebKit::WebFrameProxy*, WebKit::WebProtectionSpace* protectionSpace)
595 {
596     if (m_navigationState.m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler)
597         return protectionSpace->authenticationScheme() != WebCore::ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested;
598
599     if (!m_navigationState.m_navigationDelegateMethods.webViewCanAuthenticateAgainstProtectionSpace)
600         return false;
601
602     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
603     if (!navigationDelegate)
604         return false;
605
606     return [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView canAuthenticateAgainstProtectionSpace:wrapper(*protectionSpace)];
607 }
608
609 void NavigationState::LoaderClient::didReceiveAuthenticationChallengeInFrame(WebPageProxy*, WebFrameProxy*, AuthenticationChallengeProxy* authenticationChallenge)
610 {
611 #if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
612     if (m_navigationState.m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallengeCompletionHandler) {
613         ASSERT(authenticationChallenge->protectionSpace()->authenticationScheme() != WebCore::ProtectionSpaceAuthenticationSchemeServerTrustEvaluationRequested);
614         auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
615         if (!navigationDelegate) {
616             authenticationChallenge->listener()->performDefaultHandling();
617             return;
618         }
619
620         RefPtr<AuthenticationChallengeProxy> challenge = authenticationChallenge;
621         RefPtr<CompletionHandlerCallChecker> checker = CompletionHandlerCallChecker::create(navigationDelegate.get(), @selector(webView:didReceiveAuthenticationChallenge:completionHandler:));
622         [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) webView:m_navigationState.m_webView didReceiveAuthenticationChallenge:wrapper(*authenticationChallenge)
623             completionHandler:[challenge, checker](NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential) {
624                 checker->didCallCompletionHandler();
625
626                 switch (disposition) {
627                 case NSURLSessionAuthChallengeUseCredential: {
628                     RefPtr<WebCredential> webCredential;
629                     if (credential)
630                         webCredential = WebCredential::create(WebCore::core(credential));
631
632                     challenge->listener()->useCredential(webCredential.get());
633                     break;
634                 }
635
636                 case NSURLSessionAuthChallengePerformDefaultHandling:
637                     challenge->listener()->performDefaultHandling();
638                     break;
639
640                 case NSURLSessionAuthChallengeCancelAuthenticationChallenge:
641                     challenge->listener()->cancel();
642                     break;
643
644                 case NSURLSessionAuthChallengeRejectProtectionSpace:
645                     challenge->listener()->rejectProtectionSpaceAndContinue();
646                     break;
647
648                 default:
649                     [NSException raise:NSInvalidArgumentException format:@"Invalid NSURLSessionAuthChallengeDisposition (%ld)", (long)disposition];
650                 }
651             }
652         ];
653         return;
654     }
655 #endif
656
657     if (!m_navigationState.m_navigationDelegateMethods.webViewDidReceiveAuthenticationChallenge)
658         return;
659
660     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
661     if (!navigationDelegate)
662         return;
663
664     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didReceiveAuthenticationChallenge:wrapper(*authenticationChallenge)];
665 }
666
667 void NavigationState::LoaderClient::processDidCrash(WebKit::WebPageProxy*)
668 {
669     m_navigationState.m_navigations.clear();
670
671     if (!m_navigationState.m_navigationDelegateMethods.webViewWebProcessDidCrash)
672         return;
673
674     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
675     if (!navigationDelegate)
676         return;
677
678     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webViewWebProcessDidCrash:m_navigationState.m_webView];
679 }
680
681 PassRefPtr<API::Data> NavigationState::LoaderClient::webCryptoMasterKey(WebKit::WebPageProxy&)
682 {
683     if (!m_navigationState.m_navigationDelegateMethods.webCryptoMasterKeyForWebView)
684         return nullptr;
685
686     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
687     if (!navigationDelegate)
688         return nullptr;
689
690     RetainPtr<NSData> data = [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webCryptoMasterKeyForWebView:m_navigationState.m_webView];
691
692     return API::Data::createWithoutCopying((const unsigned char*)[data bytes], [data length], [] (unsigned char*, const void* data) {
693         [(NSData *)data release];
694     }, data.leakRef());
695 }
696
697 #if USE(QUICK_LOOK)
698 void NavigationState::LoaderClient::didStartLoadForQuickLookDocumentInMainFrame(const String& fileName, const String& uti)
699 {
700     if (!m_navigationState.m_navigationDelegateMethods.webViewDidStartLoadForQuickLookDocumentInMainFrame)
701         return;
702
703     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
704     if (!navigationDelegate)
705         return;
706
707     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:fileName uti:uti];
708 }
709
710 void NavigationState::LoaderClient::didFinishLoadForQuickLookDocumentInMainFrame(const WebKit::QuickLookDocumentData& data)
711 {
712     if (!m_navigationState.m_navigationDelegateMethods.webViewDidFinishLoadForQuickLookDocumentInMainFrame)
713         return;
714
715     auto navigationDelegate = m_navigationState.m_navigationDelegate.get();
716     if (!navigationDelegate)
717         return;
718
719     [static_cast<id <WKNavigationDelegatePrivate>>(navigationDelegate.get()) _webView:m_navigationState.m_webView didFinishLoadForQuickLookDocumentInMainFrame:(NSData *)data.decodedData()];
720 }
721 #endif
722
723 void NavigationState::willChangeIsLoading()
724 {
725     [m_webView willChangeValueForKey:@"loading"];
726 }
727
728 void NavigationState::didChangeIsLoading()
729 {
730 #if PLATFORM(IOS)
731     if (m_webView->_page->pageLoadState().isLoading())
732         m_activityToken = std::make_unique<ProcessThrottler::BackgroundActivityToken>(m_webView->_page->process().throttler());
733     else
734         m_activityToken = nullptr;
735 #endif
736
737     [m_webView didChangeValueForKey:@"loading"];
738 }
739
740 void NavigationState::willChangeTitle()
741 {
742     [m_webView willChangeValueForKey:@"title"];
743 }
744
745 void NavigationState::didChangeTitle()
746 {
747     [m_webView didChangeValueForKey:@"title"];
748 }
749
750 void NavigationState::willChangeActiveURL()
751 {
752     [m_webView willChangeValueForKey:@"URL"];
753 }
754
755 void NavigationState::didChangeActiveURL()
756 {
757     [m_webView didChangeValueForKey:@"URL"];
758 }
759
760 void NavigationState::willChangeHasOnlySecureContent()
761 {
762     [m_webView willChangeValueForKey:@"hasOnlySecureContent"];
763 }
764
765 void NavigationState::didChangeHasOnlySecureContent()
766 {
767     [m_webView didChangeValueForKey:@"hasOnlySecureContent"];
768 }
769
770 void NavigationState::willChangeEstimatedProgress()
771 {
772     [m_webView willChangeValueForKey:@"estimatedProgress"];
773 }
774
775 void NavigationState::didChangeEstimatedProgress()
776 {
777     [m_webView didChangeValueForKey:@"estimatedProgress"];
778 }
779
780 void NavigationState::willChangeCanGoBack()
781 {
782     [m_webView willChangeValueForKey:@"canGoBack"];
783 }
784
785 void NavigationState::didChangeCanGoBack()
786 {
787     [m_webView didChangeValueForKey:@"canGoBack"];
788 }
789
790 void NavigationState::willChangeCanGoForward()
791 {
792     [m_webView willChangeValueForKey:@"canGoForward"];
793 }
794
795 void NavigationState::didChangeCanGoForward()
796 {
797     [m_webView didChangeValueForKey:@"canGoForward"];
798 }
799
800 } // namespace WebKit
801
802 #endif