Index: content/browser/frame_host/navigation_controller_impl.cc |
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc |
index 0b0f411a1a041f52893e84357af935f7fe81c0df..eda129d5f155e334856105b2eed072061629bb1a 100644 |
--- a/content/browser/frame_host/navigation_controller_impl.cc |
+++ b/content/browser/frame_host/navigation_controller_impl.cc |
@@ -801,6 +801,41 @@ bool NavigationControllerImpl::RendererDidNavigate( |
// Do navigation-type specific actions. These will make and commit an entry. |
details->type = ClassifyNavigation(rfh, params); |
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kSitePerProcess)) { |
+ // For site-per-process, both ClassifyNavigation methods get it wrong (see |
+ // http://crbug.com/464014) so don't worry about a mismatch if that's the |
+ // case. |
+ auto nt = [](NavigationType type) { |
+ switch(type) { |
+ case NAVIGATION_TYPE_UNKNOWN: |
+ return "UNKNOWN"; |
+ case NAVIGATION_TYPE_NEW_PAGE: |
+ return "NEW_PAGE"; |
+ case NAVIGATION_TYPE_EXISTING_PAGE: |
+ return "EXISTING_PAGE"; |
+ case NAVIGATION_TYPE_SAME_PAGE: |
+ return "SAME_PAGE"; |
+ case NAVIGATION_TYPE_IN_PAGE: |
+ return "IN_PAGE"; |
+ case NAVIGATION_TYPE_NEW_SUBFRAME: |
+ return "NEW_SUBFRAME"; |
+ case NAVIGATION_TYPE_AUTO_SUBFRAME: |
+ return "AUTO_SUBFRAME"; |
+ case NAVIGATION_TYPE_NAV_IGNORE: |
+ return "NAV_IGNORE"; |
+ default: |
+ return "<invalid>"; |
+ } |
+ }; |
+ NavigationType new_type = ClassifyNavigationWithoutPageID(rfh, params); |
+ if (details->type != new_type) { |
+ LOG(FATAL) << "old classify is " << nt(details->type) |
+ << ", new classify is " << nt(new_type); |
+ } |
+ // Detailed logging above is temporary; will ship with vvvv below. |
+ // DCHECK_EQ(details->type, ClassifyNavigationWithoutPageID(rfh, params)); |
+ } |
// is_in_page must be computed before the entry gets committed. |
details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), |
@@ -899,13 +934,14 @@ bool NavigationControllerImpl::RendererDidNavigate( |
NavigationType NavigationControllerImpl::ClassifyNavigation( |
RenderFrameHostImpl* rfh, |
const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { |
+ LOG(ERROR) << "NavigationControllerImpl::ClassifyNavigation"; |
if (params.page_id == -1) { |
- // TODO(nasko, creis): An out-of-process child frame has no way of |
- // knowing the page_id of its parent, so it is passing back -1. The |
- // semantics here should be re-evaluated during session history refactor |
- // (see http://crbug.com/236848). For now, we assume this means the |
- // child frame loaded and proceed. Note that this may do the wrong thing |
- // for cross-process AUTO_SUBFRAME navigations. |
+ // TODO(nasko, creis): An out-of-process child frame has no way of knowing |
+ // the page_id of its parent, so it is passing back -1. The semantics here |
+ // should be re-evaluated during session history refactor (see |
+ // http://crbug.com/236848 and in particular http://crbug.com/464014). For |
+ // now, we assume this means the child frame loaded and proceed. Note that |
+ // this may do the wrong thing for cross-process AUTO_SUBFRAME navigations. |
if (rfh->IsCrossProcessSubframe()) |
return NAVIGATION_TYPE_NEW_SUBFRAME; |
@@ -927,11 +963,13 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
// list. |
// |
// In these cases, there's nothing we can do with them, so ignore. |
+ LOG(ERROR) << " > page id is -1; ignoring"; |
return NAVIGATION_TYPE_NAV_IGNORE; |
} |
if (params.page_id > delegate_->GetMaxPageIDForSiteInstance( |
rfh->GetSiteInstance())) { |
+ LOG(ERROR) << "larger page id (" << params.page_id << ") than we've seen before (" << delegate_->GetMaxPageIDForSiteInstance(rfh->GetSiteInstance()) << ")"; |
// Greater page IDs than we've ever seen before are new pages. We may or may |
// not have a pending entry for the page, and this may or may not be the |
// main frame. |
@@ -1000,6 +1038,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get(); |
if (!ui::PageTransitionIsMainFrame(params.transition)) { |
+ LOG(ERROR) << " > subframe transition; so it's auto"; |
// All manual subframes would get new IDs and were handled above, so we |
// know this is auto. Since the current page was found in the navigation |
// entry list, we're guaranteed to have a last committed entry. |
@@ -1013,6 +1052,7 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
existing_entry != pending_entry_ && |
pending_entry_->GetPageID() == -1 && |
existing_entry == GetLastCommittedEntry()) { |
+ LOG(ERROR) << " > same page"; |
// In this case, we have a pending entry for a URL but WebCore didn't do a |
// new navigation. This happens when you press enter in the URL bar to |
// reload. We will create a pending entry, but WebKit will convert it to |
@@ -1030,6 +1070,102 @@ NavigationType NavigationControllerImpl::ClassifyNavigation( |
// an encoding override (it always sends a navigation request). |
if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, |
params.was_within_same_page, rfh)) { |
+ LOG(ERROR) << " > in page"; |
+ return NAVIGATION_TYPE_IN_PAGE; |
+ } |
+ |
+ // Since we weeded out "new" navigations above, we know this is an existing |
+ // (back/forward) navigation. |
+ LOG(ERROR) << " > existing page"; |
+ return NAVIGATION_TYPE_EXISTING_PAGE; |
+} |
+ |
+NavigationType NavigationControllerImpl::ClassifyNavigationWithoutPageID( |
+ RenderFrameHostImpl* rfh, |
+ const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { |
+ LOG(ERROR) << "NavigationControllerImpl::ClassifyNavigationWithoutPageID" |
+ << " nav_entry_id " << params.nav_entry_id; |
+ if (params.did_create_new_entry) { |
+ // A new entry. We may or may not have a pending entry for the page, and |
+ // this may or may not be the main frame. |
+ if (!rfh->GetParent()) { |
+ // TODO(avi): Everyone does ui::PageTransitionIsMainFrame to determine |
+ // main-frame-ness. I can get that consumers of page transitions would |
+ // want to do that, but for code inside RenderFrameHost and NavController? |
+ // Please. |
+ return NAVIGATION_TYPE_NEW_PAGE; |
+ } |
+ |
+ // When this is a new subframe navigation, we should have a committed page |
+ // in which it's a subframe. This may not be the case when an iframe is |
+ // navigated on a popup navigated to about:blank (the iframe would be |
+ // written into the popup by script on the main page). For these cases, |
+ // there isn't any navigation stuff we can do, so just ignore it. |
+ if (!GetLastCommittedEntry()) |
+ return NAVIGATION_TYPE_NAV_IGNORE; |
+ |
+ // Valid subframe navigation. |
+ return NAVIGATION_TYPE_NEW_SUBFRAME; |
+ } |
+ |
+ // We only clear the session history when navigating to a new page. |
+ DCHECK(!params.history_list_was_cleared); |
+ |
+ if (rfh->GetParent()) { |
+ // All manual subframes would be WebStandardCommit and handled above, so we |
+ // know this is auto. |
+ DCHECK(GetLastCommittedEntry()); |
+ return NAVIGATION_TYPE_AUTO_SUBFRAME; |
+ } |
+ |
+ if (params.nav_entry_id == 0) { |
+ // Just like above in the did_create_new_entry case, it's possible to |
+ // scribble onto an uncommitted page. Again, there isn't any navigation |
+ // stuff that we can do, so ignore it here as well. |
+ if (!GetLastCommittedEntry()) |
+ return NAVIGATION_TYPE_NAV_IGNORE; |
+ |
+ // This is a renderer-initiated navigation, but didn't create a new page. |
+ if (params.was_within_same_page) { |
+ // This is history.replaceState(), which is renderer-initiated yet within |
+ // the same page. |
+ return NAVIGATION_TYPE_IN_PAGE; |
+ } else { |
+ // This is history.reload() and client-side redirection. |
+ return NAVIGATION_TYPE_EXISTING_PAGE; |
+ } |
+ } |
+ |
+ if (pending_entry_ && pending_entry_index_ == -1 && |
+ pending_entry_->GetUniqueID() == params.nav_entry_id) { |
+ // In this case, we have a pending entry for a load of a new URL but Blink |
+ // didn't do a new navigation (params.did_create_new_entry). This happens |
+ // when you press enter in the URL bar to reload. We will create a pending |
+ // entry, but Blink will convert it to a reload since it's the same page and |
+ // not create a new entry for it (the user doesn't want to have a new |
+ // back/forward entry when they do this). Therefore we want to just ignore |
+ // the pending entry and go back to where we were (the "existing entry"). |
+ return NAVIGATION_TYPE_SAME_PAGE; |
+ } |
+ |
+ // Now we know that the notification is for an existing page. Find that entry. |
+ int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id); |
+ if (existing_entry_index == -1) { |
+ // The page was not found. It could have been pruned because of the limit on |
+ // back/forward entries (not likely since we'll usually tell it to navigate |
+ // to such entries). It could also mean that the renderer is smoking crack. |
+ NOTREACHED() << "Could not find nav entry with id " << params.nav_entry_id; |
+ return NAVIGATION_TYPE_NAV_IGNORE; |
+ } |
+ |
+ // Any top-level navigations with the same base (minus the reference fragment) |
+ // are in-page navigations. (We weeded out subframe navigations above.) Most |
+ // 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)) { |
return NAVIGATION_TYPE_IN_PAGE; |
} |
@@ -1565,6 +1701,7 @@ int NavigationControllerImpl::GetPendingEntryIndex() const { |
void NavigationControllerImpl::InsertOrReplaceEntry(NavigationEntryImpl* entry, |
bool replace) { |
+ LOG(ERROR) << "NavigationControllerImpl::InsertOrReplaceEntry"; |
DCHECK(entry->GetTransitionType() != ui::PAGE_TRANSITION_AUTO_SUBFRAME); |
// Copy the pending entry's unique ID to the committed entry. |
@@ -1779,6 +1916,15 @@ int NavigationControllerImpl::GetEntryIndexWithPageID( |
return -1; |
} |
+int NavigationControllerImpl::GetEntryIndexWithUniqueID( |
+ int nav_entry_id) const { |
+ for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { |
+ if (entries_[i]->GetUniqueID() == nav_entry_id) |
+ return i; |
+ } |
+ return -1; |
+} |
+ |
NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { |
if (transient_entry_index_ == -1) |
return NULL; |