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 794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
805 // when we got the notice of the load failure. If so, look at the copy of the | 805 // when we got the notice of the load failure. If so, look at the copy of the |
806 // pending parameters that were saved. | 806 // pending parameters that were saved. |
807 if (params.url_is_unreachable && failed_pending_entry_id_ != 0) { | 807 if (params.url_is_unreachable && failed_pending_entry_id_ != 0) { |
808 details->did_replace_entry = failed_pending_entry_should_replace_; | 808 details->did_replace_entry = failed_pending_entry_should_replace_; |
809 } else { | 809 } else { |
810 details->did_replace_entry = pending_entry_ && | 810 details->did_replace_entry = pending_entry_ && |
811 pending_entry_->should_replace_entry(); | 811 pending_entry_->should_replace_entry(); |
812 } | 812 } |
813 | 813 |
814 // Do navigation-type specific actions. These will make and commit an entry. | 814 // Do navigation-type specific actions. These will make and commit an entry. |
815 details->type = ClassifyNavigation(rfh, params); | 815 details->type = ClassifyNavigation(rfh, params); |
clamy
2015/04/10 12:05:44
With PlzNavigate enabled, ClassifyNavigation fails
Avi (use Gerrit)
2015/04/13 22:42:48
My current plan is to commit this with the DCHECK
clamy
2015/04/14 15:44:47
Acknowledged.
| |
816 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( | |
817 switches::kSitePerProcess)) { | |
818 // For site-per-process, both ClassifyNavigation methods get it wrong (see | |
819 // http://crbug.com/464014) so don't worry about a mismatch if that's the | |
820 // case. | |
821 DCHECK_EQ(details->type, ClassifyNavigationWithoutPageID(rfh, params)); | |
822 } | |
816 | 823 |
817 // is_in_page must be computed before the entry gets committed. | 824 // is_in_page must be computed before the entry gets committed. |
818 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), | 825 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), |
819 params.url, params.was_within_same_page, rfh); | 826 params.url, params.was_within_same_page, rfh); |
820 | 827 |
821 switch (details->type) { | 828 switch (details->type) { |
822 case NAVIGATION_TYPE_NEW_PAGE: | 829 case NAVIGATION_TYPE_NEW_PAGE: |
823 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); | 830 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); |
824 break; | 831 break; |
825 case NAVIGATION_TYPE_EXISTING_PAGE: | 832 case NAVIGATION_TYPE_EXISTING_PAGE: |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
905 details->http_status_code = params.http_status_code; | 912 details->http_status_code = params.http_status_code; |
906 NotifyNavigationEntryCommitted(details); | 913 NotifyNavigationEntryCommitted(details); |
907 | 914 |
908 return true; | 915 return true; |
909 } | 916 } |
910 | 917 |
911 NavigationType NavigationControllerImpl::ClassifyNavigation( | 918 NavigationType NavigationControllerImpl::ClassifyNavigation( |
912 RenderFrameHostImpl* rfh, | 919 RenderFrameHostImpl* rfh, |
913 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { | 920 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { |
914 if (params.page_id == -1) { | 921 if (params.page_id == -1) { |
915 // TODO(nasko, creis): An out-of-process child frame has no way of | 922 // TODO(nasko, creis): An out-of-process child frame has no way of knowing |
916 // knowing the page_id of its parent, so it is passing back -1. The | 923 // the page_id of its parent, so it is passing back -1. The semantics here |
917 // semantics here should be re-evaluated during session history refactor | 924 // should be re-evaluated during session history refactor (see |
918 // (see http://crbug.com/236848). For now, we assume this means the | 925 // http://crbug.com/236848 and in particular http://crbug.com/464014). For |
919 // child frame loaded and proceed. Note that this may do the wrong thing | 926 // now, we assume this means the child frame loaded and proceed. Note that |
920 // for cross-process AUTO_SUBFRAME navigations. | 927 // this may do the wrong thing for cross-process AUTO_SUBFRAME navigations. |
921 if (rfh->IsCrossProcessSubframe()) | 928 if (rfh->IsCrossProcessSubframe()) |
922 return NAVIGATION_TYPE_NEW_SUBFRAME; | 929 return NAVIGATION_TYPE_NEW_SUBFRAME; |
923 | 930 |
924 // The renderer generates the page IDs, and so if it gives us the invalid | 931 // The renderer generates the page IDs, and so if it gives us the invalid |
925 // page ID (-1) we know it didn't actually navigate. This happens in a few | 932 // page ID (-1) we know it didn't actually navigate. This happens in a few |
926 // cases: | 933 // cases: |
927 // | 934 // |
928 // - If a page makes a popup navigated to about blank, and then writes | 935 // - If a page makes a popup navigated to about blank, and then writes |
929 // stuff like a subframe navigated to a real page. We'll get the commit | 936 // stuff like a subframe navigated to a real page. We'll get the commit |
930 // for the subframe, but there won't be any commit for the outer page. | 937 // for the subframe, but there won't be any commit for the outer page. |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1018 DCHECK(GetLastCommittedEntry()); | 1025 DCHECK(GetLastCommittedEntry()); |
1019 return NAVIGATION_TYPE_AUTO_SUBFRAME; | 1026 return NAVIGATION_TYPE_AUTO_SUBFRAME; |
1020 } | 1027 } |
1021 | 1028 |
1022 // Anything below here we know is a main frame navigation. | 1029 // Anything below here we know is a main frame navigation. |
1023 if (pending_entry_ && | 1030 if (pending_entry_ && |
1024 !pending_entry_->is_renderer_initiated() && | 1031 !pending_entry_->is_renderer_initiated() && |
1025 existing_entry != pending_entry_ && | 1032 existing_entry != pending_entry_ && |
1026 pending_entry_->GetPageID() == -1 && | 1033 pending_entry_->GetPageID() == -1 && |
1027 existing_entry == GetLastCommittedEntry()) { | 1034 existing_entry == GetLastCommittedEntry()) { |
1028 // In this case, we have a pending entry for a URL but WebCore didn't do a | 1035 const std::vector<GURL>& existing_redirect_chain = |
1029 // new navigation. This happens when you press enter in the URL bar to | 1036 existing_entry->GetRedirectChain(); |
1030 // reload. We will create a pending entry, but WebKit will convert it to | 1037 |
1031 // a reload since it's the same page and not create a new entry for it | 1038 if (existing_entry->GetURL() == pending_entry_->GetURL() || |
1032 // (the user doesn't want to have a new back/forward entry when they do | 1039 (existing_redirect_chain.size() && |
1033 // this). If this matches the last committed entry, we want to just ignore | 1040 existing_redirect_chain[0] == pending_entry_->GetURL()) || |
1034 // the pending entry and go back to where we were (the "existing entry"). | 1041 existing_entry->GetURL() == pending_entry_->GetVirtualURL()) { |
Charlie Reis
2015/04/10 23:54:21
We probably shouldn't be changing ClassifyNavigati
Avi (use Gerrit)
2015/04/13 22:42:48
https://codereview.chromium.org/1082083002
It sho
| |
1035 return NAVIGATION_TYPE_SAME_PAGE; | 1042 // In this case, we have a pending entry for a URL but WebCore didn't do a |
1043 // new navigation. This happens when you press enter in the URL bar to | |
1044 // reload. We will create a pending entry, but WebKit will convert it to | |
1045 // a reload since it's the same page and not create a new entry for it | |
1046 // (the user doesn't want to have a new back/forward entry when they do | |
1047 // this). If this matches the last committed entry, we want to just ignore | |
1048 // the pending entry and go back to where we were (the "existing entry"). | |
1049 return NAVIGATION_TYPE_SAME_PAGE; | |
1050 } | |
1036 } | 1051 } |
1037 | 1052 |
1038 // Any toplevel navigations with the same base (minus the reference fragment) | 1053 // Any toplevel navigations with the same base (minus the reference fragment) |
1039 // are in-page navigations. We weeded out subframe navigations above. Most of | 1054 // are in-page navigations. We weeded out subframe navigations above. Most of |
1040 // the time this doesn't matter since WebKit doesn't tell us about subframe | 1055 // the time this doesn't matter since WebKit doesn't tell us about subframe |
1041 // navigations that don't actually navigate, but it can happen when there is | 1056 // navigations that don't actually navigate, but it can happen when there is |
1042 // an encoding override (it always sends a navigation request). | 1057 // an encoding override (it always sends a navigation request). |
1043 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, | 1058 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, |
1044 params.was_within_same_page, rfh)) { | 1059 params.was_within_same_page, rfh)) { |
1045 return NAVIGATION_TYPE_IN_PAGE; | 1060 return NAVIGATION_TYPE_IN_PAGE; |
1046 } | 1061 } |
1047 | 1062 |
1048 // Since we weeded out "new" navigations above, we know this is an existing | 1063 // Since we weeded out "new" navigations above, we know this is an existing |
1049 // (back/forward) navigation. | 1064 // (back/forward) navigation. |
1050 return NAVIGATION_TYPE_EXISTING_PAGE; | 1065 return NAVIGATION_TYPE_EXISTING_PAGE; |
1051 } | 1066 } |
1052 | 1067 |
1068 NavigationType NavigationControllerImpl::ClassifyNavigationWithoutPageID( | |
1069 RenderFrameHostImpl* rfh, | |
1070 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { | |
1071 if (params.did_create_new_entry) { | |
1072 // A new entry. We may or may not have a pending entry for the page, and | |
1073 // this may or may not be the main frame. | |
1074 if (ui::PageTransitionIsMainFrame(params.transition)) { | |
1075 // TODO(avi): I want to use |if (!rfh->GetParent())| here but lots of unit | |
1076 // tests fake auto subframe commits by sending the main frame a | |
1077 // PAGE_TRANSITION_AUTO_SUBFRAME transition. Fix those, and adjust here. | |
Charlie Reis
2015/04/10 23:54:20
I like this plan.
Avi (use Gerrit)
2015/04/13 22:42:48
Acknowledged.
PageTransitionIsMainFrame is used i
| |
1078 return NAVIGATION_TYPE_NEW_PAGE; | |
1079 } | |
1080 | |
1081 // When this is a new subframe navigation, we should have a committed page | |
1082 // in which it's a subframe. This may not be the case when an iframe is | |
1083 // navigated on a popup navigated to about:blank (the iframe would be | |
1084 // written into the popup by script on the main page). For these cases, | |
1085 // there isn't any navigation stuff we can do, so just ignore it. | |
1086 if (!GetLastCommittedEntry()) | |
1087 return NAVIGATION_TYPE_NAV_IGNORE; | |
1088 | |
1089 // Valid subframe navigation. | |
1090 return NAVIGATION_TYPE_NEW_SUBFRAME; | |
1091 } | |
1092 | |
1093 // We only clear the session history when navigating to a new page. | |
1094 DCHECK(!params.history_list_was_cleared); | |
1095 | |
1096 if (!ui::PageTransitionIsMainFrame(params.transition)) { | |
1097 // All manual subframes would be did_create_new_entry and handled above, so | |
1098 // we know this is auto. | |
1099 if (GetLastCommittedEntry()) { | |
1100 return NAVIGATION_TYPE_AUTO_SUBFRAME; | |
1101 } else { | |
1102 // We ignore subframes created in non-committed pages; we'd appreciate if | |
1103 // people stopped doing that. | |
1104 return NAVIGATION_TYPE_NAV_IGNORE; | |
1105 } | |
1106 } | |
1107 | |
1108 if (params.nav_entry_id == 0) { | |
Charlie Reis
2015/04/10 23:54:20
Can you add a comment saying what nav_entry_id ==
Avi (use Gerrit)
2015/04/13 22:42:48
Done.
| |
1109 // Just like above in the did_create_new_entry case, it's possible to | |
1110 // scribble onto an uncommitted page. Again, there isn't any navigation | |
1111 // stuff that we can do, so ignore it here as well. | |
1112 if (!GetLastCommittedEntry()) | |
1113 return NAVIGATION_TYPE_NAV_IGNORE; | |
1114 | |
1115 // This is a renderer-initiated navigation, but didn't create a new page. | |
1116 if (params.was_within_same_page) { | |
1117 // This is history.replaceState(), which is renderer-initiated yet within | |
1118 // the same page. | |
1119 return NAVIGATION_TYPE_IN_PAGE; | |
1120 } else { | |
1121 // This is history.reload() and client-side redirection. | |
1122 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1123 } | |
1124 } | |
1125 | |
1126 if (pending_entry_ && pending_entry_index_ == -1 && | |
1127 pending_entry_->GetUniqueID() == params.nav_entry_id) { | |
1128 // In this case, we have a pending entry for a load of a new URL but Blink | |
1129 // didn't do a new navigation (params.did_create_new_entry). This happens | |
1130 // when you press enter in the URL bar to reload. We will create a pending | |
1131 // entry, but Blink will convert it to a reload since it's the same page and | |
1132 // not create a new entry for it (the user doesn't want to have a new | |
1133 // back/forward entry when they do this). Therefore we want to just ignore | |
1134 // the pending entry and go back to where we were (the "existing entry"). | |
1135 return NAVIGATION_TYPE_SAME_PAGE; | |
1136 } | |
1137 | |
1138 if (params.url_is_unreachable && failed_pending_entry_id_ != 0 && | |
1139 params.nav_entry_id == failed_pending_entry_id_) { | |
1140 // If the renderer was going to a new pending entry that got cleared because | |
1141 // of an error, this is the case of the user trying to retry a failed load | |
1142 // by pressing return. | |
1143 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1144 } | |
1145 | |
1146 // Now we know that the notification is for an existing page. Find that entry. | |
1147 int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id); | |
1148 if (existing_entry_index == -1) { | |
1149 // The page was not found. It could have been pruned because of the limit on | |
1150 // back/forward entries (not likely since we'll usually tell it to navigate | |
1151 // to such entries). It could also mean that the renderer is smoking crack. | |
1152 // TODO(avi): Crash the renderer like we do in the old ClassifyNavigation? | |
1153 NOTREACHED() << "Could not find nav entry with id " << params.nav_entry_id; | |
1154 return NAVIGATION_TYPE_NAV_IGNORE; | |
1155 } | |
1156 | |
1157 // Any top-level navigations with the same base (minus the reference fragment) | |
1158 // are in-page navigations. (We weeded out subframe navigations above.) Most | |
1159 // of the time this doesn't matter since Blink doesn't tell us about subframe | |
1160 // navigations that don't actually navigate, but it can happen when there is | |
1161 // an encoding override (it always sends a navigation request). | |
1162 NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get(); | |
1163 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, | |
1164 params.was_within_same_page, rfh)) { | |
1165 return NAVIGATION_TYPE_IN_PAGE; | |
1166 } | |
1167 | |
1168 // Since we weeded out "new" navigations above, we know this is an existing | |
1169 // (back/forward) navigation. | |
1170 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1171 } | |
1172 | |
1053 void NavigationControllerImpl::RendererDidNavigateToNewPage( | 1173 void NavigationControllerImpl::RendererDidNavigateToNewPage( |
1054 RenderFrameHostImpl* rfh, | 1174 RenderFrameHostImpl* rfh, |
1055 const FrameHostMsg_DidCommitProvisionalLoad_Params& params, | 1175 const FrameHostMsg_DidCommitProvisionalLoad_Params& params, |
1056 bool replace_entry) { | 1176 bool replace_entry) { |
1057 NavigationEntryImpl* new_entry; | 1177 NavigationEntryImpl* new_entry; |
1058 bool update_virtual_url; | 1178 bool update_virtual_url; |
1059 // Only make a copy of the pending entry if it is appropriate for the new page | 1179 // Only make a copy of the pending entry if it is appropriate for the new page |
1060 // that was just loaded. We verify this at a coarse grain by checking that | 1180 // that was just loaded. We verify this at a coarse grain by checking that |
1061 // the SiteInstance hasn't been assigned to something else. | 1181 // the SiteInstance hasn't been assigned to something else. |
1062 if (pending_entry_ && | 1182 if (pending_entry_ && |
(...skipping 741 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1804 int NavigationControllerImpl::GetEntryIndexWithPageID( | 1924 int NavigationControllerImpl::GetEntryIndexWithPageID( |
1805 SiteInstance* instance, int32 page_id) const { | 1925 SiteInstance* instance, int32 page_id) const { |
1806 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { | 1926 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { |
1807 if ((entries_[i]->site_instance() == instance) && | 1927 if ((entries_[i]->site_instance() == instance) && |
1808 (entries_[i]->GetPageID() == page_id)) | 1928 (entries_[i]->GetPageID() == page_id)) |
1809 return i; | 1929 return i; |
1810 } | 1930 } |
1811 return -1; | 1931 return -1; |
1812 } | 1932 } |
1813 | 1933 |
1934 int NavigationControllerImpl::GetEntryIndexWithUniqueID( | |
1935 int nav_entry_id) const { | |
1936 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { | |
1937 if (entries_[i]->GetUniqueID() == nav_entry_id) | |
1938 return i; | |
1939 } | |
1940 return -1; | |
1941 } | |
1942 | |
1814 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { | 1943 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { |
1815 if (transient_entry_index_ == -1) | 1944 if (transient_entry_index_ == -1) |
1816 return NULL; | 1945 return NULL; |
1817 return entries_[transient_entry_index_].get(); | 1946 return entries_[transient_entry_index_].get(); |
1818 } | 1947 } |
1819 | 1948 |
1820 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) { | 1949 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) { |
1821 // Discard any current transient entry, we can only have one at a time. | 1950 // Discard any current transient entry, we can only have one at a time. |
1822 int index = 0; | 1951 int index = 0; |
1823 if (last_committed_entry_index_ != -1) | 1952 if (last_committed_entry_index_ != -1) |
(...skipping 23 matching lines...) Expand all Loading... | |
1847 } | 1976 } |
1848 } | 1977 } |
1849 } | 1978 } |
1850 | 1979 |
1851 void NavigationControllerImpl::SetGetTimestampCallbackForTest( | 1980 void NavigationControllerImpl::SetGetTimestampCallbackForTest( |
1852 const base::Callback<base::Time()>& get_timestamp_callback) { | 1981 const base::Callback<base::Time()>& get_timestamp_callback) { |
1853 get_timestamp_callback_ = get_timestamp_callback; | 1982 get_timestamp_callback_ = get_timestamp_callback; |
1854 } | 1983 } |
1855 | 1984 |
1856 } // namespace content | 1985 } // namespace content |
OLD | NEW |