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

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

Issue 1661423002: Solidify Entry discarding logic (NavigationHandle keeps its ID) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge @377292 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 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
144 render_frame_host->navigation_handle()->set_is_transferring(false); 144 render_frame_host->navigation_handle()->set_is_transferring(false);
145 return; 145 return;
146 } 146 }
147 147
148 // This ensures that notifications about the end of the previous 148 // This ensures that notifications about the end of the previous
149 // navigation are sent before notifications about the start of the 149 // navigation are sent before notifications about the start of the
150 // new navigation. 150 // new navigation.
151 render_frame_host->SetNavigationHandle(scoped_ptr<NavigationHandleImpl>()); 151 render_frame_host->SetNavigationHandle(scoped_ptr<NavigationHandleImpl>());
152 } 152 }
153 153
154 NavigationEntry* pending_entry = controller_->GetPendingEntry();
154 render_frame_host->SetNavigationHandle(NavigationHandleImpl::Create( 155 render_frame_host->SetNavigationHandle(NavigationHandleImpl::Create(
155 validated_url, render_frame_host->frame_tree_node(), 156 validated_url, render_frame_host->frame_tree_node(),
156 false, // is_synchronous 157 false, // is_synchronous
157 is_iframe_srcdoc, // is_srcdoc 158 is_iframe_srcdoc, // is_srcdoc
158 navigation_start)); 159 navigation_start, pending_entry ? pending_entry->GetUniqueID() : 0));
clamy 2016/02/26 14:08:13 Can the pending entry ever be null here except in
Charlie Harrison 2016/02/26 17:39:51 It can be null for subframes. Good catch.
159 } 160 }
160 161
161 void NavigatorImpl::DidFailProvisionalLoadWithError( 162 void NavigatorImpl::DidFailProvisionalLoadWithError(
162 RenderFrameHostImpl* render_frame_host, 163 RenderFrameHostImpl* render_frame_host,
163 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { 164 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) {
164 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec() 165 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec()
165 << ", error_code: " << params.error_code 166 << ", error_code: " << params.error_code
166 << ", error_description: " << params.error_description 167 << ", error_description: " << params.error_description
167 << ", showing_repost_interstitial: " << 168 << ", showing_repost_interstitial: " <<
168 params.showing_repost_interstitial 169 params.showing_repost_interstitial
(...skipping 19 matching lines...) Expand all
188 // commits of the interstitial page. 189 // commits of the interstitial page.
189 FrameTreeNode* root = 190 FrameTreeNode* root =
190 render_frame_host->frame_tree_node()->frame_tree()->root(); 191 render_frame_host->frame_tree_node()->frame_tree()->root();
191 if (root->render_manager()->interstitial_page() != NULL) { 192 if (root->render_manager()->interstitial_page() != NULL) {
192 LOG(WARNING) << "Discarding message during interstitial."; 193 LOG(WARNING) << "Discarding message during interstitial.";
193 return; 194 return;
194 } 195 }
195 196
196 // We used to cancel the pending renderer here for cross-site downloads. 197 // We used to cancel the pending renderer here for cross-site downloads.
197 // However, it's not safe to do that because the download logic repeatedly 198 // However, it's not safe to do that because the download logic repeatedly
198 // looks for this WebContents based on a render ID. Instead, we just 199 // looks for this WebContents based on a render ID. Instead, we just
199 // leave the pending renderer around until the next navigation event 200 // leave the pending renderer around until the next navigation event
200 // (Navigate, DidNavigate, etc), which will clean it up properly. 201 // (Navigate, DidNavigate, etc), which will clean it up properly.
201 // 202 //
202 // TODO(creis): Find a way to cancel any pending RFH here. 203 // TODO(creis): Find a way to cancel any pending RFH here.
203 } 204 }
204 205
205 // We usually clear the pending entry when it fails, so that an arbitrary URL 206 // Racy conditions can cause a fail message to arrive after its corresponding
206 // isn't left visible above a committed page. This must be enforced when 207 // pending entry has been replaced by another navigation. If
207 // the pending entry isn't visible (e.g., renderer-initiated navigations) to 208 // |DiscardPendingEntry| is called in this case, then the completely valid
208 // prevent URL spoofs for in-page navigations that don't go through 209 // entry for the new navigation would be discarded. See crbug.com/513742. To
209 // DidStartProvisionalLoadForFrame. 210 // catch this case, the current pending entry is compared against the current
210 // 211 // navigation handle's entry id, which should correspond to the failed load.
211 // However, we do preserve the pending entry in some cases, such as on the 212 NavigationHandleImpl* handle = render_frame_host->navigation_handle();
212 // initial navigation of an unmodified blank tab. We also allow the delegate 213 NavigationEntry* pending_entry = controller_->GetPendingEntry();
213 // to say when it's safe to leave aborted URLs in the omnibox, to let the user 214 bool pending_matches_fail_msg =
214 // edit the URL and try again. This may be useful in cases that the committed 215 handle && pending_entry &&
215 // page cannot be attacker-controlled. In these cases, we still allow the 216 handle->pending_nav_entry_id() == pending_entry->GetUniqueID();
216 // view to clear the pending entry and typed URL if the user requests 217 if (pending_matches_fail_msg) {
217 // (e.g., hitting Escape with focus in the address bar). 218 // We usually clear the pending entry when it fails, so that an arbitrary
218 // 219 // URL isn't left visible above a committed page. This must be enforced
219 // Note: don't touch the transient entry, since an interstitial may exist. 220 // when the pending entry isn't visible (e.g., renderer-initiated
220 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || 221 // navigations) to prevent URL spoofs for in-page navigations that don't go
221 delegate_->ShouldPreserveAbortedURLs(); 222 // through DidStartProvisionalLoadForFrame.
222 if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() || 223 //
223 !should_preserve_entry) { 224 // However, we do preserve the pending entry in some cases, such as on the
224 controller_->DiscardPendingEntry(true); 225 // initial navigation of an unmodified blank tab. We also allow the
226 // delegate to say when it's safe to leave aborted URLs in the omnibox, to
227 // let the user edit the URL and try again. This may be useful in cases
228 // that the committed page cannot be attacker-controlled. In these cases,
229 // we still allow the view to clear the pending entry and typed URL if the
230 // user requests (e.g., hitting Escape with focus in the address bar).
231 //
232 // Note: don't touch the transient entry, since an interstitial may exist.
233 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() ||
234 delegate_->ShouldPreserveAbortedURLs();
235 if (pending_entry != controller_->GetVisibleEntry() ||
236 !should_preserve_entry) {
237 controller_->DiscardPendingEntry(true);
225 238
226 // Also force the UI to refresh. 239 // Also force the UI to refresh.
227 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); 240 controller_->delegate()->NotifyNavigationStateChanged(
241 INVALIDATE_TYPE_URL);
242 }
228 } 243 }
229 244
230 if (delegate_) 245 if (delegate_)
231 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); 246 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params);
232 } 247 }
233 248
234 void NavigatorImpl::DidFailLoadWithError( 249 void NavigatorImpl::DidFailLoadWithError(
235 RenderFrameHostImpl* render_frame_host, 250 RenderFrameHostImpl* render_frame_host,
236 const GURL& url, 251 const GURL& url,
237 int error_code, 252 int error_code,
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after
792 } 807 }
793 808
794 // In all other cases the current navigation, if any, is canceled and a new 809 // In all other cases the current navigation, if any, is canceled and a new
795 // NavigationRequest is created for the node. 810 // NavigationRequest is created for the node.
796 frame_tree_node->CreatedNavigationRequest( 811 frame_tree_node->CreatedNavigationRequest(
797 NavigationRequest::CreateRendererInitiated( 812 NavigationRequest::CreateRendererInitiated(
798 frame_tree_node, common_params, begin_params, body, 813 frame_tree_node, common_params, begin_params, body,
799 controller_->GetLastCommittedEntryIndex(), 814 controller_->GetLastCommittedEntryIndex(),
800 controller_->GetEntryCount())); 815 controller_->GetEntryCount()));
801 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); 816 NavigationRequest* navigation_request = frame_tree_node->navigation_request();
802 navigation_request->CreateNavigationHandle();
803
804 if (frame_tree_node->IsMainFrame()) { 817 if (frame_tree_node->IsMainFrame()) {
805 // Renderer-initiated main-frame navigations that need to swap processes 818 // Renderer-initiated main-frame navigations that need to swap processes
806 // will go to the browser via a OpenURL call, and then be handled by the 819 // will go to the browser via a OpenURL call, and then be handled by the
807 // same code path as browser-initiated navigations. For renderer-initiated 820 // same code path as browser-initiated navigations. For renderer-initiated
808 // main frame navigation that start via a BeginNavigation IPC, the 821 // main frame navigation that start via a BeginNavigation IPC, the
809 // RenderFrameHost will not be swapped. Therefore it is safe to call 822 // RenderFrameHost will not be swapped. Therefore it is safe to call
810 // DidStartMainFrameNavigation with the SiteInstance from the current 823 // DidStartMainFrameNavigation with the SiteInstance from the current
811 // RenderFrameHost. 824 // RenderFrameHost.
812 DidStartMainFrameNavigation( 825 DidStartMainFrameNavigation(
813 common_params.url, 826 common_params.url,
814 frame_tree_node->current_frame_host()->GetSiteInstance()); 827 frame_tree_node->current_frame_host()->GetSiteInstance());
815 navigation_data_.reset(); 828 navigation_data_.reset();
816 } 829 }
817 830
831 // The NavigationHandle must be created after the call to
832 // |DidStartMainFrameNavigation|, so it receives the most up to date pending
833 // entry from the NavigationController. The pending entry is guaranteed to be
834 // non null at this point.
835 DCHECK(controller_->GetPendingEntry());
clamy 2016/02/26 14:08:13 Is it always the case with subframes? Subframes wi
Charlie Harrison 2016/02/26 17:39:51 You've caught an error. I don't believe that subfr
836 navigation_request->CreateNavigationHandle(
837 controller_->GetPendingEntry()->GetUniqueID());
818 navigation_request->BeginNavigation(); 838 navigation_request->BeginNavigation();
819 } 839 }
820 840
821 // PlzNavigate 841 // PlzNavigate
822 void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node, 842 void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node,
823 ResourceResponse* response, 843 ResourceResponse* response,
824 scoped_ptr<StreamHandle> body) { 844 scoped_ptr<StreamHandle> body) {
825 CHECK(IsBrowserSideNavigationEnabled()); 845 CHECK(IsBrowserSideNavigationEnabled());
826 846
827 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); 847 NavigationRequest* navigation_request = frame_tree_node->navigation_request();
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
961 bool should_dispatch_beforeunload = 981 bool should_dispatch_beforeunload =
962 frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload(); 982 frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload();
963 FrameMsg_Navigate_Type::Value navigation_type = 983 FrameMsg_Navigate_Type::Value navigation_type =
964 GetNavigationType(controller_->GetBrowserContext(), entry, reload_type); 984 GetNavigationType(controller_->GetBrowserContext(), entry, reload_type);
965 frame_tree_node->CreatedNavigationRequest( 985 frame_tree_node->CreatedNavigationRequest(
966 NavigationRequest::CreateBrowserInitiated( 986 NavigationRequest::CreateBrowserInitiated(
967 frame_tree_node, dest_url, dest_referrer, frame_entry, entry, 987 frame_tree_node, dest_url, dest_referrer, frame_entry, entry,
968 navigation_type, lofi_state, is_same_document_history_load, 988 navigation_type, lofi_state, is_same_document_history_load,
969 navigation_start, controller_)); 989 navigation_start, controller_));
970 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); 990 NavigationRequest* navigation_request = frame_tree_node->navigation_request();
971 navigation_request->CreateNavigationHandle(); 991 navigation_request->CreateNavigationHandle(entry.GetUniqueID());
972 992
973 // Have the current renderer execute its beforeunload event if needed. If it 993 // Have the current renderer execute its beforeunload event if needed. If it
974 // is not needed (when beforeunload dispatch is not needed or this navigation 994 // is not needed (when beforeunload dispatch is not needed or this navigation
975 // is synchronous and same-site) then NavigationRequest::BeginNavigation 995 // is synchronous and same-site) then NavigationRequest::BeginNavigation
976 // should be directly called instead. 996 // should be directly called instead.
977 if (should_dispatch_beforeunload && 997 if (should_dispatch_beforeunload &&
978 ShouldMakeNetworkRequestForURL( 998 ShouldMakeNetworkRequestForURL(
979 navigation_request->common_params().url)) { 999 navigation_request->common_params().url)) {
980 navigation_request->SetWaitingForRendererResponse(); 1000 navigation_request->SetWaitingForRendererResponse();
981 frame_tree_node->current_frame_host()->DispatchBeforeUnload(true); 1001 frame_tree_node->current_frame_host()->DispatchBeforeUnload(true);
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1065 entry->set_should_replace_entry(pending_entry->should_replace_entry()); 1085 entry->set_should_replace_entry(pending_entry->should_replace_entry());
1066 entry->SetRedirectChain(pending_entry->GetRedirectChain()); 1086 entry->SetRedirectChain(pending_entry->GetRedirectChain());
1067 } 1087 }
1068 controller_->SetPendingEntry(std::move(entry)); 1088 controller_->SetPendingEntry(std::move(entry));
1069 if (delegate_) 1089 if (delegate_)
1070 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); 1090 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
1071 } 1091 }
1072 } 1092 }
1073 1093
1074 } // namespace content 1094 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698