Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: content/browser/frame_host/navigator_impl.cc

Issue 1697563002: PlzNavigate: clear pending entry on aborted navigations (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698