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

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

Issue 2380383004: Fix aborted navigates not clearing the pending navigation entry with PlzNavigate. (Closed)
Patch Set: more targeted fix without treating this as failednavigation Created 4 years, 2 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
« no previous file with comments | « content/browser/frame_host/navigator_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/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
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
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
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
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
OLDNEW
« no previous file with comments | « content/browser/frame_host/navigator_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698