| 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/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 | 197 |
| 198 // We used to cancel the pending renderer here for cross-site downloads. | 198 // We used to cancel the pending renderer here for cross-site downloads. |
| 199 // However, it's not safe to do that because the download logic repeatedly | 199 // However, it's not safe to do that because the download logic repeatedly |
| 200 // looks for this WebContents based on a render ID. Instead, we just | 200 // looks for this WebContents based on a render ID. Instead, we just |
| 201 // leave the pending renderer around until the next navigation event | 201 // leave the pending renderer around until the next navigation event |
| 202 // (Navigate, DidNavigate, etc), which will clean it up properly. | 202 // (Navigate, DidNavigate, etc), which will clean it up properly. |
| 203 // | 203 // |
| 204 // TODO(creis): Find a way to cancel any pending RFH here. | 204 // TODO(creis): Find a way to cancel any pending RFH here. |
| 205 } | 205 } |
| 206 | 206 |
| 207 // Racy conditions can cause a fail message to arrive after its corresponding | 207 DiscardPendingEntryOnFailureIfNeeded(render_frame_host->navigation_handle()); |
| 208 // pending entry has been replaced by another navigation. If | |
| 209 // |DiscardPendingEntry| is called in this case, then the completely valid | |
| 210 // entry for the new navigation would be discarded. See crbug.com/513742. To | |
| 211 // catch this case, the current pending entry is compared against the current | |
| 212 // navigation handle's entry id, which should correspond to the failed load. | |
| 213 NavigationHandleImpl* handle = render_frame_host->navigation_handle(); | |
| 214 NavigationEntry* pending_entry = controller_->GetPendingEntry(); | |
| 215 bool pending_matches_fail_msg = | |
| 216 handle && pending_entry && | |
| 217 handle->pending_nav_entry_id() == pending_entry->GetUniqueID(); | |
| 218 if (pending_matches_fail_msg) { | |
| 219 // We usually clear the pending entry when it fails, so that an arbitrary | |
| 220 // URL isn't left visible above a committed page. This must be enforced | |
| 221 // when the pending entry isn't visible (e.g., renderer-initiated | |
| 222 // navigations) to prevent URL spoofs for in-page navigations that don't go | |
| 223 // through DidStartProvisionalLoadForFrame. | |
| 224 // | |
| 225 // However, we do preserve the pending entry in some cases, such as on the | |
| 226 // initial navigation of an unmodified blank tab. We also allow the | |
| 227 // delegate to say when it's safe to leave aborted URLs in the omnibox, to | |
| 228 // let the user edit the URL and try again. This may be useful in cases | |
| 229 // that the committed page cannot be attacker-controlled. In these cases, | |
| 230 // we still allow the view to clear the pending entry and typed URL if the | |
| 231 // user requests (e.g., hitting Escape with focus in the address bar). | |
| 232 // | |
| 233 // Note: don't touch the transient entry, since an interstitial may exist. | |
| 234 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || | |
| 235 delegate_->ShouldPreserveAbortedURLs(); | |
| 236 if (pending_entry != controller_->GetVisibleEntry() || | |
| 237 !should_preserve_entry) { | |
| 238 controller_->DiscardPendingEntry(true); | |
| 239 | |
| 240 // Also force the UI to refresh. | |
| 241 controller_->delegate()->NotifyNavigationStateChanged( | |
| 242 INVALIDATE_TYPE_URL); | |
| 243 } | |
| 244 } | |
| 245 | 208 |
| 246 if (delegate_) | 209 if (delegate_) |
| 247 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); | 210 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); |
| 248 } | 211 } |
| 249 | 212 |
| 250 void NavigatorImpl::DidFailLoadWithError( | 213 void NavigatorImpl::DidFailLoadWithError( |
| 251 RenderFrameHostImpl* render_frame_host, | 214 RenderFrameHostImpl* render_frame_host, |
| 252 const GURL& url, | 215 const GURL& url, |
| 253 int error_code, | 216 int error_code, |
| 254 const base::string16& error_description, | 217 const base::string16& error_description, |
| (...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 | 873 |
| 911 // PlzNavigate | 874 // PlzNavigate |
| 912 void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node, | 875 void NavigatorImpl::FailedNavigation(FrameTreeNode* frame_tree_node, |
| 913 bool has_stale_copy_in_cache, | 876 bool has_stale_copy_in_cache, |
| 914 int error_code) { | 877 int error_code) { |
| 915 CHECK(IsBrowserSideNavigationEnabled()); | 878 CHECK(IsBrowserSideNavigationEnabled()); |
| 916 | 879 |
| 917 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 880 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
| 918 DCHECK(navigation_request); | 881 DCHECK(navigation_request); |
| 919 | 882 |
| 883 DiscardPendingEntryOnFailureIfNeeded(navigation_request->navigation_handle()); |
| 884 |
| 920 // If the request was canceled by the user do not show an error page. | 885 // If the request was canceled by the user do not show an error page. |
| 921 if (error_code == net::ERR_ABORTED) { | 886 if (error_code == net::ERR_ABORTED) { |
| 922 frame_tree_node->ResetNavigationRequest(false); | 887 frame_tree_node->ResetNavigationRequest(false); |
| 923 return; | 888 return; |
| 924 } | 889 } |
| 925 | 890 |
| 926 // Select an appropriate renderer to show the error page. | 891 // Select an appropriate renderer to show the error page. |
| 927 RenderFrameHostImpl* render_frame_host = | 892 RenderFrameHostImpl* render_frame_host = |
| 928 frame_tree_node->render_manager()->GetFrameHostForNavigation( | 893 frame_tree_node->render_manager()->GetFrameHostForNavigation( |
| 929 *navigation_request); | 894 *navigation_request); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1114 pending_entry->transferred_global_request_id()); | 1079 pending_entry->transferred_global_request_id()); |
| 1115 entry->set_should_replace_entry(pending_entry->should_replace_entry()); | 1080 entry->set_should_replace_entry(pending_entry->should_replace_entry()); |
| 1116 entry->SetRedirectChain(pending_entry->GetRedirectChain()); | 1081 entry->SetRedirectChain(pending_entry->GetRedirectChain()); |
| 1117 } | 1082 } |
| 1118 controller_->SetPendingEntry(std::move(entry)); | 1083 controller_->SetPendingEntry(std::move(entry)); |
| 1119 if (delegate_) | 1084 if (delegate_) |
| 1120 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); | 1085 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); |
| 1121 } | 1086 } |
| 1122 } | 1087 } |
| 1123 | 1088 |
| 1089 void NavigatorImpl::DiscardPendingEntryOnFailureIfNeeded( |
| 1090 NavigationHandleImpl* handle) { |
| 1091 // Racy conditions can cause a fail message to arrive after its corresponding |
| 1092 // pending entry has been replaced by another navigation. If |
| 1093 // |DiscardPendingEntry| is called in this case, then the completely valid |
| 1094 // entry for the new navigation would be discarded. See crbug.com/513742. To |
| 1095 // catch this case, the current pending entry is compared against the current |
| 1096 // navigation handle's entry id, which should correspond to the failed load. |
| 1097 NavigationEntry* pending_entry = controller_->GetPendingEntry(); |
| 1098 bool pending_matches_fail_msg = |
| 1099 handle && pending_entry && |
| 1100 handle->pending_nav_entry_id() == pending_entry->GetUniqueID(); |
| 1101 if (!pending_matches_fail_msg) |
| 1102 return; |
| 1103 |
| 1104 // We usually clear the pending entry when it fails, so that an arbitrary URL |
| 1105 // isn't left visible above a committed page. This must be enforced when the |
| 1106 // pending entry isn't visible (e.g., renderer-initiated navigations) to |
| 1107 // prevent URL spoofs for in-page navigations that don't go through |
| 1108 // DidStartProvisionalLoadForFrame. |
| 1109 // |
| 1110 // However, we do preserve the pending entry in some cases, such as on the |
| 1111 // initial navigation of an unmodified blank tab. We also allow the delegate |
| 1112 // to say when it's safe to leave aborted URLs in the omnibox, to let the |
| 1113 // user edit the URL and try again. This may be useful in cases that the |
| 1114 // committed page cannot be attacker-controlled. In these cases, we still |
| 1115 // allow the view to clear the pending entry and typed URL if the user |
| 1116 // requests (e.g., hitting Escape with focus in the address bar). |
| 1117 // |
| 1118 // Note: don't touch the transient entry, since an interstitial may exist. |
| 1119 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || |
| 1120 delegate_->ShouldPreserveAbortedURLs(); |
| 1121 if (pending_entry != controller_->GetVisibleEntry() || |
| 1122 !should_preserve_entry) { |
| 1123 controller_->DiscardPendingEntry(true); |
| 1124 |
| 1125 // Also force the UI to refresh. |
| 1126 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); |
| 1127 } |
| 1128 } |
| 1129 |
| 1124 } // namespace content | 1130 } // namespace content |
| OLD | NEW |