Fix the in-page navigation check to look at the correct entry.

BUG=495708
TEST=everything stays green

Review URL: https://codereview.chromium.org/1166473006

Cr-Commit-Position: refs/heads/master@{#333340}
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 4c9fcf02..5d4dee8 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -106,43 +106,6 @@
   }
 }
 
-// There are two general cases where a navigation is in page:
-// 1. A fragment navigation, in which the url is kept the same except for the
-//    reference fragment.
-// 2. A history API navigation (pushState and replaceState). This case is
-//    always in-page, but the urls are not guaranteed to match excluding the
-//    fragment. The relevant spec allows pushState/replaceState to any URL on
-//    the same origin.
-// However, due to reloads, even identical urls are *not* guaranteed to be
-// in-page navigations, we have to trust the renderer almost entirely.
-// The one thing we do know is that cross-origin navigations will *never* be
-// in-page. Therefore, trust the renderer if the URLs are on the same origin,
-// and assume the renderer is malicious if a cross-origin navigation claims to
-// be in-page.
-bool AreURLsInPageNavigation(const GURL& existing_url,
-                             const GURL& new_url,
-                             bool renderer_says_in_page,
-                             RenderFrameHost* rfh) {
-  WebPreferences prefs = rfh->GetRenderViewHost()->GetWebkitPreferences();
-  bool is_same_origin = existing_url.is_empty() ||
-                        // TODO(japhet): We should only permit navigations
-                        // originating from about:blank to be in-page if the
-                        // about:blank is the first document that frame loaded.
-                        // We don't have sufficient information to identify
-                        // that case at the moment, so always allow about:blank
-                        // for now.
-                        existing_url == GURL(url::kAboutBlankURL) ||
-                        existing_url.GetOrigin() == new_url.GetOrigin() ||
-                        !prefs.web_security_enabled ||
-                        (prefs.allow_universal_access_from_file_urls &&
-                         existing_url.SchemeIs(url::kFileScheme));
-  if (!is_same_origin && renderer_says_in_page) {
-    bad_message::ReceivedBadMessage(rfh->GetProcess(),
-                                    bad_message::NC_IN_PAGE_NAVIGATION);
-  }
-  return is_same_origin && renderer_says_in_page;
-}
-
 // Determines whether or not we should be carrying over a user agent override
 // between two NavigationEntries.
 bool ShouldKeepOverride(const NavigationEntry* last_entry) {
@@ -857,7 +820,7 @@
   }
 
   // is_in_page must be computed before the entry gets committed.
-  details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(),
+  details->is_in_page = IsURLInPageNavigation(
       params.url, params.was_within_same_page, rfh);
 
   switch (details->type) {
@@ -1090,10 +1053,8 @@
   // the time this doesn't matter since WebKit doesn't tell us about subframe
   // navigations that don't actually navigate, but it can happen when there is
   // an encoding override (it always sends a navigation request).
-  if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
-                              params.was_within_same_page, rfh)) {
+  if (IsURLInPageNavigation(params.url, params.was_within_same_page, rfh))
     return NAVIGATION_TYPE_IN_PAGE;
-  }
 
   // Since we weeded out "new" navigations above, we know this is an existing
   // (back/forward) navigation.
@@ -1148,8 +1109,7 @@
     if (!last_committed)
       return NAVIGATION_TYPE_NAV_IGNORE;
 
-    if (AreURLsInPageNavigation(last_committed->GetURL(), params.url,
-                                params.was_within_same_page, rfh)) {
+    if (IsURLInPageNavigation(params.url, params.was_within_same_page, rfh)) {
       // This is history.replaceState(), which is renderer-initiated yet within
       // the same page.
       return NAVIGATION_TYPE_IN_PAGE;
@@ -1203,11 +1163,8 @@
   // of the time this doesn't matter since Blink doesn't tell us about subframe
   // navigations that don't actually navigate, but it can happen when there is
   // an encoding override (it always sends a navigation request).
-  NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
-  if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
-                              params.was_within_same_page, rfh)) {
+  if (IsURLInPageNavigation(params.url, params.was_within_same_page, rfh))
     return NAVIGATION_TYPE_IN_PAGE;
-  }
 
   // Since we weeded out "new" navigations above, we know this is an existing
   // (back/forward) navigation.
@@ -1513,13 +1470,54 @@
   return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin());
 }
 
+// There are two general cases where a navigation is "in page":
+// 1. A fragment navigation, in which the url is kept the same except for the
+//    reference fragment.
+// 2. A history API navigation (pushState and replaceState). This case is
+//    always in-page, but the urls are not guaranteed to match excluding the
+//    fragment. The relevant spec allows pushState/replaceState to any URL on
+//    the same origin.
+// However, due to reloads, even identical urls are *not* guaranteed to be
+// in-page navigations, we have to trust the renderer almost entirely.
+// The one thing we do know is that cross-origin navigations will *never* be
+// in-page. Therefore, trust the renderer if the URLs are on the same origin,
+// and assume the renderer is malicious if a cross-origin navigation claims to
+// be in-page.
 bool NavigationControllerImpl::IsURLInPageNavigation(
     const GURL& url,
     bool renderer_says_in_page,
     RenderFrameHost* rfh) const {
-  NavigationEntry* last_committed = GetLastCommittedEntry();
-  return last_committed && AreURLsInPageNavigation(
-      last_committed->GetURL(), url, renderer_says_in_page, rfh);
+  GURL last_committed_url;
+  if (rfh->GetParent()) {
+    last_committed_url = rfh->GetLastCommittedURL();
+  } else {
+    NavigationEntry* last_committed = GetLastCommittedEntry();
+    // There must be a last-committed entry to compare URLs to. TODO(avi): When
+    // might Blink say that a navigation is in-page yet there be no last-
+    // committed entry?
+    if (!last_committed)
+      return false;
+    last_committed_url = last_committed->GetURL();
+  }
+
+  WebPreferences prefs = rfh->GetRenderViewHost()->GetWebkitPreferences();
+  bool is_same_origin = last_committed_url.is_empty() ||
+                        // TODO(japhet): We should only permit navigations
+                        // originating from about:blank to be in-page if the
+                        // about:blank is the first document that frame loaded.
+                        // We don't have sufficient information to identify
+                        // that case at the moment, so always allow about:blank
+                        // for now.
+                        last_committed_url == GURL(url::kAboutBlankURL) ||
+                        last_committed_url.GetOrigin() == url.GetOrigin() ||
+                        !prefs.web_security_enabled ||
+                        (prefs.allow_universal_access_from_file_urls &&
+                         last_committed_url.SchemeIs(url::kFileScheme));
+  if (!is_same_origin && renderer_says_in_page) {
+    bad_message::ReceivedBadMessage(rfh->GetProcess(),
+                                    bad_message::NC_IN_PAGE_NAVIGATION);
+  }
+  return is_same_origin && renderer_says_in_page;
 }
 
 void NavigationControllerImpl::CopyStateFrom(