| 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 |