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(); | |
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, |
160 pending_entry ? pending_entry->GetUniqueID() : 0)); | |
159 } | 161 } |
160 | 162 |
161 void NavigatorImpl::DidFailProvisionalLoadWithError( | 163 void NavigatorImpl::DidFailProvisionalLoadWithError( |
162 RenderFrameHostImpl* render_frame_host, | 164 RenderFrameHostImpl* render_frame_host, |
163 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { | 165 const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params) { |
164 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec() | 166 VLOG(1) << "Failed Provisional Load: " << params.url.possibly_invalid_spec() |
165 << ", error_code: " << params.error_code | 167 << ", error_code: " << params.error_code |
166 << ", error_description: " << params.error_description | 168 << ", error_description: " << params.error_description |
167 << ", showing_repost_interstitial: " << | 169 << ", showing_repost_interstitial: " << |
168 params.showing_repost_interstitial | 170 params.showing_repost_interstitial |
(...skipping 19 matching lines...) Expand all Loading... | |
188 // commits of the interstitial page. | 190 // commits of the interstitial page. |
189 FrameTreeNode* root = | 191 FrameTreeNode* root = |
190 render_frame_host->frame_tree_node()->frame_tree()->root(); | 192 render_frame_host->frame_tree_node()->frame_tree()->root(); |
191 if (root->render_manager()->interstitial_page() != NULL) { | 193 if (root->render_manager()->interstitial_page() != NULL) { |
192 LOG(WARNING) << "Discarding message during interstitial."; | 194 LOG(WARNING) << "Discarding message during interstitial."; |
193 return; | 195 return; |
194 } | 196 } |
195 | 197 |
196 // 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. |
197 // 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 |
198 // 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 |
199 // leave the pending renderer around until the next navigation event | 201 // leave the pending renderer around until the next navigation event |
200 // (Navigate, DidNavigate, etc), which will clean it up properly. | 202 // (Navigate, DidNavigate, etc), which will clean it up properly. |
201 // | 203 // |
202 // TODO(creis): Find a way to cancel any pending RFH here. | 204 // TODO(creis): Find a way to cancel any pending RFH here. |
203 } | 205 } |
204 | 206 |
205 // We usually clear the pending entry when it fails, so that an arbitrary URL | 207 // 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 | 208 // pending entry has been replaced by another navigation. If |
207 // the pending entry isn't visible (e.g., renderer-initiated navigations) to | 209 // |DiscardPendingEntry| is called in this case, then the completely valid |
208 // prevent URL spoofs for in-page navigations that don't go through | 210 // entry for the new navigation would be discarded. See crbug.com/513742. To |
209 // DidStartProvisionalLoadForFrame. | 211 // catch this case, the current pending entry is compared against the current |
210 // | 212 // 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 | 213 NavigationHandleImpl* handle = render_frame_host->navigation_handle(); |
212 // initial navigation of an unmodified blank tab. We also allow the delegate | 214 NavigationEntry* pending_entry = controller_->GetPendingEntry(); |
213 // to say when it's safe to leave aborted URLs in the omnibox, to let the user | 215 bool pending_matches_fail_msg = |
214 // edit the URL and try again. This may be useful in cases that the committed | 216 handle && pending_entry && |
215 // page cannot be attacker-controlled. In these cases, we still allow the | 217 handle->pending_nav_entry_id() == pending_entry->GetUniqueID(); |
216 // view to clear the pending entry and typed URL if the user requests | 218 if (pending_matches_fail_msg) { |
217 // (e.g., hitting Escape with focus in the address bar). | 219 // We usually clear the pending entry when it fails, so that an arbitrary |
218 // | 220 // 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. | 221 // when the pending entry isn't visible (e.g., renderer-initiated |
220 bool should_preserve_entry = controller_->IsUnmodifiedBlankTab() || | 222 // navigations) to prevent URL spoofs for in-page navigations that don't go |
221 delegate_->ShouldPreserveAbortedURLs(); | 223 // through DidStartProvisionalLoadForFrame. |
222 if (controller_->GetPendingEntry() != controller_->GetVisibleEntry() || | 224 // |
223 !should_preserve_entry) { | 225 // However, we do preserve the pending entry in some cases, such as on the |
224 controller_->DiscardPendingEntry(true); | 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() || | |
Charlie Reis
2016/02/16 21:55:07
Sanity check: If I remember correctly this line is
Charlie Harrison
2016/02/16 22:55:22
Done.
| |
237 !should_preserve_entry) { | |
238 controller_->DiscardPendingEntry(true); | |
225 | 239 |
226 // Also force the UI to refresh. | 240 // Also force the UI to refresh. |
227 controller_->delegate()->NotifyNavigationStateChanged(INVALIDATE_TYPE_URL); | 241 controller_->delegate()->NotifyNavigationStateChanged( |
242 INVALIDATE_TYPE_URL); | |
243 } | |
228 } | 244 } |
229 | 245 |
230 if (delegate_) | 246 if (delegate_) |
231 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); | 247 delegate_->DidFailProvisionalLoadWithError(render_frame_host, params); |
232 } | 248 } |
233 | 249 |
234 void NavigatorImpl::DidFailLoadWithError( | 250 void NavigatorImpl::DidFailLoadWithError( |
235 RenderFrameHostImpl* render_frame_host, | 251 RenderFrameHostImpl* render_frame_host, |
236 const GURL& url, | 252 const GURL& url, |
237 int error_code, | 253 int error_code, |
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
770 } | 786 } |
771 | 787 |
772 // In all other cases the current navigation, if any, is canceled and a new | 788 // In all other cases the current navigation, if any, is canceled and a new |
773 // NavigationRequest is created for the node. | 789 // NavigationRequest is created for the node. |
774 frame_tree_node->CreatedNavigationRequest( | 790 frame_tree_node->CreatedNavigationRequest( |
775 NavigationRequest::CreateRendererInitiated( | 791 NavigationRequest::CreateRendererInitiated( |
776 frame_tree_node, common_params, begin_params, body, | 792 frame_tree_node, common_params, begin_params, body, |
777 controller_->GetLastCommittedEntryIndex(), | 793 controller_->GetLastCommittedEntryIndex(), |
778 controller_->GetEntryCount())); | 794 controller_->GetEntryCount())); |
779 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 795 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
780 navigation_request->CreateNavigationHandle(); | |
781 | |
782 if (frame_tree_node->IsMainFrame()) { | 796 if (frame_tree_node->IsMainFrame()) { |
783 // Renderer-initiated main-frame navigations that need to swap processes | 797 // Renderer-initiated main-frame navigations that need to swap processes |
784 // will go to the browser via a OpenURL call, and then be handled by the | 798 // will go to the browser via a OpenURL call, and then be handled by the |
785 // same code path as browser-initiated navigations. For renderer-initiated | 799 // same code path as browser-initiated navigations. For renderer-initiated |
786 // main frame navigation that start via a BeginNavigation IPC, the | 800 // main frame navigation that start via a BeginNavigation IPC, the |
787 // RenderFrameHost will not be swapped. Therefore it is safe to call | 801 // RenderFrameHost will not be swapped. Therefore it is safe to call |
788 // DidStartMainFrameNavigation with the SiteInstance from the current | 802 // DidStartMainFrameNavigation with the SiteInstance from the current |
789 // RenderFrameHost. | 803 // RenderFrameHost. |
790 DidStartMainFrameNavigation( | 804 DidStartMainFrameNavigation( |
791 common_params.url, | 805 common_params.url, |
792 frame_tree_node->current_frame_host()->GetSiteInstance()); | 806 frame_tree_node->current_frame_host()->GetSiteInstance()); |
793 navigation_data_.reset(); | 807 navigation_data_.reset(); |
794 } | 808 } |
795 | 809 |
810 // The NavigationHandle must be created after the call to | |
811 // |DidStartMainFrameNavigation|, so it receives the most up to date pending | |
812 // entry from the NavigationController. The pending entry is guaranteed to be | |
813 // non null at this point. | |
814 DCHECK(controller_->GetPendingEntry()); | |
815 navigation_request->CreateNavigationHandle( | |
816 controller_->GetPendingEntry()->GetUniqueID()); | |
796 navigation_request->BeginNavigation(); | 817 navigation_request->BeginNavigation(); |
797 } | 818 } |
798 | 819 |
799 // PlzNavigate | 820 // PlzNavigate |
800 void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node, | 821 void NavigatorImpl::CommitNavigation(FrameTreeNode* frame_tree_node, |
801 ResourceResponse* response, | 822 ResourceResponse* response, |
802 scoped_ptr<StreamHandle> body) { | 823 scoped_ptr<StreamHandle> body) { |
803 CHECK(IsBrowserSideNavigationEnabled()); | 824 CHECK(IsBrowserSideNavigationEnabled()); |
804 | 825 |
805 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 826 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
939 bool should_dispatch_beforeunload = | 960 bool should_dispatch_beforeunload = |
940 frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload(); | 961 frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload(); |
941 FrameMsg_Navigate_Type::Value navigation_type = | 962 FrameMsg_Navigate_Type::Value navigation_type = |
942 GetNavigationType(controller_->GetBrowserContext(), entry, reload_type); | 963 GetNavigationType(controller_->GetBrowserContext(), entry, reload_type); |
943 frame_tree_node->CreatedNavigationRequest( | 964 frame_tree_node->CreatedNavigationRequest( |
944 NavigationRequest::CreateBrowserInitiated( | 965 NavigationRequest::CreateBrowserInitiated( |
945 frame_tree_node, dest_url, dest_referrer, frame_entry, entry, | 966 frame_tree_node, dest_url, dest_referrer, frame_entry, entry, |
946 navigation_type, lofi_state, is_same_document_history_load, | 967 navigation_type, lofi_state, is_same_document_history_load, |
947 navigation_start, controller_)); | 968 navigation_start, controller_)); |
948 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); | 969 NavigationRequest* navigation_request = frame_tree_node->navigation_request(); |
949 navigation_request->CreateNavigationHandle(); | 970 navigation_request->CreateNavigationHandle(entry.GetUniqueID()); |
950 | 971 |
951 // Have the current renderer execute its beforeunload event if needed. If it | 972 // Have the current renderer execute its beforeunload event if needed. If it |
952 // is not needed (when beforeunload dispatch is not needed or this navigation | 973 // is not needed (when beforeunload dispatch is not needed or this navigation |
953 // is synchronous and same-site) then NavigationRequest::BeginNavigation | 974 // is synchronous and same-site) then NavigationRequest::BeginNavigation |
954 // should be directly called instead. | 975 // should be directly called instead. |
955 if (should_dispatch_beforeunload && | 976 if (should_dispatch_beforeunload && |
956 ShouldMakeNetworkRequestForURL( | 977 ShouldMakeNetworkRequestForURL( |
957 navigation_request->common_params().url)) { | 978 navigation_request->common_params().url)) { |
958 navigation_request->SetWaitingForRendererResponse(); | 979 navigation_request->SetWaitingForRendererResponse(); |
959 frame_tree_node->current_frame_host()->DispatchBeforeUnload(true); | 980 frame_tree_node->current_frame_host()->DispatchBeforeUnload(true); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1043 entry->set_should_replace_entry(pending_entry->should_replace_entry()); | 1064 entry->set_should_replace_entry(pending_entry->should_replace_entry()); |
1044 entry->SetRedirectChain(pending_entry->GetRedirectChain()); | 1065 entry->SetRedirectChain(pending_entry->GetRedirectChain()); |
1045 } | 1066 } |
1046 controller_->SetPendingEntry(std::move(entry)); | 1067 controller_->SetPendingEntry(std::move(entry)); |
1047 if (delegate_) | 1068 if (delegate_) |
1048 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); | 1069 delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL); |
1049 } | 1070 } |
1050 } | 1071 } |
1051 | 1072 |
1052 } // namespace content | 1073 } // namespace content |
OLD | NEW |