| 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]; | 
| } | 
| } | 
|  | 
|  |