| Index: ios/web/web_state/ui/crw_web_controller.mm
|
| diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
|
| index a11db2cd1f93d34b9d54ca75e09a11516d9a6a6b..4a91a55197aa70258ad070550f31ef2fd50c312b 100644
|
| --- a/ios/web/web_state/ui/crw_web_controller.mm
|
| +++ b/ios/web/web_state/ui/crw_web_controller.mm
|
| @@ -616,10 +616,11 @@ NSError* WKWebViewErrorWithSource(NSError* error, WKWebViewErrorSource source) {
|
| // events. Navigation is considered complete when the document has finished
|
| // loading, or when other page load mechanics are completed on a
|
| // non-document-changing URL change.
|
| -- (void)didFinishNavigation;
|
| +- (void)didFinishNavigation:(WKNavigation*)navigation;
|
| // Update the appropriate parts of the model and broadcast to the embedder. This
|
| // may be called multiple times and thus must be idempotent.
|
| -- (void)loadCompleteWithSuccess:(BOOL)loadSuccess;
|
| +- (void)loadCompleteWithSuccess:(BOOL)loadSuccess
|
| + forNavigation:(WKNavigation*)navigation;
|
| // Called after URL is finished loading and _loadPhase is set to PAGE_LOADED.
|
| - (void)didFinishWithURL:(const GURL&)currentURL loadSuccess:(BOOL)loadSuccess;
|
| // Navigates forwards or backwards by |delta| pages. No-op if delta is out of
|
| @@ -756,7 +757,7 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
|
| // provided by web view.
|
| - (void)updateSSLStatusForCurrentNavigationItem;
|
| // Called when a load ends in an SSL error and certificate chain.
|
| -- (void)handleSSLCertError:(NSError*)error;
|
| +- (void)handleSSLCertError:(NSError*)error forNavigation:navigation;
|
|
|
| // Used in webView:didReceiveAuthenticationChallenge:completionHandler: to
|
| // reply with NSURLSessionAuthChallengeDisposition and credentials.
|
| @@ -889,7 +890,9 @@ typedef void (^ViewportStateCompletion)(const web::PageViewportState*);
|
| // TODO(stuartmorgan): Figure out if there's actually enough shared logic that
|
| // this makes sense. At the very least remove inMainFrame since that only makes
|
| // sense for UIWebView.
|
| -- (void)handleLoadError:(NSError*)error inMainFrame:(BOOL)inMainFrame;
|
| +- (void)handleLoadError:(NSError*)error
|
| + inMainFrame:(BOOL)inMainFrame
|
| + forNavigation:(WKNavigation*)navigation;
|
|
|
| // Handles cancelled load in WKWebView (error with NSURLErrorCancelled code).
|
| - (void)handleCancelledError:(NSError*)error;
|
| @@ -2070,7 +2073,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| [sessionController isSameDocumentNavigationBetweenItem:fromItem
|
| andItem:toItem];
|
| if (sameDocumentNavigation) {
|
| - [sessionController goToItemAtIndex:index];
|
| + [sessionController goToItemAtIndex:index discardNonCommittedItems:YES];
|
| [self updateHTML5HistoryState];
|
| } else {
|
| [sessionController discardNonCommittedItems];
|
| @@ -2088,15 +2091,16 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| return _loadPhase == web::PAGE_LOADED;
|
| }
|
|
|
| -- (void)didFinishNavigation {
|
| +- (void)didFinishNavigation:(WKNavigation*)navigation {
|
| // This can be called at multiple times after the document has loaded. Do
|
| // nothing if the document has already loaded.
|
| if (_loadPhase == web::PAGE_LOADED)
|
| return;
|
| - [self loadCompleteWithSuccess:YES];
|
| + [self loadCompleteWithSuccess:YES forNavigation:navigation];
|
| }
|
|
|
| -- (void)loadCompleteWithSuccess:(BOOL)loadSuccess {
|
| +- (void)loadCompleteWithSuccess:(BOOL)loadSuccess
|
| + forNavigation:(WKNavigation*)navigation {
|
| [self removePlaceholderOverlay];
|
| // The webView may have been torn down (or replaced by a native view). Be
|
| // safe and do nothing if that's happened.
|
| @@ -2111,10 +2115,10 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
|
|
| [self optOutScrollsToTopForSubviews];
|
|
|
| - // Ensure the URL is as expected (and already reported to the delegate).
|
| - // If |_lastRegisteredRequestURL| is invalid then |currentURL| will be
|
| - // "about:blank".
|
| - DCHECK((currentURL == _lastRegisteredRequestURL) ||
|
| + DCHECK((currentURL == _lastRegisteredRequestURL) || // latest navigation
|
| + // previous navigation
|
| + ![[_navigationStates lastAddedNavigation] isEqual:navigation] ||
|
| + // invalid URL load
|
| (!_lastRegisteredRequestURL.is_valid() &&
|
| _documentURL.spec() == url::kAboutBlankURL))
|
| << std::endl
|
| @@ -2823,7 +2827,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| return;
|
| base::scoped_nsobject<CRWWebController> strongSelf([weakSelf retain]);
|
| [strongSelf optOutScrollsToTopForSubviews];
|
| - [strongSelf didFinishNavigation];
|
| + [strongSelf didFinishNavigation:nil];
|
| }];
|
| return YES;
|
| }
|
| @@ -2878,7 +2882,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| if (!weakSelf || weakSelf.get()->_isBeingDestroyed)
|
| return;
|
| base::scoped_nsobject<CRWWebController> strongSelf([weakSelf retain]);
|
| - [strongSelf didFinishNavigation];
|
| + [strongSelf didFinishNavigation:nil];
|
| }];
|
| return YES;
|
| }
|
| @@ -3113,7 +3117,9 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| return YES;
|
| }
|
|
|
| -- (void)handleLoadError:(NSError*)error inMainFrame:(BOOL)inMainFrame {
|
| +- (void)handleLoadError:(NSError*)error
|
| + inMainFrame:(BOOL)inMainFrame
|
| + forNavigation:(WKNavigation*)navigation {
|
| NSString* MIMEType = [_pendingNavigationInfo MIMEType];
|
| if ([_passKitDownloader isMIMETypePassKitType:MIMEType])
|
| return;
|
| @@ -3176,7 +3182,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| id<CRWNativeContent> controller =
|
| [_delegate controllerForUnhandledContentAtURL:errorGURL];
|
| if (controller) {
|
| - [self loadCompleteWithSuccess:NO];
|
| + [self loadCompleteWithSuccess:NO forNavigation:navigation];
|
| [self removeWebViewAllowingCachedReconstruction:NO];
|
| [self setNativeController:controller];
|
| [self loadNativeViewWithSuccess:YES];
|
| @@ -3204,7 +3210,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| NSURLErrorFailingURLStringErrorKey : [errorURL absoluteString],
|
| NSUnderlyingErrorKey : error
|
| }];
|
| - [self loadCompleteWithSuccess:NO];
|
| + [self loadCompleteWithSuccess:NO forNavigation:navigation];
|
| [self loadErrorInNativeView:wrapperError];
|
| return;
|
| }
|
| @@ -3216,7 +3222,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| return;
|
| }
|
|
|
| - [self loadCompleteWithSuccess:NO];
|
| + [self loadCompleteWithSuccess:NO forNavigation:navigation];
|
| [self loadErrorInNativeView:error];
|
| }
|
|
|
| @@ -3949,7 +3955,8 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| _webStateImpl->OnVisibleSecurityStateChange();
|
| }
|
|
|
| -- (void)handleSSLCertError:(NSError*)error {
|
| +- (void)handleSSLCertError:(NSError*)error
|
| + forNavigation:(WKNavigation*)navigation {
|
| CHECK(web::IsWKWebViewSSLCertError(error));
|
|
|
| net::SSLInfo info;
|
| @@ -3959,7 +3966,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| // |info.cert| can be null if certChain in NSError is empty or can not be
|
| // parsed, in this case do not ask delegate if error should be allowed, it
|
| // should not be.
|
| - [self handleLoadError:error inMainFrame:YES];
|
| + [self handleLoadError:error inMainFrame:YES forNavigation:navigation];
|
| return;
|
| }
|
|
|
| @@ -4159,7 +4166,9 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| messageRouter:messageRouter
|
| completionHandler:^(NSError* loadError) {
|
| if (loadError)
|
| - [self handleLoadError:loadError inMainFrame:YES];
|
| + [self handleLoadError:loadError
|
| + inMainFrame:YES
|
| + forNavigation:nil];
|
| else
|
| self.webStateImpl->SetContentsMimeType("text/html");
|
| }];
|
| @@ -4423,6 +4432,13 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| [_navigationStates setState:web::WKNavigationState::STARTED
|
| forNavigation:navigation];
|
|
|
| + if (navigation &&
|
| + ![[_navigationStates lastAddedNavigation] isEqual:navigation]) {
|
| + // |navigation| is not the latest navigation and will be cancelled.
|
| + // Ignore |navigation| as a new navigation will start soon.
|
| + return;
|
| + }
|
| +
|
| GURL webViewURL = net::GURLWithNSURL(webView.URL);
|
| if (webViewURL.is_empty()) {
|
| // May happen on iOS9, however in didCommitNavigation: callback the URL
|
| @@ -4510,9 +4526,9 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| error = WKWebViewErrorWithSource(error, PROVISIONAL_LOAD);
|
|
|
| if (web::IsWKWebViewSSLCertError(error))
|
| - [self handleSSLCertError:error];
|
| + [self handleSSLCertError:error forNavigation:navigation];
|
| else
|
| - [self handleLoadError:error inMainFrame:YES];
|
| + [self handleLoadError:error inMainFrame:YES forNavigation:navigation];
|
| }
|
|
|
| // This must be reset at the end, since code above may need information about
|
| @@ -4539,8 +4555,15 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| // will be "about:blank".
|
| [[self sessionController] updatePendingItem:_documentURL];
|
| }
|
| - DCHECK(_documentURL == _lastRegisteredRequestURL ||
|
| - (!_lastRegisteredRequestURL.is_valid() &&
|
| +
|
| + // If |navigation| is nil (which happens for windows open by DOM), then it
|
| + // should be the first and the only pending navigaiton.
|
| + BOOL isLastNavigation =
|
| + !navigation ||
|
| + [[_navigationStates lastAddedNavigation] isEqual:navigation];
|
| + DCHECK(_documentURL == _lastRegisteredRequestURL || // latest navigation
|
| + !isLastNavigation || // previous navigation
|
| + (!_lastRegisteredRequestURL.is_valid() && // invalid URL load
|
| _documentURL.spec() == url::kAboutBlankURL));
|
|
|
| self.webStateImpl->UpdateHttpResponseHeaders(_documentURL);
|
| @@ -4567,7 +4590,23 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| [self injectWindowID];
|
| }
|
|
|
| - [self webPageChanged];
|
| + if (isLastNavigation) {
|
| + [self webPageChanged];
|
| + } else {
|
| + // WKWebView has more than one in progress navigation, and committed
|
| + // navigation was not the latest. It is critical to keep last committed
|
| + // URL the same as actual document URL, so try guessing which navigation
|
| + // item should be set to current.
|
| + // TODO(crbug.com/712269):
|
| + for (int i = 0; i < self.navigationManagerImpl->GetItemCount(); i++) {
|
| + web::NavigationItem* item = self.navigationManagerImpl->GetItemAtIndex(i);
|
| + if (item->GetURL() == _documentURL) {
|
| + // Do not discard pending entry, because another pending navigation is
|
| + // still in progress and will commit or fail soon.
|
| + [self.sessionController goToItemAtIndex:i discardNonCommittedItems:NO];
|
| + }
|
| + }
|
| + }
|
| self.webStateImpl->OnNavigationCommitted(_documentURL);
|
|
|
| [self updateSSLStatusForCurrentNavigationItem];
|
| @@ -4599,7 +4638,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| // WKUserScriptInjectionTimeAtDocumentEnd to inject this material at the
|
| // appropriate time rather than invoking here.
|
| web::ExecuteJavaScript(webView, @"__gCrWeb.didFinishNavigation()", nil);
|
| - [self didFinishNavigation];
|
| + [self didFinishNavigation:navigation];
|
| }
|
|
|
| - (void)webView:(WKWebView*)webView
|
| @@ -4609,7 +4648,8 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| forNavigation:navigation];
|
|
|
| [self handleLoadError:WKWebViewErrorWithSource(error, NAVIGATION)
|
| - inMainFrame:YES];
|
| + inMainFrame:YES
|
| + forNavigation:navigation];
|
| _certVerificationErrors->Clear();
|
| }
|
|
|
| @@ -4769,7 +4809,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| // Fast back forward navigation may not call |didFinishNavigation:|, so
|
| // signal did finish navigation explicitly.
|
| if (_lastRegisteredRequestURL == _documentURL) {
|
| - [self didFinishNavigation];
|
| + [self didFinishNavigation:nil];
|
| }
|
| }
|
|
|
| @@ -4916,7 +4956,7 @@ const NSTimeInterval kSnapshotOverlayTransition = 0.5;
|
| [self didStartLoadingURL:_documentURL];
|
| _webStateImpl->OnSameDocumentNavigation(newURL);
|
| [self updateSSLStatusForCurrentNavigationItem];
|
| - [self didFinishNavigation];
|
| + [self didFinishNavigation:nil];
|
| }
|
| }
|
|
|
|
|