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 783 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
794 // If we are doing a cross-site reload, we need to replace the existing | 794 // If we are doing a cross-site reload, we need to replace the existing |
795 // navigation entry, not add another entry to the history. This has the side | 795 // navigation entry, not add another entry to the history. This has the side |
796 // effect of removing forward browsing history, if such existed. | 796 // effect of removing forward browsing history, if such existed. |
797 // Or if we are doing a cross-site redirect navigation, | 797 // Or if we are doing a cross-site redirect navigation, |
798 // we will do a similar thing. | 798 // we will do a similar thing. |
799 details->did_replace_entry = | 799 details->did_replace_entry = |
800 pending_entry_ && pending_entry_->should_replace_entry(); | 800 pending_entry_ && pending_entry_->should_replace_entry(); |
801 | 801 |
802 // Do navigation-type specific actions. These will make and commit an entry. | 802 // Do navigation-type specific actions. These will make and commit an entry. |
803 details->type = ClassifyNavigation(rfh, params); | 803 details->type = ClassifyNavigation(rfh, params); |
804 DCHECK_EQ(details->type, ClassifyNavigationWithoutPageID(rfh, params)); | |
804 | 805 |
805 // is_in_page must be computed before the entry gets committed. | 806 // is_in_page must be computed before the entry gets committed. |
806 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), | 807 details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(), |
807 params.url, params.was_within_same_page, rfh); | 808 params.url, params.was_within_same_page, rfh); |
808 | 809 |
809 switch (details->type) { | 810 switch (details->type) { |
810 case NAVIGATION_TYPE_NEW_PAGE: | 811 case NAVIGATION_TYPE_NEW_PAGE: |
811 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); | 812 RendererDidNavigateToNewPage(rfh, params, details->did_replace_entry); |
812 break; | 813 break; |
813 case NAVIGATION_TYPE_EXISTING_PAGE: | 814 case NAVIGATION_TYPE_EXISTING_PAGE: |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1031 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, | 1032 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, |
1032 params.was_within_same_page, rfh)) { | 1033 params.was_within_same_page, rfh)) { |
1033 return NAVIGATION_TYPE_IN_PAGE; | 1034 return NAVIGATION_TYPE_IN_PAGE; |
1034 } | 1035 } |
1035 | 1036 |
1036 // Since we weeded out "new" navigations above, we know this is an existing | 1037 // Since we weeded out "new" navigations above, we know this is an existing |
1037 // (back/forward) navigation. | 1038 // (back/forward) navigation. |
1038 return NAVIGATION_TYPE_EXISTING_PAGE; | 1039 return NAVIGATION_TYPE_EXISTING_PAGE; |
1039 } | 1040 } |
1040 | 1041 |
1042 NavigationType NavigationControllerImpl::ClassifyNavigationWithoutPageID( | |
1043 RenderFrameHostImpl* rfh, | |
1044 const FrameHostMsg_DidCommitProvisionalLoad_Params& params) const { | |
1045 if (params.commit_type == blink::WebStandardCommit) { | |
1046 // Standard commits are new pages. We may or may not have a pending entry | |
1047 // for the page, and this may or may not be the main frame. | |
1048 if (!rfh->GetParent()) { | |
1049 // TODO(avi): Everyone does ui::PageTransitionIsMainFrame to determine | |
1050 // main-frame-ness. I can get that consumers of page transitions would | |
1051 // want to do that, but for code inside RenderFrameHost and NavController? | |
1052 // Please. | |
1053 return NAVIGATION_TYPE_NEW_PAGE; | |
1054 } | |
1055 | |
1056 // When this is a new subframe navigation, we should have a committed page | |
1057 // in which it's a subframe. This may not be the case when an iframe is | |
1058 // navigated on a popup navigated to about:blank (the iframe would be | |
1059 // written into the popup by script on the main page). For these cases, | |
1060 // there isn't any navigation stuff we can do, so just ignore it. | |
1061 if (!GetLastCommittedEntry()) | |
1062 return NAVIGATION_TYPE_NAV_IGNORE; | |
1063 | |
1064 // Valid subframe navigation. | |
1065 return NAVIGATION_TYPE_NEW_SUBFRAME; | |
1066 } | |
1067 | |
1068 // We only clear the session history when navigating to a new page. | |
1069 DCHECK(!params.history_list_was_cleared); | |
1070 | |
1071 if (rfh->GetParent()) { | |
1072 // All manual subframes would be WebStandardCommit and handled above, so we | |
1073 // know this is auto. | |
1074 DCHECK(GetLastCommittedEntry()); | |
1075 return NAVIGATION_TYPE_AUTO_SUBFRAME; | |
1076 } | |
1077 | |
1078 if (params.nav_entry_id == 0) { | |
1079 // This is a renderer-initiated navigation, but didn't create a new page. | |
1080 // This must be an inert commit (standard commits are handled above, | |
Charlie Reis
2015/03/12 18:28:17
Can you explain what inert commit means? That's a
Avi (use Gerrit)
2015/03/12 19:21:17
https://code.google.com/p/chromium/codesearch#chro
| |
1081 // back/forward commits are always browser-initiated, and initial child | |
Charlie Reis
2015/03/12 18:28:17
Minor wording issue, though I'm not sure if it cha
Avi (use Gerrit)
2015/03/12 19:21:17
That doesn't change the code.
Because the request
| |
1082 // frame commits are only seen with subframes, also handled above). | |
1083 DCHECK_EQ(blink::WebHistoryInertCommit, params.commit_type); | |
1084 if (params.was_within_same_page) { | |
1085 // This is history.replaceState(), which is renderer-initiated yet within | |
1086 // the same page. | |
1087 return NAVIGATION_TYPE_IN_PAGE; | |
1088 } else { | |
1089 // This is history.reload() and client-side redirection. | |
1090 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1091 } | |
1092 } | |
1093 | |
1094 if (pending_entry_ && pending_entry_index_ == -1 && | |
1095 pending_entry_->GetUniqueID() == params.nav_entry_id) { | |
1096 DCHECK_EQ(blink::WebHistoryInertCommit, params.commit_type); | |
1097 // In this case, we have a pending entry for a load of a new URL but Blink | |
1098 // didn't do a new navigation (aka WebStandardCommit). This happens when you | |
1099 // press enter in the URL bar to reload. We will create a pending entry, but | |
1100 // Blink will convert it to a reload since it's the same page and not create | |
1101 // a new entry for it (the user doesn't want to have a new back/forward | |
1102 // entry when they do this). Therefore we want to just ignore the pending | |
1103 // entry and go back to where we were (the "existing entry"). | |
1104 return NAVIGATION_TYPE_SAME_PAGE; | |
1105 } | |
1106 | |
1107 // Now we know that the notification is for an existing page. Find that entry. | |
1108 int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id); | |
1109 if (existing_entry_index == -1) { | |
1110 // The page was not found. It could have been pruned because of the limit on | |
1111 // back/forward entries (not likely since we'll usually tell it to navigate | |
1112 // to such entries). It could also mean that the renderer is smoking crack. | |
1113 NOTREACHED() << "Could not find nav entry with id " << params.nav_entry_id; | |
1114 | |
1115 // Because the unknown entry has committed, we risk showing the wrong URL in | |
1116 // release builds. Instead, we'll kill the renderer process to be safe. | |
1117 LOG(ERROR) << "terminating renderer for bad navigation: " << params.url; | |
1118 RecordAction(base::UserMetricsAction("BadMessageTerminate_NC")); | |
Charlie Reis
2015/03/12 18:28:17
We probably don't want to kill the renderer in bot
Avi (use Gerrit)
2015/03/12 19:21:17
Done.
| |
1119 | |
1120 // Temporary code so we can get more information. Format: | |
1121 // http://url/foo.html#uniqueid5#frame1#ids2,3,4, | |
1122 std::string temp = params.url.spec(); | |
1123 temp.append("#uniqueid"); | |
1124 temp.append(base::IntToString(params.nav_entry_id)); | |
1125 temp.append("#frame"); | |
1126 temp.append(base::IntToString(rfh->GetRoutingID())); | |
1127 temp.append("#ids"); | |
1128 for (int i = 0; i < static_cast<int>(entries_.size()); ++i) { | |
1129 // Append entry metadata (e.g., 3): | |
1130 // 3: nav_entry_id | |
1131 temp.append(base::IntToString(entries_[i]->GetUniqueID())); | |
1132 temp.append(","); | |
1133 } | |
1134 GURL url(temp); | |
1135 rfh->render_view_host()->Send(new ViewMsg_TempCrashWithData(url)); | |
1136 return NAVIGATION_TYPE_NAV_IGNORE; | |
1137 } | |
1138 | |
1139 // Any top-level navigations with the same base (minus the reference fragment) | |
1140 // are in-page navigations. (We weeded out subframe navigations above.) Most | |
1141 // of the time this doesn't matter since Blink doesn't tell us about subframe | |
1142 // navigations that don't actually navigate, but it can happen when there is | |
1143 // an encoding override (it always sends a navigation request). | |
1144 NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get(); | |
1145 if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url, | |
1146 params.was_within_same_page, rfh)) { | |
1147 return NAVIGATION_TYPE_IN_PAGE; | |
1148 } | |
1149 | |
1150 // Since we weeded out "new" navigations above, we know this is an existing | |
1151 // (back/forward) navigation. | |
1152 return NAVIGATION_TYPE_EXISTING_PAGE; | |
1153 } | |
1154 | |
1041 void NavigationControllerImpl::RendererDidNavigateToNewPage( | 1155 void NavigationControllerImpl::RendererDidNavigateToNewPage( |
1042 RenderFrameHostImpl* rfh, | 1156 RenderFrameHostImpl* rfh, |
1043 const FrameHostMsg_DidCommitProvisionalLoad_Params& params, | 1157 const FrameHostMsg_DidCommitProvisionalLoad_Params& params, |
1044 bool replace_entry) { | 1158 bool replace_entry) { |
1045 NavigationEntryImpl* new_entry; | 1159 NavigationEntryImpl* new_entry; |
1046 bool update_virtual_url; | 1160 bool update_virtual_url; |
1047 // Only make a copy of the pending entry if it is appropriate for the new page | 1161 // Only make a copy of the pending entry if it is appropriate for the new page |
1048 // that was just loaded. We verify this at a coarse grain by checking that | 1162 // that was just loaded. We verify this at a coarse grain by checking that |
1049 // the SiteInstance hasn't been assigned to something else. | 1163 // the SiteInstance hasn't been assigned to something else. |
1050 if (pending_entry_ && | 1164 if (pending_entry_ && |
(...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1773 int NavigationControllerImpl::GetEntryIndexWithPageID( | 1887 int NavigationControllerImpl::GetEntryIndexWithPageID( |
1774 SiteInstance* instance, int32 page_id) const { | 1888 SiteInstance* instance, int32 page_id) const { |
1775 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { | 1889 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { |
1776 if ((entries_[i]->site_instance() == instance) && | 1890 if ((entries_[i]->site_instance() == instance) && |
1777 (entries_[i]->GetPageID() == page_id)) | 1891 (entries_[i]->GetPageID() == page_id)) |
1778 return i; | 1892 return i; |
1779 } | 1893 } |
1780 return -1; | 1894 return -1; |
1781 } | 1895 } |
1782 | 1896 |
1897 int NavigationControllerImpl::GetEntryIndexWithUniqueID( | |
1898 int nav_entry_id) const { | |
1899 for (int i = static_cast<int>(entries_.size()) - 1; i >= 0; --i) { | |
1900 if (entries_[i]->GetUniqueID() == nav_entry_id) | |
1901 return i; | |
1902 } | |
1903 return -1; | |
1904 } | |
1905 | |
1783 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { | 1906 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const { |
1784 if (transient_entry_index_ == -1) | 1907 if (transient_entry_index_ == -1) |
1785 return NULL; | 1908 return NULL; |
1786 return entries_[transient_entry_index_].get(); | 1909 return entries_[transient_entry_index_].get(); |
1787 } | 1910 } |
1788 | 1911 |
1789 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) { | 1912 void NavigationControllerImpl::SetTransientEntry(NavigationEntry* entry) { |
1790 // Discard any current transient entry, we can only have one at a time. | 1913 // Discard any current transient entry, we can only have one at a time. |
1791 int index = 0; | 1914 int index = 0; |
1792 if (last_committed_entry_index_ != -1) | 1915 if (last_committed_entry_index_ != -1) |
(...skipping 21 matching lines...) Expand all Loading... | |
1814 } | 1937 } |
1815 } | 1938 } |
1816 } | 1939 } |
1817 | 1940 |
1818 void NavigationControllerImpl::SetGetTimestampCallbackForTest( | 1941 void NavigationControllerImpl::SetGetTimestampCallbackForTest( |
1819 const base::Callback<base::Time()>& get_timestamp_callback) { | 1942 const base::Callback<base::Time()>& get_timestamp_callback) { |
1820 get_timestamp_callback_ = get_timestamp_callback; | 1943 get_timestamp_callback_ = get_timestamp_callback; |
1821 } | 1944 } |
1822 | 1945 |
1823 } // namespace content | 1946 } // namespace content |
OLD | NEW |