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 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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |