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
3 // found in the LICENSE file.
4 
5 #include "content/browser/renderer_host/navigator.h"
6 
7 #include <utility>
8 
9 #include "base/check_op.h"
10 #include "base/debug/dump_without_crashing.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/notreached.h"
13 #include "base/strings/string_util.h"
14 #include "base/time/time.h"
15 #include "content/browser/child_process_security_policy_impl.h"
16 #include "content/browser/renderer_host/debug_urls.h"
17 #include "content/browser/renderer_host/frame_tree.h"
18 #include "content/browser/renderer_host/frame_tree_node.h"
19 #include "content/browser/renderer_host/navigation_controller_impl.h"
20 #include "content/browser/renderer_host/navigation_entry_impl.h"
21 #include "content/browser/renderer_host/navigation_request.h"
22 #include "content/browser/renderer_host/navigation_request_info.h"
23 #include "content/browser/renderer_host/navigator_delegate.h"
24 #include "content/browser/renderer_host/render_frame_host_impl.h"
25 #include "content/browser/renderer_host/render_view_host_impl.h"
26 #include "content/browser/site_instance_impl.h"
27 #include "content/browser/web_package/prefetched_signed_exchange_cache.h"
28 #include "content/browser/web_package/web_bundle_handle_tracker.h"
29 #include "content/browser/webui/web_ui_controller_factory_registry.h"
30 #include "content/browser/webui/web_ui_impl.h"
31 #include "content/common/frame_messages.h"
32 #include "content/common/inter_process_time_ticks_converter.h"
33 #include "content/common/navigation_params.h"
34 #include "content/common/navigation_params_utils.h"
35 #include "content/public/browser/browser_context.h"
36 #include "content/public/browser/content_browser_client.h"
37 #include "content/public/browser/global_request_id.h"
38 #include "content/public/browser/invalidate_type.h"
39 #include "content/public/browser/navigation_controller.h"
40 #include "content/public/browser/navigation_details.h"
41 #include "content/public/browser/page_navigator.h"
42 #include "content/public/browser/render_view_host.h"
43 #include "content/public/browser/restore_type.h"
44 #include "content/public/common/bindings_policy.h"
45 #include "content/public/common/content_client.h"
46 #include "content/public/common/content_constants.h"
47 #include "content/public/common/navigation_policy.h"
48 #include "content/public/common/url_utils.h"
49 #include "net/base/net_errors.h"
50 #include "services/metrics/public/cpp/ukm_builders.h"
51 #include "services/metrics/public/cpp/ukm_recorder.h"
52 #include "services/metrics/public/cpp/ukm_source_id.h"
53 #include "services/network/public/mojom/url_loader_factory.mojom.h"
54 #include "url/gurl.h"
55 #include "url/url_util.h"
56 
57 namespace content {
58 
59 struct Navigator::NavigationMetricsData {
NavigationMetricsDatacontent::Navigator::NavigationMetricsData60   NavigationMetricsData(base::TimeTicks start_time,
61                         GURL url,
62                         ukm::SourceId ukm_source_id,
63                         bool is_browser_initiated_before_unload,
64                         RestoreType restore_type)
65       : start_time_(start_time),
66         url_(url),
67         ukm_source_id_(ukm_source_id),
68         is_browser_initiated_before_unload_(
69             is_browser_initiated_before_unload) {
70     is_restoring_from_last_session_ =
71         (restore_type == RestoreType::LAST_SESSION_EXITED_CLEANLY ||
72          restore_type == RestoreType::LAST_SESSION_CRASHED);
73   }
74 
75   base::TimeTicks start_time_;
76   GURL url_;
77   ukm::SourceId ukm_source_id_;
78   bool is_browser_initiated_before_unload_;
79   bool is_restoring_from_last_session_;
80   base::TimeTicks url_job_start_time_;
81   base::TimeDelta before_unload_delay_;
82 
83   // Timestamps before_unload_(start|end)_ give the time it took to run
84   // beforeunloads dispatched from the browser process. For browser-initated
85   // navigations this includes all frames (all beforeunload handlers on a page).
86   // For renderer-initated navigations this just includes OOPIFs since local
87   // beforeunloads will have been run in the renderer before dispatching the
88   // navigation IPC.
89   base::Optional<base::TimeTicks> before_unload_start_;
90   base::Optional<base::TimeTicks> before_unload_end_;
91 
92   // Time at which the browser process received a navigation request and
93   // dispatched beforeunloads to the renderer.
94   base::Optional<base::TimeTicks> before_unload_sent_;
95 
96   // Timestamps renderer_before_unload_(start|end)_ give the time it took to run
97   // beforeunloads for local frames in a renderer-initiated navigation, prior to
98   // notifying the browser process about the navigation.
99   base::Optional<base::TimeTicks> renderer_before_unload_start_;
100   base::Optional<base::TimeTicks> renderer_before_unload_end_;
101 };
102 
Navigator(NavigationControllerImpl * navigation_controller,NavigatorDelegate * delegate)103 Navigator::Navigator(NavigationControllerImpl* navigation_controller,
104                      NavigatorDelegate* delegate)
105     : controller_(navigation_controller), delegate_(delegate) {}
106 
107 Navigator::~Navigator() = default;
108 
109 // static
CheckWebUIRendererDoesNotDisplayNormalURL(RenderFrameHostImpl * render_frame_host,const UrlInfo & url_info,bool is_renderer_initiated_check)110 bool Navigator::CheckWebUIRendererDoesNotDisplayNormalURL(
111     RenderFrameHostImpl* render_frame_host,
112     const UrlInfo& url_info,
113     bool is_renderer_initiated_check) {
114   const GURL& url = url_info.url;
115   // In single process mode, everything runs in the same process, so the checks
116   // below are irrelevant.
117   if (RenderProcessHost::run_renderer_in_process())
118     return true;
119 
120   ChildProcessSecurityPolicyImpl* security_policy =
121       ChildProcessSecurityPolicyImpl::GetInstance();
122   ProcessLock process_lock =
123       security_policy->GetProcessLock(render_frame_host->GetProcess()->GetID());
124 
125   // In the case of error page process, any URL is allowed to commit.
126   if (process_lock == ProcessLock::CreateForErrorPage())
127     return true;
128 
129   bool frame_has_bindings = ((render_frame_host->GetEnabledBindings() &
130                               kWebUIBindingsPolicyMask) != 0);
131   bool is_allowed_in_web_ui_renderer =
132       WebUIControllerFactoryRegistry::GetInstance()->IsURLAcceptableForWebUI(
133           render_frame_host->GetProcess()->GetBrowserContext(), url);
134 
135   // Embedders might disable locking for WebUI URLs, which is bad idea, however
136   // this method should take this into account.
137   SiteInstanceImpl* site_instance = render_frame_host->GetSiteInstance();
138   SiteInfo site_info = site_instance->DeriveSiteInfo(url_info);
139   bool should_lock_process =
140       site_info.ShouldLockProcessToSite(site_instance->GetIsolationContext());
141 
142   // If the |render_frame_host| has any WebUI bindings, disallow URLs that are
143   // not allowed in a WebUI renderer process.
144   if (frame_has_bindings) {
145     // The process itself must have WebUI bit in the security policy.
146     // Otherwise it indicates that there is a bug in browser process logic and
147     // the browser process must be terminated.
148     // TODO(nasko): Convert to CHECK() once it is confirmed this is not
149     // violated in reality.
150     if (!security_policy->HasWebUIBindings(
151             render_frame_host->GetProcess()->GetID())) {
152       base::debug::DumpWithoutCrashing();
153     }
154 
155     // Check whether the process must be locked and if so that the process lock
156     // is indeed in place.
157     if (should_lock_process && !process_lock.is_locked_to_site())
158       return false;
159 
160     // There must be a WebUI on the frame.
161     if (!render_frame_host->web_ui())
162       return false;
163 
164     // The |url| must be allowed in a WebUI process if the frame has WebUI.
165     if (!is_allowed_in_web_ui_renderer) {
166       // If this method is called in response to IPC message from the renderer
167       // process, it should be terminated, otherwise it is a bug in the
168       // navigation logic and the browser process should be terminated to avoid
169       // exposing users to security issues.
170       if (is_renderer_initiated_check)
171         return false;
172 
173       CHECK(false);
174     }
175   }
176 
177   // If |url| is one that is allowed in WebUI renderer process, ensure that its
178   // origin is either opaque or matches the origin of the process lock.
179   if (is_allowed_in_web_ui_renderer) {
180     url::Origin url_origin = url::Origin::Create(url.GetOrigin());
181 
182     // Verify |url| matches the origin of the process lock, if one is in place.
183     if (should_lock_process) {
184       if (!url_origin.opaque() && !process_lock.MatchesOrigin(url_origin))
185         return false;
186     }
187   }
188 
189   return true;
190 }
191 
192 // A renderer-initiated navigation should be ignored iff a) there is an ongoing
193 // request b) which is browser initiated and c) the renderer request is not
194 // user-initiated.
195 // static
ShouldIgnoreIncomingRendererRequest(const NavigationRequest * ongoing_navigation_request,bool has_user_gesture)196 bool Navigator::ShouldIgnoreIncomingRendererRequest(
197     const NavigationRequest* ongoing_navigation_request,
198     bool has_user_gesture) {
199   return ongoing_navigation_request &&
200          ongoing_navigation_request->browser_initiated() && !has_user_gesture;
201 }
202 
GetDelegate()203 NavigatorDelegate* Navigator::GetDelegate() {
204   return delegate_;
205 }
206 
GetController()207 NavigationController* Navigator::GetController() {
208   return controller_;
209 }
210 
DidFailLoadWithError(RenderFrameHostImpl * render_frame_host,const GURL & url,int error_code)211 void Navigator::DidFailLoadWithError(RenderFrameHostImpl* render_frame_host,
212                                      const GURL& url,
213                                      int error_code) {
214   if (delegate_) {
215     delegate_->DidFailLoadWithError(render_frame_host, url, error_code);
216   }
217 }
218 
StartHistoryNavigationInNewSubframe(RenderFrameHostImpl * render_frame_host,mojo::PendingAssociatedRemote<mojom::NavigationClient> * navigation_client)219 bool Navigator::StartHistoryNavigationInNewSubframe(
220     RenderFrameHostImpl* render_frame_host,
221     mojo::PendingAssociatedRemote<mojom::NavigationClient>* navigation_client) {
222   return controller_->StartHistoryNavigationInNewSubframe(render_frame_host,
223                                                           navigation_client);
224 }
225 
DidNavigate(RenderFrameHostImpl * render_frame_host,const FrameHostMsg_DidCommitProvisionalLoad_Params & params,std::unique_ptr<NavigationRequest> navigation_request,bool was_within_same_document)226 void Navigator::DidNavigate(
227     RenderFrameHostImpl* render_frame_host,
228     const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
229     std::unique_ptr<NavigationRequest> navigation_request,
230     bool was_within_same_document) {
231   DCHECK(navigation_request);
232   FrameTreeNode* frame_tree_node = render_frame_host->frame_tree_node();
233   FrameTree* frame_tree = frame_tree_node->frame_tree();
234   base::WeakPtr<RenderFrameHostImpl> old_frame_host =
235       frame_tree_node->render_manager()->current_frame_host()->GetWeakPtr();
236 
237   bool is_same_document_navigation = controller_->IsURLSameDocumentNavigation(
238       params.url, params.origin, was_within_same_document, render_frame_host);
239   // If a frame claims the navigation was same-document, it must be the current
240   // frame, not a pending one.
241   if (is_same_document_navigation &&
242       render_frame_host != old_frame_host.get()) {
243     bad_message::ReceivedBadMessage(render_frame_host->GetProcess(),
244                                     bad_message::NI_IN_PAGE_NAVIGATION);
245     is_same_document_navigation = false;
246   }
247   // At this point we have already chosen a SiteInstance for this navigation, so
248   // set |origin_requests_isolation| = false in the conversion to UrlInfo below.
249   const UrlInfo url_info(params.url, false /* origin_requests_isolation */);
250   bool is_cross_document_same_site_navigation =
251       !is_same_document_navigation &&
252       old_frame_host->IsNavigationSameSite(
253           url_info, render_frame_host->GetSiteInstance()
254                         ->GetCoopCoepCrossOriginIsolatedInfo());
255 
256   if (is_cross_document_same_site_navigation) {
257     UMA_HISTOGRAM_BOOLEAN(
258         "BackForwardCache.ProactiveSameSiteBISwap.SameSiteNavigationDidSwap",
259         navigation_request->did_same_site_proactive_browsing_instance_swap());
260   }
261 
262   if (navigation_request->did_same_site_proactive_browsing_instance_swap()) {
263     // If we did a same-site cross-BrowsingInstance main frame navigation, we
264     // might be introducing a web-observable behavior change if we need to
265     // unload the old frame (if we can't store the page in the back-forward
266     // cache), because on normal same-site navigations the unloading of the old
267     // RenderFrameHost happens before commit. We're measuring how often this
268     // case happens to determine the risk of this change.
269     DCHECK(old_frame_host.get());
270     DCHECK_NE(old_frame_host.get(), render_frame_host);
271     DCHECK(frame_tree_node->IsMainFrame());
272     DCHECK(!old_frame_host->GetSiteInstance()->IsRelatedSiteInstance(
273         render_frame_host->GetSiteInstance()));
274     DCHECK(is_cross_document_same_site_navigation);
275     bool can_store_in_back_forward_cache =
276         controller_->GetBackForwardCache().CanStorePageNow(
277             old_frame_host.get());
278     UMA_HISTOGRAM_BOOLEAN(
279         "BackForwardCache.ProactiveSameSiteBISwap.EligibilityDuringCommit",
280         can_store_in_back_forward_cache);
281     UMA_HISTOGRAM_BOOLEAN(
282         "BackForwardCache.ProactiveSameSiteBISwap.UnloadRunsAfterCommit",
283         !can_store_in_back_forward_cache &&
284             old_frame_host->UnloadHandlerExistsInSameSiteInstanceSubtree());
285   }
286 
287   if (auto& old_page_info = navigation_request->commit_params().old_page_info) {
288     // This is a same-site main-frame navigation where we did a proactive
289     // BrowsingInstance swap but we're reusing the old page's process, and we
290     // have dispatched the pagehide and visibilitychange handlers of the old
291     // page when we committed the new page.
292     auto* page_lifecycle_state_manager =
293         old_frame_host->render_view_host()->GetPageLifecycleStateManager();
294     page_lifecycle_state_manager->DidSetPagehideDispatchDuringNewPageCommit(
295         std::move(old_page_info->new_lifecycle_state_for_old_page));
296   }
297 
298   if (ui::PageTransitionIsMainFrame(params.transition)) {
299     if (delegate_) {
300       // Run tasks that must execute just before the commit.
301       delegate_->DidNavigateMainFramePreCommit(is_same_document_navigation);
302     }
303   }
304 
305   // DidNavigateFrame() must be called before replicating the new origin and
306   // other properties to proxies.  This is because it destroys the subframes of
307   // the frame we're navigating from, which might trigger those subframes to
308   // run unload handlers.  Those unload handlers should still see the old
309   // frame's origin.  See https://crbug.com/825283.
310   frame_tree_node->render_manager()->DidNavigateFrame(
311       render_frame_host, params.gesture == NavigationGestureUser,
312       is_same_document_navigation,
313       navigation_request->coop_status()
314           .require_browsing_instance_swap() /* clear_proxies_on_commit */,
315       navigation_request->commit_params().frame_policy);
316 
317   // Save the new page's origin and other properties, and replicate them to
318   // proxies, including the proxy created in DidNavigateFrame() to replace the
319   // old frame in cross-process navigation cases.
320   frame_tree_node->SetCurrentOrigin(
321       params.origin, params.has_potentially_trustworthy_unique_origin);
322   frame_tree_node->SetInsecureRequestPolicy(params.insecure_request_policy);
323   frame_tree_node->SetInsecureNavigationsSet(params.insecure_navigations_set);
324 
325   // Save the activation status of the previous page here before it gets reset
326   // in FrameTreeNode::ResetForNavigation.
327   bool previous_document_was_activated =
328       frame_tree->root()->HasStickyUserActivation();
329 
330   if (!is_same_document_navigation) {
331     // Navigating to a new location means a new, fresh set of http headers
332     // and/or <meta> elements - we need to reset CSP and Feature Policy.
333     // However, if the navigation is restoring the given |render_frame_host|
334     // from back-forward cache, it does not change the document in the given
335     // RenderFrameHost and the existing Content Security Policy should be kept.
336     if (!navigation_request->IsServedFromBackForwardCache())
337       render_frame_host->ResetContentSecurityPolicies();
338 
339     auto reset_result = frame_tree_node->ResetForNavigation(
340         navigation_request->IsServedFromBackForwardCache());
341 
342     // |old_frame_host| might get immediately deleted after the DidNavigateFrame
343     // call above, so use weak pointer here.
344     if (old_frame_host && old_frame_host->IsInBackForwardCache()) {
345       if (reset_result.changed_frame_policy) {
346         old_frame_host->EvictFromBackForwardCacheWithReason(
347             BackForwardCacheMetrics::NotRestoredReason::
348                 kFrameTreeNodeStateReset);
349       }
350     }
351   }
352 
353   // Update the site of the SiteInstance if it doesn't have one yet, unless
354   // assigning a site is not necessary for this URL. In that case, the
355   // SiteInstance can still be considered unused until a navigation to a real
356   // page.
357   SiteInstanceImpl* site_instance = render_frame_host->GetSiteInstance();
358   if (!site_instance->HasSite() &&
359       SiteInstanceImpl::ShouldAssignSiteForURL(url_info.url)) {
360     site_instance->ConvertToDefaultOrSetSite(url_info);
361   }
362 
363   // Need to update MIME type here because it's referred to in
364   // UpdateNavigationCommands() called by RendererDidNavigate() to
365   // determine whether or not to enable the encoding menu.
366   // It's updated only for the main frame. For a subframe,
367   // RenderView::UpdateURL does not set params.contents_mime_type.
368   // (see http://code.google.com/p/chromium/issues/detail?id=2929 )
369   // TODO(jungshik): Add a test for the encoding menu to avoid
370   // regressing it again.
371   // TODO(nasko): Verify the correctness of the above comment, since some of the
372   // code doesn't exist anymore. Also, move this code in the
373   // PageTransitionIsMainFrame code block above.
374   if (ui::PageTransitionIsMainFrame(params.transition) && delegate_) {
375     RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
376         render_frame_host->GetRenderViewHost());
377     rvh->SetContentsMimeType(params.contents_mime_type);
378   }
379 
380   int old_entry_count = controller_->GetEntryCount();
381   LoadCommittedDetails details;
382   bool did_navigate = controller_->RendererDidNavigate(
383       render_frame_host, params, &details, is_same_document_navigation,
384       previous_document_was_activated, navigation_request.get());
385 
386   // If the history length and/or offset changed, update other renderers in the
387   // FrameTree.
388   if (old_entry_count != controller_->GetEntryCount() ||
389       details.previous_entry_index !=
390           controller_->GetLastCommittedEntryIndex()) {
391     frame_tree->root()->render_manager()->ExecutePageBroadcastMethod(
392         base::BindRepeating(
393             [](int history_offset, int history_count, RenderViewHostImpl* rvh) {
394               if (auto& broadcast = rvh->GetAssociatedPageBroadcast())
395                 broadcast->SetHistoryOffsetAndLength(history_offset,
396                                                      history_count);
397             },
398             controller_->GetLastCommittedEntryIndex(),
399             controller_->GetEntryCount()),
400         site_instance);
401   }
402 
403   // Back-forward cache navigations do not create a new document.
404   //
405   // |was_within_same_document| (controlled by the renderer) also needs to be
406   // considered: in some cases, the browser and renderer can disagree. While
407   // this is usually a bad message kill, there are some situations where this
408   // can legitimately happen. When a new frame is created (e.g. with
409   // <iframe src="...">), the initial about:blank document doesn't have a
410   // corresponding entry in the browser process. As a result, the browser
411   // process incorrectly determines that the navigation is cross-document when
412   // in reality it's same-document.
413   //
414   // TODO(crbug/1099264): Remove |was_within_same_document| from this logic
415   // once all same-document navigations have a NavigationEntry. Once this
416   // happens there should be no cases where the browser and renderer
417   // legitimately disagree as described above.
418   bool did_create_new_document =
419       !navigation_request->IsServedFromBackForwardCache() &&
420       !is_same_document_navigation && !was_within_same_document;
421 
422   render_frame_host->DidNavigate(params, navigation_request.get(),
423                                  did_create_new_document);
424 
425   // Send notification about committed provisional loads. This notification is
426   // different from the NAV_ENTRY_COMMITTED notification which doesn't include
427   // the actual URL navigated to and isn't sent for AUTO_SUBFRAME navigations.
428   if (details.type != NAVIGATION_TYPE_NAV_IGNORE && delegate_) {
429     DCHECK_EQ(!render_frame_host->GetParent(),
430               did_navigate ? details.is_main_frame : false);
431     navigation_request->DidCommitNavigation(params, did_navigate,
432                                             details.did_replace_entry,
433                                             details.previous_url, details.type);
434     navigation_request.reset();
435   }
436 
437   if (!did_navigate)
438     return;  // No navigation happened.
439 
440   // DO NOT ADD MORE STUFF TO THIS FUNCTION! Your component should either listen
441   // for the appropriate notification (best) or you can add it to
442   // DidNavigateMainFramePostCommit / DidNavigateAnyFramePostCommit (only if
443   // necessary, please).
444 
445   // TODO(carlosk): Move this out.
446   RecordNavigationMetrics(details, params, site_instance);
447 
448   // Run post-commit tasks.
449   if (delegate_) {
450     if (details.is_main_frame) {
451       delegate_->DidNavigateMainFramePostCommit(render_frame_host, details,
452                                                 params);
453     }
454 
455     delegate_->DidNavigateAnyFramePostCommit(render_frame_host, details,
456                                              params);
457   }
458 }
459 
Navigate(std::unique_ptr<NavigationRequest> request,ReloadType reload_type,RestoreType restore_type)460 void Navigator::Navigate(std::unique_ptr<NavigationRequest> request,
461                          ReloadType reload_type,
462                          RestoreType restore_type) {
463   TRACE_EVENT0("browser,navigation", "Navigator::Navigate");
464   TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
465       "navigation,rail", "NavigationTiming navigationStart",
466       TRACE_EVENT_SCOPE_GLOBAL, request->common_params().navigation_start);
467 
468   // Save destination url, as it is needed for
469   // DidStartNavigationToPendingEntry and request could be destroyed after
470   // BeginNavigation below.
471   GURL dest_url = request->common_params().url;
472   FrameTreeNode* frame_tree_node = request->frame_tree_node();
473 
474   navigation_data_ = std::make_unique<NavigationMetricsData>(
475       request->common_params().navigation_start, request->common_params().url,
476       frame_tree_node->current_frame_host()->GetPageUkmSourceId(),
477       true /* is_browser_initiated_before_unload */, restore_type);
478 
479   // Check if the BeforeUnload event needs to execute before assigning the
480   // NavigationRequest to the FrameTreeNode. Assigning it to the FrameTreeNode
481   // has the side effect of initializing the current RenderFrameHost, which will
482   // return that it should execute the BeforeUnload event (even though we don't
483   // need to wait for it in the case of a brand new RenderFrameHost).
484   //
485   // We don't want to dispatch a beforeunload handler if
486   // is_history_navigation_in_new_child is true. This indicates a newly created
487   // child frame which does not have a beforeunload handler.
488   bool should_dispatch_beforeunload =
489       !NavigationTypeUtils::IsSameDocument(
490           request->common_params().navigation_type) &&
491       !request->common_params().is_history_navigation_in_new_child_frame &&
492       frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload(
493           false /* check_subframes_only */);
494 
495   int nav_entry_id = request->nav_entry_id();
496   bool is_pending_entry =
497       controller_->GetPendingEntry() &&
498       (nav_entry_id == controller_->GetPendingEntry()->GetUniqueID());
499   frame_tree_node->CreatedNavigationRequest(std::move(request));
500   DCHECK(frame_tree_node->navigation_request());
501 
502   // Have the current renderer execute its beforeunload event if needed. If it
503   // is not needed then NavigationRequest::BeginNavigation should be directly
504   // called instead.
505   if (should_dispatch_beforeunload) {
506     frame_tree_node->navigation_request()->SetWaitingForRendererResponse();
507     frame_tree_node->current_frame_host()->DispatchBeforeUnload(
508         RenderFrameHostImpl::BeforeUnloadType::BROWSER_INITIATED_NAVIGATION,
509         reload_type != ReloadType::NONE);
510   } else {
511     frame_tree_node->navigation_request()->BeginNavigation();
512     // WARNING: The NavigationRequest might have been destroyed in
513     // BeginNavigation(). Do not use |frame_tree_node->navigation_request()|
514     // after this point without null checking it first.
515   }
516 
517   // Make sure no code called via RFH::Navigate clears the pending entry.
518   if (is_pending_entry)
519     CHECK_EQ(nav_entry_id, controller_->GetPendingEntry()->GetUniqueID());
520 }
521 
RequestOpenURL(RenderFrameHostImpl * render_frame_host,const GURL & url,const GlobalFrameRoutingId & initiator_routing_id,const base::Optional<url::Origin> & initiator_origin,const scoped_refptr<network::ResourceRequestBody> & post_body,const std::string & extra_headers,const Referrer & referrer,WindowOpenDisposition disposition,bool should_replace_current_entry,bool user_gesture,blink::TriggeringEventInfo triggering_event_info,const std::string & href_translate,scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,const base::Optional<Impression> & impression)522 void Navigator::RequestOpenURL(
523     RenderFrameHostImpl* render_frame_host,
524     const GURL& url,
525     const GlobalFrameRoutingId& initiator_routing_id,
526     const base::Optional<url::Origin>& initiator_origin,
527     const scoped_refptr<network::ResourceRequestBody>& post_body,
528     const std::string& extra_headers,
529     const Referrer& referrer,
530     WindowOpenDisposition disposition,
531     bool should_replace_current_entry,
532     bool user_gesture,
533     blink::TriggeringEventInfo triggering_event_info,
534     const std::string& href_translate,
535     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
536     const base::Optional<Impression>& impression) {
537   // Note: This can be called for subframes (even when OOPIFs are not possible)
538   // if the disposition calls for a different window.
539 
540   // Only the current RenderFrameHost should be sending an OpenURL request.
541   // Pending RenderFrameHost should know where it is navigating and pending
542   // deletion RenderFrameHost shouldn't be trying to navigate.
543   if (render_frame_host !=
544       render_frame_host->frame_tree_node()->current_frame_host()) {
545     return;
546   }
547 
548   SiteInstance* current_site_instance = render_frame_host->GetSiteInstance();
549 
550   // TODO(creis): Pass the redirect_chain into this method to support client
551   // redirects.  http://crbug.com/311721.
552   std::vector<GURL> redirect_chain;
553 
554   int frame_tree_node_id = FrameTreeNode::kFrameTreeNodeInvalidId;
555 
556   // Send the navigation to the current FrameTreeNode if it's destined for a
557   // subframe in the current tab.  We'll assume it's for the main frame
558   // (possibly of a new or different WebContents) otherwise.
559   if (disposition == WindowOpenDisposition::CURRENT_TAB &&
560       render_frame_host->GetParent()) {
561     frame_tree_node_id =
562         render_frame_host->frame_tree_node()->frame_tree_node_id();
563   }
564 
565   OpenURLParams params(url, referrer, frame_tree_node_id, disposition,
566                        ui::PAGE_TRANSITION_LINK,
567                        true /* is_renderer_initiated */);
568   params.post_data = post_body;
569   params.extra_headers = extra_headers;
570   if (redirect_chain.size() > 0)
571     params.redirect_chain = redirect_chain;
572   params.should_replace_current_entry = should_replace_current_entry;
573   params.user_gesture = user_gesture;
574   params.triggering_event_info = triggering_event_info;
575   params.initiator_origin = initiator_origin;
576   params.initiator_routing_id = initiator_routing_id;
577 
578   // RequestOpenURL is used only for local frames, so we can get here only if
579   // the navigation is initiated by a frame in the same SiteInstance as this
580   // frame.  Note that navigations on RenderFrameProxies do not use
581   // RequestOpenURL and go through NavigateFromFrameProxy instead.
582   params.source_site_instance = current_site_instance;
583 
584   params.source_render_frame_id = render_frame_host->GetRoutingID();
585   params.source_render_process_id = render_frame_host->GetProcess()->GetID();
586 
587   if (render_frame_host->web_ui()) {
588     // Note that we hide the referrer for Web UI pages. We don't really want
589     // web sites to see a referrer of "chrome://blah" (and some chrome: URLs
590     // might have search terms or other stuff we don't want to send to the
591     // site), so we send no referrer.
592     params.referrer = Referrer();
593 
594     // Navigations in Web UI pages count as browser-initiated navigations.
595     params.is_renderer_initiated = false;
596   }
597 
598   params.blob_url_loader_factory = std::move(blob_url_loader_factory);
599   params.href_translate = href_translate;
600   params.impression = impression;
601 
602   if (delegate_)
603     delegate_->OpenURL(params);
604 }
605 
NavigateFromFrameProxy(RenderFrameHostImpl * render_frame_host,const GURL & url,const GlobalFrameRoutingId & initiator_routing_id,const url::Origin & initiator_origin,SiteInstance * source_site_instance,const Referrer & referrer,ui::PageTransition page_transition,bool should_replace_current_entry,NavigationDownloadPolicy download_policy,const std::string & method,scoped_refptr<network::ResourceRequestBody> post_body,const std::string & extra_headers,scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,bool has_user_gesture,const base::Optional<Impression> & impression)606 void Navigator::NavigateFromFrameProxy(
607     RenderFrameHostImpl* render_frame_host,
608     const GURL& url,
609     const GlobalFrameRoutingId& initiator_routing_id,
610     const url::Origin& initiator_origin,
611     SiteInstance* source_site_instance,
612     const Referrer& referrer,
613     ui::PageTransition page_transition,
614     bool should_replace_current_entry,
615     NavigationDownloadPolicy download_policy,
616     const std::string& method,
617     scoped_refptr<network::ResourceRequestBody> post_body,
618     const std::string& extra_headers,
619     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
620     bool has_user_gesture,
621     const base::Optional<Impression>& impression) {
622   // |method != "POST"| should imply absence of |post_body|.
623   if (method != "POST" && post_body) {
624     NOTREACHED();
625     post_body = nullptr;
626   }
627 
628   // Allow the delegate to cancel the transfer.
629   if (!delegate_->ShouldTransferNavigation(
630           render_frame_host->frame_tree_node()->IsMainFrame()))
631     return;
632 
633   // TODO(creis): Determine if this transfer started as a browser-initiated
634   // navigation.  See https://crbug.com/495161.
635   bool is_renderer_initiated = true;
636   Referrer referrer_to_use(referrer);
637   if (render_frame_host->web_ui()) {
638     // Note that we hide the referrer for Web UI pages. We don't really want
639     // web sites to see a referrer of "chrome://blah" (and some chrome: URLs
640     // might have search terms or other stuff we don't want to send to the
641     // site), so we send no referrer.
642     referrer_to_use = Referrer();
643 
644     // Navigations in Web UI pages count as browser-initiated navigations.
645     is_renderer_initiated = false;
646   }
647 
648   if (is_renderer_initiated &&
649       ShouldIgnoreIncomingRendererRequest(
650           render_frame_host->frame_tree_node()->navigation_request(),
651           has_user_gesture)) {
652     return;
653   }
654 
655   controller_->NavigateFromFrameProxy(
656       render_frame_host, url, initiator_routing_id, initiator_origin,
657       is_renderer_initiated, source_site_instance, referrer_to_use,
658       page_transition, should_replace_current_entry, download_policy, method,
659       post_body, extra_headers, std::move(blob_url_loader_factory), impression);
660 }
661 
BeforeUnloadCompleted(FrameTreeNode * frame_tree_node,bool proceed,const base::TimeTicks & proceed_time)662 void Navigator::BeforeUnloadCompleted(FrameTreeNode* frame_tree_node,
663                                       bool proceed,
664                                       const base::TimeTicks& proceed_time) {
665   DCHECK(frame_tree_node);
666 
667   NavigationRequest* navigation_request = frame_tree_node->navigation_request();
668 
669   // The NavigationRequest may have been canceled while the renderer was
670   // executing the BeforeUnload event.
671   if (!navigation_request)
672     return;
673 
674   // If the user chose not to proceed, cancel the ongoing navigation.
675   // Note: it might be a new navigation, and not the one that triggered the
676   // sending of the BeforeUnload IPC in the first place. However, the
677   // BeforeUnload where the user asked not to proceed will have taken place
678   // after the navigation started. The last user input should be respected, and
679   // the navigation cancelled anyway.
680   if (!proceed) {
681     CancelNavigation(frame_tree_node);
682     return;
683   }
684 
685   // The browser-initiated NavigationRequest that triggered the sending of the
686   // BeforeUnload IPC might have been replaced by a renderer-initiated one while
687   // the BeforeUnload event executed in the renderer. In that case, the request
688   // will already have begun, so there is no need to start it again.
689   if (navigation_request->state() >
690       NavigationRequest::WAITING_FOR_RENDERER_RESPONSE) {
691     DCHECK(navigation_request->from_begin_navigation());
692     return;
693   }
694 
695   // Update the navigation start: it should be when it was determined that the
696   // navigation will proceed.
697   navigation_request->set_navigation_start_time(proceed_time);
698 
699   DCHECK_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
700             navigation_request->state());
701 
702   // Send the request to the IO thread.
703   navigation_request->BeginNavigation();
704   // DO NOT USE |navigation_request| BEYOND THIS POINT. It might have been
705   // destroyed in BeginNavigation().
706   // See https://crbug.com/770157.
707 }
708 
OnBeginNavigation(FrameTreeNode * frame_tree_node,mojom::CommonNavigationParamsPtr common_params,mojom::BeginNavigationParamsPtr begin_params,scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client,mojo::PendingRemote<blink::mojom::NavigationInitiator> navigation_initiator,scoped_refptr<PrefetchedSignedExchangeCache> prefetched_signed_exchange_cache,std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker)709 void Navigator::OnBeginNavigation(
710     FrameTreeNode* frame_tree_node,
711     mojom::CommonNavigationParamsPtr common_params,
712     mojom::BeginNavigationParamsPtr begin_params,
713     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
714     mojo::PendingAssociatedRemote<mojom::NavigationClient> navigation_client,
715     mojo::PendingRemote<blink::mojom::NavigationInitiator> navigation_initiator,
716     scoped_refptr<PrefetchedSignedExchangeCache>
717         prefetched_signed_exchange_cache,
718     std::unique_ptr<WebBundleHandleTracker> web_bundle_handle_tracker) {
719   // TODO(clamy): the url sent by the renderer should be validated with
720   // FilterURL.
721   // This is a renderer-initiated navigation.
722   DCHECK(frame_tree_node);
723 
724   if (common_params->is_history_navigation_in_new_child_frame) {
725     // Try to find a FrameNavigationEntry that matches this frame instead, based
726     // on the frame's unique name.  If this can't be found, fall back to the
727     // default path below.
728     if (frame_tree_node->navigator().StartHistoryNavigationInNewSubframe(
729             frame_tree_node->current_frame_host(), &navigation_client)) {
730       return;
731     }
732   }
733 
734   NavigationRequest* ongoing_navigation_request =
735       frame_tree_node->navigation_request();
736 
737   // Client redirects during the initial history navigation of a child frame
738   // should take precedence over the history navigation (despite being renderer-
739   // initiated).  See https://crbug.com/348447 and https://crbug.com/691168.
740   if (ongoing_navigation_request &&
741       ongoing_navigation_request->common_params()
742           .is_history_navigation_in_new_child_frame) {
743     // Preemptively clear this local pointer before deleting the request.
744     ongoing_navigation_request = nullptr;
745     frame_tree_node->ResetNavigationRequest(false);
746   }
747 
748   // Verify this navigation has precedence.
749   if (ShouldIgnoreIncomingRendererRequest(ongoing_navigation_request,
750                                           common_params->has_user_gesture)) {
751     return;
752   }
753 
754   NavigationEntryImpl* navigation_entry =
755       GetNavigationEntryForRendererInitiatedNavigation(*common_params,
756                                                        frame_tree_node);
757   const bool override_user_agent =
758       delegate_ &&
759       delegate_->ShouldOverrideUserAgentForRendererInitiatedNavigation();
760   frame_tree_node->CreatedNavigationRequest(
761       NavigationRequest::CreateRendererInitiated(
762           frame_tree_node, navigation_entry, std::move(common_params),
763           std::move(begin_params), controller_->GetLastCommittedEntryIndex(),
764           controller_->GetEntryCount(), override_user_agent,
765           std::move(blob_url_loader_factory), std::move(navigation_client),
766           std::move(navigation_initiator),
767           std::move(prefetched_signed_exchange_cache),
768           std::move(web_bundle_handle_tracker)));
769   NavigationRequest* navigation_request = frame_tree_node->navigation_request();
770 
771   navigation_data_ = std::make_unique<NavigationMetricsData>(
772       navigation_request->common_params().navigation_start,
773       navigation_request->common_params().url,
774       frame_tree_node->current_frame_host()->GetPageUkmSourceId(),
775       false /* is_browser_initiated_before_unload */, RestoreType::NONE);
776 
777   LogRendererInitiatedBeforeUnloadTime(
778       navigation_request->begin_params()->before_unload_start,
779       navigation_request->begin_params()->before_unload_end);
780 
781   // This frame has already run beforeunload before it sent this IPC.  See if
782   // any of its cross-process subframes also need to run beforeunload.  If so,
783   // delay the navigation until beforeunload completion callbacks are invoked on
784   // those frames.
785   DCHECK(!NavigationTypeUtils::IsSameDocument(
786       navigation_request->common_params().navigation_type));
787   bool should_dispatch_beforeunload =
788       frame_tree_node->current_frame_host()->ShouldDispatchBeforeUnload(
789           true /* check_subframes_only */);
790   if (should_dispatch_beforeunload) {
791     frame_tree_node->navigation_request()->SetWaitingForRendererResponse();
792     frame_tree_node->current_frame_host()->DispatchBeforeUnload(
793         RenderFrameHostImpl::BeforeUnloadType::RENDERER_INITIATED_NAVIGATION,
794         NavigationTypeUtils::IsReload(
795             navigation_request->common_params().navigation_type));
796     return;
797   }
798 
799   // For main frames, NavigationHandle will be created after the call to
800   // |DidStartMainFrameNavigation|, so it receives the most up to date pending
801   // entry from the NavigationController.
802   navigation_request->BeginNavigation();
803   // DO NOT USE |navigation_request| BEYOND THIS POINT. It might have been
804   // destroyed in BeginNavigation().
805   // See https://crbug.com/770157.
806 }
807 
RestartNavigationAsCrossDocument(std::unique_ptr<NavigationRequest> navigation_request)808 void Navigator::RestartNavigationAsCrossDocument(
809     std::unique_ptr<NavigationRequest> navigation_request) {
810   FrameTreeNode* frame_tree_node = navigation_request->frame_tree_node();
811   // Don't restart the navigation if there is already another ongoing navigation
812   // in the FrameTreeNode.
813   if (frame_tree_node->navigation_request())
814     return;
815 
816   navigation_request->ResetForCrossDocumentRestart();
817   frame_tree_node->CreatedNavigationRequest(std::move(navigation_request));
818   frame_tree_node->navigation_request()->BeginNavigation();
819   // DO NOT USE THE NAVIGATION REQUEST BEYOND THIS POINT. It might have been
820   // destroyed in BeginNavigation().
821   // See https://crbug.com/770157.
822 }
823 
CancelNavigation(FrameTreeNode * frame_tree_node)824 void Navigator::CancelNavigation(FrameTreeNode* frame_tree_node) {
825   if (frame_tree_node->navigation_request())
826     frame_tree_node->navigation_request()->set_net_error(net::ERR_ABORTED);
827   frame_tree_node->ResetNavigationRequest(false);
828   if (frame_tree_node->IsMainFrame())
829     navigation_data_.reset();
830 }
831 
LogResourceRequestTime(base::TimeTicks timestamp,const GURL & url)832 void Navigator::LogResourceRequestTime(base::TimeTicks timestamp,
833                                        const GURL& url) {
834   if (navigation_data_ && navigation_data_->url_ == url) {
835     navigation_data_->url_job_start_time_ = timestamp;
836     UMA_HISTOGRAM_TIMES(
837         "Navigation.TimeToURLJobStart",
838         navigation_data_->url_job_start_time_ - navigation_data_->start_time_);
839   }
840 }
841 
LogBeforeUnloadTime(base::TimeTicks renderer_before_unload_start_time,base::TimeTicks renderer_before_unload_end_time,base::TimeTicks before_unload_sent_time)842 void Navigator::LogBeforeUnloadTime(
843     base::TimeTicks renderer_before_unload_start_time,
844     base::TimeTicks renderer_before_unload_end_time,
845     base::TimeTicks before_unload_sent_time) {
846   if (!navigation_data_)
847     return;
848 
849   // Only stores the beforeunload delay if we're tracking a browser initiated
850   // navigation and it happened later than the navigation request.
851   if (navigation_data_->is_browser_initiated_before_unload_ &&
852       renderer_before_unload_start_time > navigation_data_->start_time_) {
853     navigation_data_->before_unload_delay_ =
854         renderer_before_unload_end_time - renderer_before_unload_start_time;
855   }
856   // LogBeforeUnloadTime is called once for each cross-process frame. Once all
857   // beforeunloads complete, the timestamps in navigation_data will be the
858   // timestamps of the beforeunload that blocked the navigation the longest.
859   if (!base::TimeTicks::IsConsistentAcrossProcesses()) {
860     // These timestamps come directly from the renderer so they might need to be
861     // converted to local time stamps.
862     InterProcessTimeTicksConverter converter(
863         LocalTimeTicks::FromTimeTicks(before_unload_sent_time),
864         LocalTimeTicks::FromTimeTicks(base::TimeTicks::Now()),
865         RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time),
866         RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
867     LocalTimeTicks converted_renderer_before_unload_start =
868         converter.ToLocalTimeTicks(
869             RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time));
870     LocalTimeTicks converted_renderer_before_unload_end =
871         converter.ToLocalTimeTicks(
872             RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
873     navigation_data_->before_unload_start_ =
874         converted_renderer_before_unload_start.ToTimeTicks();
875     navigation_data_->before_unload_end_ =
876         converted_renderer_before_unload_end.ToTimeTicks();
877   } else {
878     navigation_data_->before_unload_start_ = renderer_before_unload_start_time;
879     navigation_data_->before_unload_end_ = renderer_before_unload_end_time;
880   }
881   navigation_data_->before_unload_sent_ = before_unload_sent_time;
882 }
883 
LogRendererInitiatedBeforeUnloadTime(base::TimeTicks renderer_before_unload_start_time,base::TimeTicks renderer_before_unload_end_time)884 void Navigator::LogRendererInitiatedBeforeUnloadTime(
885     base::TimeTicks renderer_before_unload_start_time,
886     base::TimeTicks renderer_before_unload_end_time) {
887   DCHECK(navigation_data_);
888 
889   if (renderer_before_unload_start_time == base::TimeTicks() ||
890       renderer_before_unload_end_time == base::TimeTicks())
891     return;
892 
893   if (!base::TimeTicks::IsConsistentAcrossProcesses()) {
894     // These timestamps come directly from the renderer so they might need to be
895     // converted to local time stamps.
896     InterProcessTimeTicksConverter converter(
897         LocalTimeTicks::FromTimeTicks(base::TimeTicks()),
898         LocalTimeTicks::FromTimeTicks(base::TimeTicks::Now()),
899         RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time),
900         RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
901     LocalTimeTicks converted_renderer_before_unload_start =
902         converter.ToLocalTimeTicks(
903             RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time));
904     LocalTimeTicks converted_renderer_before_unload_end =
905         converter.ToLocalTimeTicks(
906             RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
907     navigation_data_->renderer_before_unload_start_ =
908         converted_renderer_before_unload_start.ToTimeTicks();
909     navigation_data_->renderer_before_unload_end_ =
910         converted_renderer_before_unload_end.ToTimeTicks();
911   } else {
912     navigation_data_->renderer_before_unload_start_ =
913         renderer_before_unload_start_time;
914     navigation_data_->renderer_before_unload_end_ =
915         renderer_before_unload_end_time;
916   }
917 }
918 
RecordNavigationMetrics(const LoadCommittedDetails & details,const FrameHostMsg_DidCommitProvisionalLoad_Params & params,SiteInstance * site_instance)919 void Navigator::RecordNavigationMetrics(
920     const LoadCommittedDetails& details,
921     const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
922     SiteInstance* site_instance) {
923   DCHECK(site_instance->HasProcess());
924 
925   if (!details.is_main_frame || !navigation_data_ ||
926       navigation_data_->url_job_start_time_.is_null() ||
927       navigation_data_->url_ != params.original_request_url) {
928     return;
929   }
930 
931   ukm::builders::Unload builder(navigation_data_->ukm_source_id_);
932 
933   if (navigation_data_->is_browser_initiated_before_unload_) {
934     base::TimeDelta time_to_commit =
935         base::TimeTicks::Now() - navigation_data_->start_time_;
936     UMA_HISTOGRAM_TIMES("Navigation.TimeToCommit", time_to_commit);
937 
938     time_to_commit -= navigation_data_->before_unload_delay_;
939     base::TimeDelta time_to_network = navigation_data_->url_job_start_time_ -
940                                       navigation_data_->start_time_ -
941                                       navigation_data_->before_unload_delay_;
942     if (navigation_data_->is_restoring_from_last_session_) {
943       UMA_HISTOGRAM_TIMES(
944           "Navigation.TimeToCommit_SessionRestored_BeforeUnloadDiscounted",
945           time_to_commit);
946       UMA_HISTOGRAM_TIMES(
947           "Navigation.TimeToURLJobStart_SessionRestored_BeforeUnloadDiscounted",
948           time_to_network);
949       navigation_data_.reset();
950       return;
951     }
952     bool navigation_created_new_renderer_process =
953         site_instance->GetProcess()->GetInitTimeForNavigationMetrics() >
954         navigation_data_->start_time_;
955     if (navigation_created_new_renderer_process) {
956       UMA_HISTOGRAM_TIMES(
957           "Navigation.TimeToCommit_NewRenderer_BeforeUnloadDiscounted",
958           time_to_commit);
959       UMA_HISTOGRAM_TIMES(
960           "Navigation.TimeToURLJobStart_NewRenderer_BeforeUnloadDiscounted",
961           time_to_network);
962     } else {
963       UMA_HISTOGRAM_TIMES(
964           "Navigation.TimeToCommit_ExistingRenderer_BeforeUnloadDiscounted",
965           time_to_commit);
966       UMA_HISTOGRAM_TIMES(
967           "Navigation.TimeToURLJobStart_ExistingRenderer_"
968           "BeforeUnloadDiscounted",
969           time_to_network);
970     }
971     if (navigation_data_->before_unload_start_ &&
972         navigation_data_->before_unload_end_) {
973       builder.SetBeforeUnloadDuration(
974           (navigation_data_->before_unload_end_.value() -
975            navigation_data_->before_unload_start_.value())
976               .InMilliseconds());
977     }
978   } else {
979     if (navigation_data_->renderer_before_unload_start_ &&
980         navigation_data_->renderer_before_unload_end_) {
981       base::TimeDelta before_unload_duration =
982           navigation_data_->renderer_before_unload_end_.value() -
983           navigation_data_->renderer_before_unload_start_.value();
984 
985       // If we had to dispatch beforeunload handlers for OOPIFs from the
986       // browser, add those into the beforeunload duration as they contributed
987       // to the total beforeunload latency.
988       if (navigation_data_->before_unload_sent_) {
989         before_unload_duration +=
990             navigation_data_->before_unload_end_.value() -
991             navigation_data_->before_unload_start_.value();
992       }
993       builder.SetBeforeUnloadDuration(before_unload_duration.InMilliseconds());
994     }
995   }
996 
997   // Records the queuing duration of the beforeunload sent from the browser to
998   // the frame that blocked the navigation the longest. This can happen in a
999   // renderer or browser initiated navigation and could mean a long queuing time
1000   // blocked the navigation or a long beforeunload. Records nothing if none were
1001   // sent.
1002   if (navigation_data_->before_unload_sent_) {
1003     builder.SetBeforeUnloadQueueingDuration(
1004         (navigation_data_->before_unload_start_.value() -
1005          navigation_data_->before_unload_sent_.value())
1006             .InMilliseconds());
1007   }
1008 
1009   builder.Record(ukm::UkmRecorder::Get());
1010   navigation_data_.reset();
1011 }
1012 
1013 NavigationEntryImpl*
GetNavigationEntryForRendererInitiatedNavigation(const mojom::CommonNavigationParams & common_params,FrameTreeNode * frame_tree_node)1014 Navigator::GetNavigationEntryForRendererInitiatedNavigation(
1015     const mojom::CommonNavigationParams& common_params,
1016     FrameTreeNode* frame_tree_node) {
1017   if (!frame_tree_node->IsMainFrame())
1018     return nullptr;
1019 
1020   // If there is no browser-initiated pending entry for this navigation and it
1021   // is not for the error URL, create a pending entry and ensure the address bar
1022   // updates accordingly.  We don't know the referrer or extra headers at this
1023   // point, but the referrer will be set properly upon commit.  This does not
1024   // set the SiteInstance for the pending entry, because it may change
1025   // before the URL commits.
1026   NavigationEntryImpl* pending_entry = controller_->GetPendingEntry();
1027   bool has_browser_initiated_pending_entry =
1028       pending_entry && !pending_entry->is_renderer_initiated();
1029   if (has_browser_initiated_pending_entry)
1030     return nullptr;
1031 
1032   // A pending navigation entry is created in OnBeginNavigation(). The renderer
1033   // sends a provisional load notification after that. We don't want to create
1034   // a duplicate navigation entry here.
1035   bool renderer_provisional_load_to_pending_url =
1036       pending_entry && pending_entry->is_renderer_initiated() &&
1037       (pending_entry->GetURL() == common_params.url);
1038   if (renderer_provisional_load_to_pending_url)
1039     return nullptr;
1040 
1041   // Since GetNavigationEntryForRendererInitiatedNavigation is called from
1042   // OnBeginNavigation, we can assume that no frame proxies are involved and
1043   // therefore that |current_site_instance| is also the |source_site_instance|.
1044   SiteInstance* current_site_instance =
1045       frame_tree_node->current_frame_host()->GetSiteInstance();
1046   SiteInstance* source_site_instance = current_site_instance;
1047 
1048   std::unique_ptr<NavigationEntryImpl> entry =
1049       NavigationEntryImpl::FromNavigationEntry(
1050           NavigationControllerImpl::CreateNavigationEntry(
1051               common_params.url, content::Referrer(),
1052               common_params.initiator_origin, source_site_instance,
1053               ui::PAGE_TRANSITION_LINK, true /* is_renderer_initiated */,
1054               std::string() /* extra_headers */,
1055               controller_->GetBrowserContext(),
1056               nullptr /* blob_url_loader_factory */,
1057               common_params.should_replace_current_entry,
1058               controller_->GetWebContents()));
1059   entry->set_reload_type(NavigationRequest::NavigationTypeToReloadType(
1060       common_params.navigation_type));
1061 
1062   controller_->SetPendingEntry(std::move(entry));
1063   if (delegate_)
1064     delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
1065 
1066   return controller_->GetPendingEntry();
1067 }
1068 
1069 }  // namespace content
1070