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