Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Side by Side Diff: content/browser/frame_host/navigation_controller_impl.cc

Issue 1002803002: Classify navigations without page id in parallel to the existing classifier. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: relax the dcheck Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/frame_host/navigation_controller_impl.h" 5 #include "content/browser/frame_host/navigation_controller_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after
814 // pending parameters that were saved. 814 // pending parameters that were saved.
815 if (params.url_is_unreachable && failed_pending_entry_id_ != 0) { 815 if (params.url_is_unreachable && failed_pending_entry_id_ != 0) {
816 details->did_replace_entry = failed_pending_entry_should_replace_; 816 details->did_replace_entry = failed_pending_entry_should_replace_;
817 } else { 817 } else {
818 details->did_replace_entry = pending_entry_ && 818 details->did_replace_entry = pending_entry_ &&
819 pending_entry_->should_replace_entry(); 819 pending_entry_->should_replace_entry();
820 } 820 }
821 821
822 // Do navigation-type specific actions. These will make and commit an entry. 822 // Do navigation-type specific actions. These will make and commit an entry.
823 details->type = ClassifyNavigation(rfh, params); 823 details->type = ClassifyNavigation(rfh, params);
824 #if DCHECK_IS_ON()
825 // For site-per-process, both ClassifyNavigation methods get it wrong (see
826 // http://crbug.com/464014) so don't worry about a mismatch if that's the
827 // case.
828 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
829 switches::kSitePerProcess)) {
830 NavigationType new_type = ClassifyNavigationWithoutPageID(rfh, params);
831 // There's constant disagreements over SAME_PAGE between the two classifiers
832 // so ignore disagreements if that's the case. Otherwise, enforce agreement.
833 // TODO(avi): Work this out.
834 if (details->type != NAVIGATION_TYPE_SAME_PAGE &&
835 new_type != NAVIGATION_TYPE_SAME_PAGE) {
836 DCHECK_EQ(details->type, new_type);
837 }
838 }
839 #endif // DCHECK_IS_ON()
824 840
825 // is_in_page must be computed before the entry gets committed. 841 // is_in_page must be computed before the entry gets committed.
826 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), 842 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(),
827 params.url, params.was_within_same_page, rfh); 843 params.url, params.was_within_same_page, rfh);
828 844
829 switch (details->type) { 845 switch (details->type) {
830 case NAVIGATION_TYPE_NEW_PAGE: 846 case NAVIGATION_TYPE_NEW_PAGE:
831 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); 847 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry);
832 break; 848 break;
833 case NAVIGATION_TYPE_EXISTING_PAGE: 849 case NAVIGATION_TYPE_EXISTING_PAGE:
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1026 DCHECK(GetLastCommittedEntry()); 1042 DCHECK(GetLastCommittedEntry());
1027 return NAVIGATION_TYPE_AUTO_SUBFRAME; 1043 return NAVIGATION_TYPE_AUTO_SUBFRAME;
1028 } 1044 }
1029 1045
1030 // Anything below here we know is a main frame navigation. 1046 // Anything below here we know is a main frame navigation.
1031 if (pending_entry_ && 1047 if (pending_entry_ &&
1032 !pending_entry_->is_renderer_initiated() && 1048 !pending_entry_->is_renderer_initiated() &&
1033 existing_entry != pending_entry_ && 1049 existing_entry != pending_entry_ &&
1034 pending_entry_->GetPageID() == -1 && 1050 pending_entry_->GetPageID() == -1 &&
1035 existing_entry == GetLastCommittedEntry() && 1051 existing_entry == GetLastCommittedEntry() &&
1036 !params.was_within_same_page && 1052 !params.was_within_same_page) {
1037 params.url == existing_entry->GetURL() && 1053 // In order to prevent unrelated pending entries from interfering with
1038 (params.url == pending_entry_->GetURL() || 1054 // this classification, make sure that the URL committed matches the URLs
1039 (params.redirects.size() && 1055 // of both the existing entry and the pending entry. There might have been
1040 params.redirects[0] == pending_entry_->GetURL()))) { 1056 // a redirection, though, so allow both the existing and pending entries
1041 // In this case, we have a pending entry for a URL but Blink didn't do a new 1057 // to match either the final URL that committed, or the original one
1042 // navigation. This happens when you press enter in the URL bar to reload. 1058 // before redirection.
1043 // We will create a pending entry, but Blink will convert it to a reload 1059 GURL original_url;
1044 // since it's the same page and not create a new entry for it (the user 1060 if (params.redirects.size())
1045 // doesn't want to have a new back/forward entry when they do this). If this 1061 original_url = params.redirects[0];
1046 // matches the last committed entry, we want to just ignore the pending 1062
1047 // entry and go back to where we were (the "existing entry"). 1063 if ((params.url == existing_entry->GetURL() ||
1048 return NAVIGATION_TYPE_SAME_PAGE; 1064 original_url == existing_entry->GetURL()) &&
1065 (params.url == pending_entry_->GetURL() ||
1066 original_url == pending_entry_->GetURL())) {
1067 // In this case, we have a pending entry for a URL but Blink didn't do a
1068 // new navigation. This happens when you press enter in the URL bar to
1069 // reload. We will create a pending entry, but Blink will convert it to a
1070 // reload since it's the same page and not create a new entry for it (the
1071 // user doesn't want to have a new back/forward entry when they do this).
1072 // If this matches the last committed entry, we want to just ignore the
1073 // pending entry and go back to where we were (the "existing entry").
1074 return NAVIGATION_TYPE_SAME_PAGE;
1075 }
1049 } 1076 }
1050 1077
1051 // Any toplevel navigations with the same base (minus the reference fragment) 1078 // Any toplevel navigations with the same base (minus the reference fragment)
1052 // are in-page navigations. We weeded out subframe navigations above. Most of 1079 // are in-page navigations. We weeded out subframe navigations above. Most of
1053 // the time this doesn't matter since WebKit doesn't tell us about subframe 1080 // the time this doesn't matter since WebKit doesn't tell us about subframe
1054 // navigations that don't actually navigate, but it can happen when there is 1081 // navigations that don't actually navigate, but it can happen when there is
1055 // an encoding override (it always sends a navigation request). 1082 // an encoding override (it always sends a navigation request).
1056 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, 1083 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
1057 params.was_within_same_page, rfh)) { 1084 params.was_within_same_page, rfh)) {
1058 return NAVIGATION_TYPE_IN_PAGE; 1085 return NAVIGATION_TYPE_IN_PAGE;
1059 } 1086 }
1060 1087
1061 // Since we weeded out "new" navigations above, we know this is an existing 1088 // Since we weeded out "new" navigations above, we know this is an existing
1062 // (back/forward) navigation. 1089 // (back/forward) navigation.
1063 return NAVIGATION_TYPE_EXISTING_PAGE; 1090 return NAVIGATION_TYPE_EXISTING_PAGE;
1064 } 1091 }
1065 1092
1093 NavigationType NavigationControllerImpl::ClassifyNavigationWithoutPageID(
1094 RenderFrameHostImpl* rfh,
1095 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const {
1096 if (params.did_create_new_entry) {
1097 // A new entry. We may or may not have a pending entry for the page, and
1098 // this may or may not be the main frame.
1099 if (ui::PageTransitionIsMainFrame(params.transition)) {
1100 // TODO(avi): I want to use |if (!rfh->GetParent())| here but lots of unit
1101 // tests fake auto subframe commits by sending the main frame a
1102 // PAGE_TRANSITION_AUTO_SUBFRAME transition. Fix those, and adjust here.
1103 return NAVIGATION_TYPE_NEW_PAGE;
1104 }
1105
1106 // When this is a new subframe navigation, we should have a committed page
1107 // in which it's a subframe. This may not be the case when an iframe is
1108 // navigated on a popup navigated to about:blank (the iframe would be
1109 // written into the popup by script on the main page). For these cases,
1110 // there isn't any navigation stuff we can do, so just ignore it.
1111 if (!GetLastCommittedEntry())
1112 return NAVIGATION_TYPE_NAV_IGNORE;
1113
1114 // Valid subframe navigation.
1115 return NAVIGATION_TYPE_NEW_SUBFRAME;
1116 }
1117
1118 // We only clear the session history when navigating to a new page.
1119 DCHECK(!params.history_list_was_cleared);
1120
1121 if (!ui::PageTransitionIsMainFrame(params.transition)) {
1122 // All manual subframes would be did_create_new_entry and handled above, so
1123 // we know this is auto.
1124 if (GetLastCommittedEntry()) {
1125 return NAVIGATION_TYPE_AUTO_SUBFRAME;
1126 } else {
1127 // We ignore subframes created in non-committed pages; we'd appreciate if
1128 // people stopped doing that.
1129 return NAVIGATION_TYPE_NAV_IGNORE;
1130 }
1131 }
1132
1133 if (params.nav_entry_id == 0) {
1134 // This is a renderer-initiated navigation (nav_entry_id == 0), but didn't
1135 // create a new page.
1136
1137 // Just like above in the did_create_new_entry case, it's possible to
1138 // scribble onto an uncommitted page. Again, there isn't any navigation
1139 // stuff that we can do, so ignore it here as well.
1140 if (!GetLastCommittedEntry())
1141 return NAVIGATION_TYPE_NAV_IGNORE;
1142
1143 if (params.was_within_same_page) {
1144 // This is history.replaceState(), which is renderer-initiated yet within
1145 // the same page.
1146 return NAVIGATION_TYPE_IN_PAGE;
1147 } else {
1148 // This is history.reload() or a client-side redirect.
1149 return NAVIGATION_TYPE_EXISTING_PAGE;
1150 }
1151 }
1152
1153 if (pending_entry_ && pending_entry_index_ == -1 &&
1154 pending_entry_->GetUniqueID() == params.nav_entry_id) {
1155 // In this case, we have a pending entry for a load of a new URL but Blink
1156 // didn't do a new navigation (params.did_create_new_entry). This happens
1157 // when you press enter in the URL bar to reload. We will create a pending
1158 // entry, but Blink will convert it to a reload since it's the same page and
1159 // not create a new entry for it (the user doesn't want to have a new
1160 // back/forward entry when they do this). Therefore we want to just ignore
1161 // the pending entry and go back to where we were (the "existing entry").
1162 return NAVIGATION_TYPE_SAME_PAGE;
1163 }
1164
1165 if (params.intended_as_new_entry) {
1166 // This was intended to be a navigation to a new entry but the pending entry
1167 // got cleared in the meanwhile. Classify as EXISTING_PAGE because we may or
1168 // may not have a pending entry.
1169 return NAVIGATION_TYPE_EXISTING_PAGE;
1170 }
1171
1172 if (params.url_is_unreachable && failed_pending_entry_id_ != 0 &&
1173 params.nav_entry_id == failed_pending_entry_id_) {
1174 // If the renderer was going to a new pending entry that got cleared because
1175 // of an error, this is the case of the user trying to retry a failed load
1176 // by pressing return. Classify as EXISTING_PAGE because we probably don't
1177 // have a pending entry.
1178 return NAVIGATION_TYPE_EXISTING_PAGE;
1179 }
1180
1181 // Now we know that the notification is for an existing page. Find that entry.
1182 int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id);
1183 if (existing_entry_index == -1) {
1184 // The page was not found. It could have been pruned because of the limit on
1185 // back/forward entries (not likely since we'll usually tell it to navigate
1186 // to such entries). It could also mean that the renderer is smoking crack.
1187 // TODO(avi): Crash the renderer like we do in the old ClassifyNavigation?
1188 NOTREACHED() << "Could not find nav entry with id " << params.nav_entry_id;
1189 return NAVIGATION_TYPE_NAV_IGNORE;
1190 }
1191
1192 // Any top-level navigations with the same base (minus the reference fragment)
1193 // are in-page navigations. (We weeded out subframe navigations above.) Most
1194 // of the time this doesn't matter since Blink doesn't tell us about subframe
1195 // navigations that don't actually navigate, but it can happen when there is
1196 // an encoding override (it always sends a navigation request).
1197 NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
1198 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
1199 params.was_within_same_page, rfh)) {
1200 return NAVIGATION_TYPE_IN_PAGE;
1201 }
1202
1203 // Since we weeded out "new" navigations above, we know this is an existing
1204 // (back/forward) navigation.
1205 return NAVIGATION_TYPE_EXISTING_PAGE;
1206 }
1207
1066 void NavigationControllerImpl::RendererDidNavigateToNewPage( 1208 void NavigationControllerImpl::RendererDidNavigateToNewPage(
1067 RenderFrameHostImpl* rfh, 1209 RenderFrameHostImpl* rfh,
1068 const FrameHostMsg_DidCommitProvisionalLoad_Params& params, 1210 const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
1069 bool replace_entry) { 1211 bool replace_entry) {
1070 NavigationEntryImpl* new_entry; 1212 NavigationEntryImpl* new_entry;
1071 bool update_virtual_url; 1213 bool update_virtual_url;
1072 // Only make a copy of the pending entry if it is appropriate for the new page 1214 // Only make a copy of the pending entry if it is appropriate for the new page
1073 // that was just loaded. We verify this at a coarse grain by checking that 1215 // that was just loaded. We verify this at a coarse grain by checking that
1074 // the SiteInstance hasn't been assigned to something else. 1216 // the SiteInstance hasn't been assigned to something else.
1075 if (pending_entry_ && 1217 if (pending_entry_ &&
(...skipping 748 matching lines...) Expand 10 before | Expand all | Expand 10 after
1824 int NavigationControllerImpl::GetEntryIndexWithPageID( 1966 int NavigationControllerImpl::GetEntryIndexWithPageID(
1825 SiteInstance* instance, int32 page_id) const { 1967 SiteInstance* instance, int32 page_id) const {
1826 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { 1968 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) {
1827 if ((entries_[i]->site_instance() == instance) && 1969 if ((entries_[i]->site_instance() == instance) &&
1828 (entries_[i]->GetPageID() == page_id)) 1970 (entries_[i]->GetPageID() == page_id))
1829 return i; 1971 return i;
1830 } 1972 }
1831 return -1; 1973 return -1;
1832 } 1974 }
1833 1975
1976 int NavigationControllerImpl::GetEntryIndexWithUniqueID(
1977 int nav_entry_id) const {
1978 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) {
1979 if (entries_[i]->GetUniqueID() == nav_entry_id)
1980 return i;
1981 }
1982 return -1;
1983 }
1984
1834 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { 1985 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const {
1835 if (transient_entry_index_ == -1) 1986 if (transient_entry_index_ == -1)
1836 return NULL; 1987 return NULL;
1837 return entries_[transient_entry_index_].get(); 1988 return entries_[transient_entry_index_].get();
1838 } 1989 }
1839 1990
1840 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) { 1991 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) {
1841 // Discard any current transient entry, we can only have one at a time. 1992 // Discard any current transient entry, we can only have one at a time.
1842 int index = 0; 1993 int index = 0;
1843 if (last_committed_entry_index_ != -1) 1994 if (last_committed_entry_index_ != -1)
(...skipping 23 matching lines...) Expand all
1867 } 2018 }
1868 } 2019 }
1869 } 2020 }
1870 2021
1871 void NavigationControllerImpl::SetGetTimestampCallbackForTest( 2022 void NavigationControllerImpl::SetGetTimestampCallbackForTest(
1872 const base::Callback<base::Time()>& get_timestamp_callback) { 2023 const base::Callback<base::Time()>& get_timestamp_callback) {
1873 get_timestamp_callback_ = get_timestamp_callback; 2024 get_timestamp_callback_ = get_timestamp_callback;
1874 } 2025 }
1875 2026
1876 } // namespace content 2027 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698