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/navigator_impl.h" | 5 #include "content/browser/frame_host/navigator_impl.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 // We used to cancel the pending renderer here for cross-site downloads. | 238 // We used to cancel the pending renderer here for cross-site downloads. |
239 // However, it's not safe to do that because the download logic repeatedly | 239 // However, it's not safe to do that because the download logic repeatedly |
240 // looks for this WebContents based on a render ID. Instead, we just | 240 // looks for this WebContents based on a render ID. Instead, we just |
241 // leave the pending renderer around until the next navigation event | 241 // leave the pending renderer around until the next navigation event |
242 // (Navigate, DidNavigate, etc), which will clean it up properly. | 242 // (Navigate, DidNavigate, etc), which will clean it up properly. |
243 // | 243 // |
244 // TODO(creis): Find a way to cancel any pending RFH here. | 244 // TODO(creis): Find a way to cancel any pending RFH here. |
245 } | 245 } |
246 | 246 |
247 // Discard the pending navigation entry if needed. | 247 // Discard the pending navigation entry if needed. |
248 DiscardPendingEntryOnFailureIfNeeded(render_frame_host->navigation_handle()); | 248 DiscardPendingEntryIfNeeded(render_frame_host->navigation_handle()); |
249 | 249 |
250 if (delegate_) { | 250 if (delegate_) { |
251 delegate_->DidFailProvisionalLoadWithError( | 251 delegate_->DidFailProvisionalLoadWithError( |
252 render_frame_host, validated_url, params.error_code, | 252 render_frame_host, validated_url, params.error_code, |
253 params.error_description, params.was_ignored_by_handler); | 253 params.error_description, params.was_ignored_by_handler); |
254 } | 254 } |
255 } | 255 } |
256 | 256 |
257 void NavigatorImpl::DidFailLoadWithError( | 257 void NavigatorImpl::DidFailLoadWithError( |
258 RenderFrameHostImpl* render_frame_host, | 258 RenderFrameHostImpl* render_frame_host, |
(...skipping 685 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
944 | 944 |
945 // PlzNavigate | 945 // PlzNavigate |
946 void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node, | 946 void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node, |
947 bool has_stale_copy_in_cache, | 947 bool has_stale_copy_in_cache, |
948 int error_code) { | 948 int error_code) { |
949 CHECK(IsBrowserSideNavigationEnabled()); | 949 CHECK(IsBrowserSideNavigationEnabled()); |
950 | 950 |
951 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 951 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
952 DCHECK(navigation_request); | 952 DCHECK(navigation_request); |
953 | 953 |
954 DiscardPendingEntryOnFailureIfNeeded(navigation_request->navigation_handle()); | 954 DiscardPendingEntryIfNeeded(navigation_request->navigation_handle()); |
955 | 955 |
956 // If the request was canceled by the user do not show an error page. | 956 // If the request was canceled by the user do not show an error page. |
957 if (error_code == net::ERR_ABORTED) { | 957 if (error_code == net::ERR_ABORTED) { |
958 frame_tree_node->ResetNavigationRequest(false); | 958 frame_tree_node->ResetNavigationRequest(false); |
959 return; | 959 return; |
960 } | 960 } |
961 | 961 |
962 // Select an appropriate renderer to show the error page. | 962 // Select an appropriate renderer to show the error page. |
963 RenderFrameHostImpl* render_frame_host = | 963 RenderFrameHostImpl* render_frame_host = |
964 frame_tree_node->render_manager()->GetFrameHostForNavigation( | 964 frame_tree_node->render_manager()->GetFrameHostForNavigation( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1002 navigation_data_->before_unload_delay_ = | 1002 navigation_data_->before_unload_delay_ = |
1003 renderer_before_unload_end_time - renderer_before_unload_start_time; | 1003 renderer_before_unload_end_time - renderer_before_unload_start_time; |
1004 } | 1004 } |
1005 } | 1005 } |
1006 | 1006 |
1007 NavigationHandleImpl* NavigatorImpl::GetNavigationHandleForFrameHost( | 1007 NavigationHandleImpl* NavigatorImpl::GetNavigationHandleForFrameHost( |
1008 RenderFrameHostImpl* render_frame_host) { | 1008 RenderFrameHostImpl* render_frame_host) { |
1009 return render_frame_host->navigation_handle(); | 1009 return render_frame_host->navigation_handle(); |
1010 } | 1010 } |
1011 | 1011 |
| 1012 void NavigatorImpl::DiscardPendingEntryIfNeeded(NavigationHandleImpl* handle) { |
| 1013 // Racy conditions can cause a fail message to arrive after its corresponding |
| 1014 // pending entry has been replaced by another navigation. If |
| 1015 // |DiscardPendingEntry| is called in this case, then the completely valid |
| 1016 // entry for the new navigation would be discarded. See crbug.com/513742. To |
| 1017 // catch this case, the current pending entry is compared against the current |
| 1018 // navigation handle's entry id, which should correspond to the failed load. |
| 1019 NavigationEntry* pending_entry = controller_->GetPendingEntry(); |
| 1020 bool pending_matches_fail_msg = |
| 1021 handle && pending_entry && |
| 1022 handle->pending_nav_entry_id() == pending_entry->GetUniqueID(); |
| 1023 if (!pending_matches_fail_msg) |
| 1024 return; |
| 1025 |
| 1026 // We usually clear the pending entry when it fails, so that an arbitrary URL |
| 1027 // isn't left visible above a committed page. This must be enforced when the |
| 1028 // pending entry isn't visible (e.g., renderer-initiated navigations) to |
| 1029 // prevent URL spoofs for in-page navigations that don't go through |
| 1030 // DidStartProvisionalLoadForFrame. |
| 1031 // |
| 1032 // However, we do preserve the pending entry in some cases, such as on the |
| 1033 // initial navigation of an unmodified blank tab. We also allow the delegate |
| 1034 // to say when it's safe to leave aborted URLs in the omnibox, to let the |
| 1035 // user edit the URL and try again. This may be useful in cases that the |
| 1036 // committed page cannot be attacker-controlled. In these cases, we still |
| 1037 // allow the view to clear the pending entry and typed URL if the user |
| 1038 // requests (e.g., hitting Escape with focus in the address bar). |
| 1039 // |
| 1040 // Note: don't touch the transient entry, since an interstitial may exist. |
| 1041 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || |
| 1042 delegate_->ShouldPreserveAbortedURLs(); |
| 1043 if (pending_entry != controller_->GetVisibleEntry() || |
| 1044 !should_preserve_entry) { |
| 1045 controller_->DiscardPendingEntry(true); |
| 1046 |
| 1047 // Also force the UI to refresh. |
| 1048 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); |
| 1049 } |
| 1050 } |
| 1051 |
1012 // PlzNavigate | 1052 // PlzNavigate |
1013 void NavigatorImpl::RequestNavigation(FrameTreeNode* frame_tree_node, | 1053 void NavigatorImpl::RequestNavigation(FrameTreeNode* frame_tree_node, |
1014 const GURL& dest_url, | 1054 const GURL& dest_url, |
1015 const Referrer& dest_referrer, | 1055 const Referrer& dest_referrer, |
1016 const FrameNavigationEntry& frame_entry, | 1056 const FrameNavigationEntry& frame_entry, |
1017 const NavigationEntryImpl& entry, | 1057 const NavigationEntryImpl& entry, |
1018 ReloadType reload_type, | 1058 ReloadType reload_type, |
1019 LoFiState lofi_state, | 1059 LoFiState lofi_state, |
1020 bool is_same_document_history_load, | 1060 bool is_same_document_history_load, |
1021 bool is_history_navigation_in_new_child, | 1061 bool is_history_navigation_in_new_child, |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1162 // PlzNavigate. | 1202 // PlzNavigate. |
1163 if (navigation_handle) | 1203 if (navigation_handle) |
1164 navigation_handle->update_entry_id_for_transfer(entry->GetUniqueID()); | 1204 navigation_handle->update_entry_id_for_transfer(entry->GetUniqueID()); |
1165 | 1205 |
1166 controller_->SetPendingEntry(std::move(entry)); | 1206 controller_->SetPendingEntry(std::move(entry)); |
1167 if (delegate_) | 1207 if (delegate_) |
1168 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); | 1208 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); |
1169 } | 1209 } |
1170 } | 1210 } |
1171 | 1211 |
1172 void NavigatorImpl::DiscardPendingEntryOnFailureIfNeeded( | |
1173 NavigationHandleImpl* handle) { | |
1174 // Racy conditions can cause a fail message to arrive after its corresponding | |
1175 // pending entry has been replaced by another navigation. If | |
1176 // |DiscardPendingEntry| is called in this case, then the completely valid | |
1177 // entry for the new navigation would be discarded. See crbug.com/513742. To | |
1178 // catch this case, the current pending entry is compared against the current | |
1179 // navigation handle's entry id, which should correspond to the failed load. | |
1180 NavigationEntry* pending_entry = controller_->GetPendingEntry(); | |
1181 bool pending_matches_fail_msg = | |
1182 handle && pending_entry && | |
1183 handle->pending_nav_entry_id() == pending_entry->GetUniqueID(); | |
1184 if (!pending_matches_fail_msg) | |
1185 return; | |
1186 | |
1187 // We usually clear the pending entry when it fails, so that an arbitrary URL | |
1188 // isn't left visible above a committed page. This must be enforced when the | |
1189 // pending entry isn't visible (e.g., renderer-initiated navigations) to | |
1190 // prevent URL spoofs for in-page navigations that don't go through | |
1191 // DidStartProvisionalLoadForFrame. | |
1192 // | |
1193 // However, we do preserve the pending entry in some cases, such as on the | |
1194 // initial navigation of an unmodified blank tab. We also allow the delegate | |
1195 // to say when it's safe to leave aborted URLs in the omnibox, to let the | |
1196 // user edit the URL and try again. This may be useful in cases that the | |
1197 // committed page cannot be attacker-controlled. In these cases, we still | |
1198 // allow the view to clear the pending entry and typed URL if the user | |
1199 // requests (e.g., hitting Escape with focus in the address bar). | |
1200 // | |
1201 // Note: don't touch the transient entry, since an interstitial may exist. | |
1202 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || | |
1203 delegate_->ShouldPreserveAbortedURLs(); | |
1204 if (pending_entry != controller_->GetVisibleEntry() || | |
1205 !should_preserve_entry) { | |
1206 controller_->DiscardPendingEntry(true); | |
1207 | |
1208 // Also force the UI to refresh. | |
1209 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); | |
1210 } | |
1211 } | |
1212 | |
1213 } // namespace content | 1212 } // namespace content |
OLD | NEW |