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 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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(); | |
155 render_frame_host->SetNavigationHandle(NavigationHandleImpl::Create( | 154 render_frame_host->SetNavigationHandle(NavigationHandleImpl::Create( |
156 validated_url, render_frame_host->frame_tree_node(), | 155 validated_url, render_frame_host->frame_tree_node(), |
157 false, // is_synchronous | 156 false, // is_synchronous |
158 is_iframe_srcdoc, // is_srcdoc | 157 is_iframe_srcdoc, // is_srcdoc |
159 navigation_start, pending_entry ? pending_entry->GetUniqueID() : 0)); | 158 navigation_start)); |
160 } | 159 } |
161 | 160 |
162 void NavigatorImpl::DidFailProvisionalLoadWithError( | 161 void NavigatorImpl::DidFailProvisionalLoadWithError( |
163 RenderFrameHostImpl* render_frame_host, | 162 RenderFrameHostImpl* render_frame_host, |
164 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { | 163 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { |
165 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec() | 164 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec() |
166 << ", error_code: " << params.error_code | 165 << ", error_code: " << params.error_code |
167 << ", error_description: " << params.error_description | 166 << ", error_description: " << params.error_description |
168 << ", showing_repost_interstitial: " << | 167 << ", showing_repost_interstitial: " << |
169 params.showing_repost_interstitial | 168 params.showing_repost_interstitial |
(...skipping 19 matching lines...) Expand all Loading... |
189 // commits of the interstitial page. | 188 // commits of the interstitial page. |
190 FrameTreeNode* root = | 189 FrameTreeNode* root = |
191 render_frame_host->frame_tree_node()->frame_tree()->root(); | 190 render_frame_host->frame_tree_node()->frame_tree()->root(); |
192 if (root->render_manager()->interstitial_page() != NULL) { | 191 if (root->render_manager()->interstitial_page() != NULL) { |
193 LOG(WARNING) << "Discarding message during interstitial."; | 192 LOG(WARNING) << "Discarding message during interstitial."; |
194 return; | 193 return; |
195 } | 194 } |
196 | 195 |
197 // We used to cancel the pending renderer here for cross-site downloads. | 196 // We used to cancel the pending renderer here for cross-site downloads. |
198 // However, it's not safe to do that because the download logic repeatedly | 197 // However, it's not safe to do that because the download logic repeatedly |
199 // looks for this WebContents based on a render ID. Instead, we just | 198 // looks for this WebContents based on a render ID. Instead, we just |
200 // leave the pending renderer around until the next navigation event | 199 // leave the pending renderer around until the next navigation event |
201 // (Navigate, DidNavigate, etc), which will clean it up properly. | 200 // (Navigate, DidNavigate, etc), which will clean it up properly. |
202 // | 201 // |
203 // TODO(creis): Find a way to cancel any pending RFH here. | 202 // TODO(creis): Find a way to cancel any pending RFH here. |
204 } | 203 } |
205 | 204 |
206 // Racy conditions can cause a fail message to arrive after its corresponding | 205 // We usually clear the pending entry when it fails, so that an arbitrary URL |
207 // pending entry has been replaced by another navigation. If | 206 // isn't left visible above a committed page. This must be enforced when |
208 // |DiscardPendingEntry| is called in this case, then the completely valid | 207 // the pending entry isn't visible (e.g., renderer-initiated navigations) to |
209 // entry for the new navigation would be discarded. See crbug.com/513742. To | 208 // prevent URL spoofs for in-page navigations that don't go through |
210 // catch this case, the current pending entry is compared against the current | 209 // DidStartProvisionalLoadForFrame. |
211 // navigation handle's entry id, which should correspond to the failed load. | 210 // |
212 NavigationHandleImpl* handle = render_frame_host->navigation_handle(); | 211 // However, we do preserve the pending entry in some cases, such as on the |
213 NavigationEntry* pending_entry = controller_->GetPendingEntry(); | 212 // initial navigation of an unmodified blank tab. We also allow the delegate |
214 bool pending_matches_fail_msg = | 213 // to say when it's safe to leave aborted URLs in the omnibox, to let the user |
215 handle && pending_entry && | 214 // edit the URL and try again. This may be useful in cases that the committed |
216 handle->pending_nav_entry_id() == pending_entry->GetUniqueID(); | 215 // page cannot be attacker-controlled. In these cases, we still allow the |
217 if (pending_matches_fail_msg) { | 216 // view to clear the pending entry and typed URL if the user requests |
218 // We usually clear the pending entry when it fails, so that an arbitrary | 217 // (e.g., hitting Escape with focus in the address bar). |
219 // URL isn't left visible above a committed page. This must be enforced | 218 // |
220 // when the pending entry isn't visible (e.g., renderer-initiated | 219 // Note: don't touch the transient entry, since an interstitial may exist. |
221 // navigations) to prevent URL spoofs for in-page navigations that don't go | 220 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || |
222 // through DidStartProvisionalLoadForFrame. | 221 delegate_->ShouldPreserveAbortedURLs(); |
223 // | 222 if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() || |
224 // However, we do preserve the pending entry in some cases, such as on the | 223 !should_preserve_entry) { |
225 // initial navigation of an unmodified blank tab. We also allow the | 224 controller_->DiscardPendingEntry(true); |
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); | |
238 | 225 |
239 // Also force the UI to refresh. | 226 // Also force the UI to refresh. |
240 controller_->delegate()->NotifyNavigationStateChanged( | 227 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); |
241 INVALIDATE_TYPE_URL); | |
242 } | |
243 } | 228 } |
244 | 229 |
245 if (delegate_) | 230 if (delegate_) |
246 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); | 231 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); |
247 } | 232 } |
248 | 233 |
249 void NavigatorImpl::DidFailLoadWithError( | 234 void NavigatorImpl::DidFailLoadWithError( |
250 RenderFrameHostImpl* render_frame_host, | 235 RenderFrameHostImpl* render_frame_host, |
251 const GURL& url, | 236 const GURL& url, |
252 int error_code, | 237 int error_code, |
(...skipping 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
818 } | 803 } |
819 | 804 |
820 // In all other cases the current navigation, if any, is canceled and a new | 805 // In all other cases the current navigation, if any, is canceled and a new |
821 // NavigationRequest is created for the node. | 806 // NavigationRequest is created for the node. |
822 frame_tree_node->CreatedNavigationRequest( | 807 frame_tree_node->CreatedNavigationRequest( |
823 NavigationRequest::CreateRendererInitiated( | 808 NavigationRequest::CreateRendererInitiated( |
824 frame_tree_node, common_params, begin_params, body, | 809 frame_tree_node, common_params, begin_params, body, |
825 controller_->GetLastCommittedEntryIndex(), | 810 controller_->GetLastCommittedEntryIndex(), |
826 controller_->GetEntryCount())); | 811 controller_->GetEntryCount())); |
827 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 812 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
| 813 navigation_request->CreateNavigationHandle(); |
| 814 |
828 if (frame_tree_node->IsMainFrame()) { | 815 if (frame_tree_node->IsMainFrame()) { |
829 // Renderer-initiated main-frame navigations that need to swap processes | 816 // Renderer-initiated main-frame navigations that need to swap processes |
830 // will go to the browser via a OpenURL call, and then be handled by the | 817 // will go to the browser via a OpenURL call, and then be handled by the |
831 // same code path as browser-initiated navigations. For renderer-initiated | 818 // same code path as browser-initiated navigations. For renderer-initiated |
832 // main frame navigation that start via a BeginNavigation IPC, the | 819 // main frame navigation that start via a BeginNavigation IPC, the |
833 // RenderFrameHost will not be swapped. Therefore it is safe to call | 820 // RenderFrameHost will not be swapped. Therefore it is safe to call |
834 // DidStartMainFrameNavigation with the SiteInstance from the current | 821 // DidStartMainFrameNavigation with the SiteInstance from the current |
835 // RenderFrameHost. | 822 // RenderFrameHost. |
836 DidStartMainFrameNavigation( | 823 DidStartMainFrameNavigation( |
837 common_params.url, | 824 common_params.url, |
838 frame_tree_node->current_frame_host()->GetSiteInstance()); | 825 frame_tree_node->current_frame_host()->GetSiteInstance()); |
839 navigation_data_.reset(); | 826 navigation_data_.reset(); |
840 } | 827 } |
841 | 828 |
842 // For main frames, NavigationHandle will be created after the call to | |
843 // |DidStartMainFrameNavigation|, so it receives the most up to date pending | |
844 // entry from the NavigationController. | |
845 NavigationEntry* pending_entry = controller_->GetPendingEntry(); | |
846 navigation_request->CreateNavigationHandle( | |
847 pending_entry ? pending_entry->GetUniqueID() : 0); | |
848 navigation_request->BeginNavigation(); | 829 navigation_request->BeginNavigation(); |
849 } | 830 } |
850 | 831 |
851 // PlzNavigate | 832 // PlzNavigate |
852 void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node, | 833 void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node, |
853 ResourceResponse* response, | 834 ResourceResponse* response, |
854 scoped_ptr<StreamHandle> body) { | 835 scoped_ptr<StreamHandle> body) { |
855 CHECK(IsBrowserSideNavigationEnabled()); | 836 CHECK(IsBrowserSideNavigationEnabled()); |
856 | 837 |
857 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 838 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
991 bool should_dispatch_beforeunload = | 972 bool should_dispatch_beforeunload = |
992 frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload(); | 973 frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload(); |
993 FrameMsg_Navigate_Type::Value navigation_type = | 974 FrameMsg_Navigate_Type::Value navigation_type = |
994 GetNavigationType(controller_->GetBrowserContext(), entry, reload_type); | 975 GetNavigationType(controller_->GetBrowserContext(), entry, reload_type); |
995 frame_tree_node->CreatedNavigationRequest( | 976 frame_tree_node->CreatedNavigationRequest( |
996 NavigationRequest::CreateBrowserInitiated( | 977 NavigationRequest::CreateBrowserInitiated( |
997 frame_tree_node, dest_url, dest_referrer, frame_entry, entry, | 978 frame_tree_node, dest_url, dest_referrer, frame_entry, entry, |
998 navigation_type, lofi_state, is_same_document_history_load, | 979 navigation_type, lofi_state, is_same_document_history_load, |
999 navigation_start, controller_)); | 980 navigation_start, controller_)); |
1000 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 981 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
1001 navigation_request->CreateNavigationHandle(entry.GetUniqueID()); | 982 navigation_request->CreateNavigationHandle(); |
1002 | 983 |
1003 // Have the current renderer execute its beforeunload event if needed. If it | 984 // Have the current renderer execute its beforeunload event if needed. If it |
1004 // is not needed (when beforeunload dispatch is not needed or this navigation | 985 // is not needed (when beforeunload dispatch is not needed or this navigation |
1005 // is synchronous and same-site) then NavigationRequest::BeginNavigation | 986 // is synchronous and same-site) then NavigationRequest::BeginNavigation |
1006 // should be directly called instead. | 987 // should be directly called instead. |
1007 if (should_dispatch_beforeunload && | 988 if (should_dispatch_beforeunload && |
1008 ShouldMakeNetworkRequestForURL( | 989 ShouldMakeNetworkRequestForURL( |
1009 navigation_request->common_params().url)) { | 990 navigation_request->common_params().url)) { |
1010 navigation_request->SetWaitingForRendererResponse(); | 991 navigation_request->SetWaitingForRendererResponse(); |
1011 frame_tree_node->current_frame_host()->DispatchBeforeUnload(true); | 992 frame_tree_node->current_frame_host()->DispatchBeforeUnload(true); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1095 entry->set_should_replace_entry(pending_entry->should_replace_entry()); | 1076 entry->set_should_replace_entry(pending_entry->should_replace_entry()); |
1096 entry->SetRedirectChain(pending_entry->GetRedirectChain()); | 1077 entry->SetRedirectChain(pending_entry->GetRedirectChain()); |
1097 } | 1078 } |
1098 controller_->SetPendingEntry(std::move(entry)); | 1079 controller_->SetPendingEntry(std::move(entry)); |
1099 if (delegate_) | 1080 if (delegate_) |
1100 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); | 1081 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); |
1101 } | 1082 } |
1102 } | 1083 } |
1103 | 1084 |
1104 } // namespace content | 1085 } // namespace content |
OLD | NEW |