OLD | NEW |
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 Loading... |
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 (!base::CommandLine::ForCurrentProcess()->HasSwitch( | |
825 switches::kSitePerProcess)) { | |
826 // For site-per-process, both ClassifyNavigation methods get it wrong (see | |
827 // http://crbug.com/464014) so don't worry about a mismatch if that's the | |
828 // case. | |
829 DCHECK_EQ(details->type, ClassifyNavigationWithoutPageID(rfh, params)); | |
830 } | |
831 | 824 |
832 // is_in_page must be computed before the entry gets committed. | 825 // is_in_page must be computed before the entry gets committed. |
833 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), | 826 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), |
834 params.url, params.was_within_same_page, rfh); | 827 params.url, params.was_within_same_page, rfh); |
835 | 828 |
836 switch (details->type) { | 829 switch (details->type) { |
837 case NAVIGATION_TYPE_NEW_PAGE: | 830 case NAVIGATION_TYPE_NEW_PAGE: |
838 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); | 831 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); |
839 break; | 832 break; |
840 case NAVIGATION_TYPE_EXISTING_PAGE: | 833 case NAVIGATION_TYPE_EXISTING_PAGE: |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1033 DCHECK(GetLastCommittedEntry()); | 1026 DCHECK(GetLastCommittedEntry()); |
1034 return NAVIGATION_TYPE_AUTO_SUBFRAME; | 1027 return NAVIGATION_TYPE_AUTO_SUBFRAME; |
1035 } | 1028 } |
1036 | 1029 |
1037 // Anything below here we know is a main frame navigation. | 1030 // Anything below here we know is a main frame navigation. |
1038 if (pending_entry_ && | 1031 if (pending_entry_ && |
1039 !pending_entry_->is_renderer_initiated() && | 1032 !pending_entry_->is_renderer_initiated() && |
1040 existing_entry != pending_entry_ && | 1033 existing_entry != pending_entry_ && |
1041 pending_entry_->GetPageID() == -1 && | 1034 pending_entry_->GetPageID() == -1 && |
1042 existing_entry == GetLastCommittedEntry() && | 1035 existing_entry == GetLastCommittedEntry() && |
1043 !params.was_within_same_page) { | 1036 !params.was_within_same_page && |
1044 // In order to prevent unrelated pending entries from interfering with | 1037 params.url == existing_entry->GetURL() && |
1045 // this classification, make sure that the URL committed matches the URLs | 1038 (params.url == pending_entry_->GetURL() || |
1046 // of both the existing entry and the pending entry. There might have been | 1039 (params.redirects.size() && |
1047 // a redirection, though, so allow both the existing and pending entries | 1040 params.redirects[0] == pending_entry_->GetURL()))) { |
1048 // to match either the final URL that committed, or the original one | 1041 // In this case, we have a pending entry for a URL but Blink didn't do a new |
1049 // before redirection. | 1042 // navigation. This happens when you press enter in the URL bar to reload. |
1050 GURL original_url; | 1043 // We will create a pending entry, but Blink will convert it to a reload |
1051 if (params.redirects.size()) | 1044 // since it's the same page and not create a new entry for it (the user |
1052 original_url = params.redirects[0]; | 1045 // doesn't want to have a new back/forward entry when they do this). If this |
1053 | 1046 // matches the last committed entry, we want to just ignore the pending |
1054 if ((params.url == existing_entry->GetURL() || | 1047 // entry and go back to where we were (the "existing entry"). |
1055 original_url == existing_entry->GetURL()) && | 1048 return NAVIGATION_TYPE_SAME_PAGE; |
1056 (params.url == pending_entry_->GetURL() || | |
1057 original_url == pending_entry_->GetURL())) { | |
1058 // In this case, we have a pending entry for a URL but Blink didn't do a | |
1059 // new navigation. This happens when you press enter in the URL bar to | |
1060 // reload. We will create a pending entry, but Blink will convert it to a | |
1061 // reload since it's the same page and not create a new entry for it (the | |
1062 // user doesn't want to have a new back/forward entry when they do this). | |
1063 // If this matches the last committed entry, we want to just ignore the | |
1064 // pending entry and go back to where we were (the "existing entry"). | |
1065 return NAVIGATION_TYPE_SAME_PAGE; | |
1066 } | |
1067 } | 1049 } |
1068 | 1050 |
1069 // Any toplevel navigations with the same base (minus the reference fragment) | 1051 // Any toplevel navigations with the same base (minus the reference fragment) |
1070 // are in-page navigations. We weeded out subframe navigations above. Most of | 1052 // are in-page navigations. We weeded out subframe navigations above. Most of |
1071 // the time this doesn't matter since WebKit doesn't tell us about subframe | 1053 // the time this doesn't matter since WebKit doesn't tell us about subframe |
1072 // navigations that don't actually navigate, but it can happen when there is | 1054 // navigations that don't actually navigate, but it can happen when there is |
1073 // an encoding override (it always sends a navigation request). | 1055 // an encoding override (it always sends a navigation request). |
1074 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, | 1056 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, |
1075 params.was_within_same_page, rfh)) { | 1057 params.was_within_same_page, rfh)) { |
1076 return NAVIGATION_TYPE_IN_PAGE; | 1058 return NAVIGATION_TYPE_IN_PAGE; |
1077 } | |
1078 | |
1079 // Since we weeded out "new" navigations above, we know this is an existing | |
1080 // (back/forward) navigation. | |
1081 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1082 } | |
1083 | |
1084 NavigationType NavigationControllerImpl::ClassifyNavigationWithoutPageID( | |
1085 RenderFrameHostImpl* rfh, | |
1086 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { | |
1087 if (params.did_create_new_entry) { | |
1088 // A new entry. We may or may not have a pending entry for the page, and | |
1089 // this may or may not be the main frame. | |
1090 if (ui::PageTransitionIsMainFrame(params.transition)) { | |
1091 // TODO(avi): I want to use |if (!rfh->GetParent())| here but lots of unit | |
1092 // tests fake auto subframe commits by sending the main frame a | |
1093 // PAGE_TRANSITION_AUTO_SUBFRAME transition. Fix those, and adjust here. | |
1094 return NAVIGATION_TYPE_NEW_PAGE; | |
1095 } | |
1096 | |
1097 // When this is a new subframe navigation, we should have a committed page | |
1098 // in which it's a subframe. This may not be the case when an iframe is | |
1099 // navigated on a popup navigated to about:blank (the iframe would be | |
1100 // written into the popup by script on the main page). For these cases, | |
1101 // there isn't any navigation stuff we can do, so just ignore it. | |
1102 if (!GetLastCommittedEntry()) | |
1103 return NAVIGATION_TYPE_NAV_IGNORE; | |
1104 | |
1105 // Valid subframe navigation. | |
1106 return NAVIGATION_TYPE_NEW_SUBFRAME; | |
1107 } | |
1108 | |
1109 // We only clear the session history when navigating to a new page. | |
1110 DCHECK(!params.history_list_was_cleared); | |
1111 | |
1112 if (!ui::PageTransitionIsMainFrame(params.transition)) { | |
1113 // All manual subframes would be did_create_new_entry and handled above, so | |
1114 // we know this is auto. | |
1115 if (GetLastCommittedEntry()) { | |
1116 return NAVIGATION_TYPE_AUTO_SUBFRAME; | |
1117 } else { | |
1118 // We ignore subframes created in non-committed pages; we'd appreciate if | |
1119 // people stopped doing that. | |
1120 return NAVIGATION_TYPE_NAV_IGNORE; | |
1121 } | |
1122 } | |
1123 | |
1124 if (params.nav_entry_id == 0) { | |
1125 // This is a renderer-initiated navigation (nav_entry_id == 0), but didn't | |
1126 // create a new page. | |
1127 | |
1128 // Just like above in the did_create_new_entry case, it's possible to | |
1129 // scribble onto an uncommitted page. Again, there isn't any navigation | |
1130 // stuff that we can do, so ignore it here as well. | |
1131 if (!GetLastCommittedEntry()) | |
1132 return NAVIGATION_TYPE_NAV_IGNORE; | |
1133 | |
1134 if (params.was_within_same_page) { | |
1135 // This is history.replaceState(), which is renderer-initiated yet within | |
1136 // the same page. | |
1137 return NAVIGATION_TYPE_IN_PAGE; | |
1138 } else { | |
1139 // This is history.reload() or a client-side redirect. | |
1140 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1141 } | |
1142 } | |
1143 | |
1144 if (pending_entry_ && pending_entry_index_ == -1 && | |
1145 pending_entry_->GetUniqueID() == params.nav_entry_id) { | |
1146 // In this case, we have a pending entry for a load of a new URL but Blink | |
1147 // didn't do a new navigation (params.did_create_new_entry). This happens | |
1148 // when you press enter in the URL bar to reload. We will create a pending | |
1149 // entry, but Blink will convert it to a reload since it's the same page and | |
1150 // not create a new entry for it (the user doesn't want to have a new | |
1151 // back/forward entry when they do this). Therefore we want to just ignore | |
1152 // the pending entry and go back to where we were (the "existing entry"). | |
1153 return NAVIGATION_TYPE_SAME_PAGE; | |
1154 } | |
1155 | |
1156 if (params.intended_as_new_entry) { | |
1157 // This was intended to be a navigation to a new entry but the pending entry | |
1158 // got cleared in the meanwhile. Classify as EXISTING_PAGE because we may or | |
1159 // may not have a pending entry. | |
1160 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1161 } | |
1162 | |
1163 if (params.url_is_unreachable && failed_pending_entry_id_ != 0 && | |
1164 params.nav_entry_id == failed_pending_entry_id_) { | |
1165 // If the renderer was going to a new pending entry that got cleared because | |
1166 // of an error, this is the case of the user trying to retry a failed load | |
1167 // by pressing return. Classify as EXISTING_PAGE because we probably don't | |
1168 // have a pending entry. | |
1169 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1170 } | |
1171 | |
1172 // Now we know that the notification is for an existing page. Find that entry. | |
1173 int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id); | |
1174 if (existing_entry_index == -1) { | |
1175 // The page was not found. It could have been pruned because of the limit on | |
1176 // back/forward entries (not likely since we'll usually tell it to navigate | |
1177 // to such entries). It could also mean that the renderer is smoking crack. | |
1178 // TODO(avi): Crash the renderer like we do in the old ClassifyNavigation? | |
1179 NOTREACHED() << "Could not find nav entry with id " << params.nav_entry_id; | |
1180 return NAVIGATION_TYPE_NAV_IGNORE; | |
1181 } | |
1182 | |
1183 // Any top-level navigations with the same base (minus the reference fragment) | |
1184 // are in-page navigations. (We weeded out subframe navigations above.) Most | |
1185 // of the time this doesn't matter since Blink doesn't tell us about subframe | |
1186 // navigations that don't actually navigate, but it can happen when there is | |
1187 // an encoding override (it always sends a navigation request). | |
1188 NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get(); | |
1189 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, | |
1190 params.was_within_same_page, rfh)) { | |
1191 return NAVIGATION_TYPE_IN_PAGE; | |
1192 } | 1059 } |
1193 | 1060 |
1194 // Since we weeded out "new" navigations above, we know this is an existing | 1061 // Since we weeded out "new" navigations above, we know this is an existing |
1195 // (back/forward) navigation. | 1062 // (back/forward) navigation. |
1196 return NAVIGATION_TYPE_EXISTING_PAGE; | 1063 return NAVIGATION_TYPE_EXISTING_PAGE; |
1197 } | 1064 } |
1198 | 1065 |
1199 void NavigationControllerImpl::RendererDidNavigateToNewPage( | 1066 void NavigationControllerImpl::RendererDidNavigateToNewPage( |
1200 RenderFrameHostImpl* rfh, | 1067 RenderFrameHostImpl* rfh, |
1201 const FrameHostMsg_DidCommitProvisionalLoad_Params& params, | 1068 const FrameHostMsg_DidCommitProvisionalLoad_Params& params, |
(...skipping 755 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1957 int NavigationControllerImpl::GetEntryIndexWithPageID( | 1824 int NavigationControllerImpl::GetEntryIndexWithPageID( |
1958 SiteInstance* instance, int32 page_id) const { | 1825 SiteInstance* instance, int32 page_id) const { |
1959 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { | 1826 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { |
1960 if ((entries_[i]->site_instance() == instance) && | 1827 if ((entries_[i]->site_instance() == instance) && |
1961 (entries_[i]->GetPageID() == page_id)) | 1828 (entries_[i]->GetPageID() == page_id)) |
1962 return i; | 1829 return i; |
1963 } | 1830 } |
1964 return -1; | 1831 return -1; |
1965 } | 1832 } |
1966 | 1833 |
1967 int NavigationControllerImpl::GetEntryIndexWithUniqueID( | |
1968 int nav_entry_id) const { | |
1969 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { | |
1970 if (entries_[i]->GetUniqueID() == nav_entry_id) | |
1971 return i; | |
1972 } | |
1973 return -1; | |
1974 } | |
1975 | |
1976 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { | 1834 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { |
1977 if (transient_entry_index_ == -1) | 1835 if (transient_entry_index_ == -1) |
1978 return NULL; | 1836 return NULL; |
1979 return entries_[transient_entry_index_].get(); | 1837 return entries_[transient_entry_index_].get(); |
1980 } | 1838 } |
1981 | 1839 |
1982 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) { | 1840 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) { |
1983 // Discard any current transient entry, we can only have one at a time. | 1841 // Discard any current transient entry, we can only have one at a time. |
1984 int index = 0; | 1842 int index = 0; |
1985 if (last_committed_entry_index_ != -1) | 1843 if (last_committed_entry_index_ != -1) |
(...skipping 23 matching lines...) Expand all Loading... |
2009 } | 1867 } |
2010 } | 1868 } |
2011 } | 1869 } |
2012 | 1870 |
2013 void NavigationControllerImpl::SetGetTimestampCallbackForTest( | 1871 void NavigationControllerImpl::SetGetTimestampCallbackForTest( |
2014 const base::Callback<base::Time()>& get_timestamp_callback) { | 1872 const base::Callback<base::Time()>& get_timestamp_callback) { |
2015 get_timestamp_callback_ = get_timestamp_callback; | 1873 get_timestamp_callback_ = get_timestamp_callback; |
2016 } | 1874 } |
2017 | 1875 |
2018 } // namespace content | 1876 } // namespace content |
OLD | NEW |