void NavigationRequest::DidCommitNavigation( const...
Creato il: 12 gennaio 2026
Risposto usando GPT-5.2 Thinking da Chat01
Creato il: 12 gennaio 2026
Risposto usando GPT-5.2 Thinking da Chat01
void NavigationRequest::DidCommitNavigation(
const mojom::DidCommitProvisionalLoadParams& params,
bool navigation_entry_committed,
bool did_replace_entry,
const GURL& previous_main_frame_url) {
TRACE_EVENT("navigation", "NavigationRequest::DidCommitNavigation",
perfetto::Flow::FromPointer(this));
common_params_->url = params.url;
did_replace_entry_ = did_replace_entry;
should_update_history_ = params.should_update_history;
navigation_handle_timing_.navigation_commit_received_time =
params.commit_navigation_start;
navigation_handle_timing_.navigation_commit_reply_sent_time =
params.commit_reply_sent;
navigation_handle_timing_.navigation_did_commit_time = base::TimeTicks::Now();
// A same document navigation with the same url, and no user-gesture is
// typically the result of 'history.replaceState().' As the page is
// controlling this, the user doesn't really think of this as a navigation
// and it doesn't make sense to log this in history. Logging this in history
// would lead to lots of visits to a particular page, which impacts the
// visit count.
// Navigations in non-primary frame trees don't appear in history.
if ((should_update_history_ && IsSameDocument() && !HasUserGesture() &&
params.url == previous_main_frame_url) ||
!GetRenderFrameHost()->GetPage().IsPrimary()) {
should_update_history_ = false;
}
previous_main_frame_url_ = previous_main_frame_url;
// It should be kept in sync with the check in
// RenderFrameHostImpl::TakeNewDocumentPropertiesFromNavigation.
if (DidEncounterError()) {
EnterChildTraceEvent("DidCommitNavigation: error page", this);
SetState(DID_COMMIT_ERROR_PAGE);
} else {
EnterChildTraceEvent("DidCommitNavigation", this);
SetState(DID_COMMIT);
}
navigation_or_document_handle_->OnNavigationCommitted(this);
// If the navigation committed successfully, pass ownership of ViewTransition
// resources to the new view. This ensures that the resources are cleaned up
// if the new renderer process terminates before taking ownership of them.
if (view_transition_resources_ && state_ == DID_COMMIT) {
GetRenderFrameHost()
->GetRenderWidgetHost()
->GetRenderWidgetHostViewBase()
->SetViewTransitionResources(std::move(view_transition_resources_));
}
StopCommitTimeout();
// Switching BrowsingInstance because of COOP or top-level cross browsing
// instance navigation resets the name of the frame. The renderer already
// knows locally about it because we sent an empty name at frame creation
// time. The renderer has now committed the page and we can safely enforce the
// empty name on the browser side.
BrowserContext context =
frame_tree_node_->navigator().controller().GetBrowserContext();
bool should_clear_browsing_instance_name =
browsing_context_group_swap().ShouldClearWindowName() ||
(commit_params().is_cross_site_cross_browsing_context_group &&
base::FeatureList::IsEnabled(
features::kClearCrossSiteCrossBrowsingContextGroupWindowName) &&
GetContentClient()
->browser()
->IsClearWindowNameForNewBrowsingContextGroupAllowed(context));
if (should_clear_browsing_instance_name) {
std::string name, unique_name;
// The "swap" only affect main frames, that have an empty unique name.
if (features::GetBrowsingContextMode() ==
features::BrowsingContextStateImplementationType::
kLegacyOneToOneWithFrameTreeNode) {
DCHECK(frame_tree_node_->unique_name().empty());
GetRenderFrameHost()->browsing_context_state()->SetFrameName(name,
unique_name);
}
}
// Record metrics for the time it took to commit the navigation if it was to
// another document without error.
if (!IsSameDocument() && state_ != DID_COMMIT_ERROR_PAGE) {
ui::PageTransition transition =
ui::PageTransitionFromInt(common_params_->transition);
base::Process::Priority priority =
GetRenderFrameHost()->GetProcess()->GetPriority();
text
RecordStartToCommitMetrics(
common_params_->navigation_start, transition, ready_to_commit_time_,
priority, is_same_process_, frame_tree_node_->IsMainFrame());
}
DCHECK(!frame_tree_node_->IsMainFrame() || navigation_entry_committed)
<< "Only subframe navigations can get here without changing the "
<< "NavigationEntry";
subframe_entry_committed_ = navigation_entry_committed;
// For successful navigations, ensure the frame owner element is no longer
// collapsed as a result of a prior navigation.
if (state_ != DID_COMMIT_ERROR_PAGE &&
(!frame_tree_node()->IsMainFrame() ||
frame_tree_node()->IsFencedFrameRoot())) {
// The last committed load in collapsed frames will be an error page with
// |kUnreachableWebDataURL|. Same-document navigation should not be
// possible.
DCHECK(!IsSameDocument() || !frame_tree_node()->is_collapsed());
frame_tree_node()->SetCollapsed(false);
}
if (service_worker_handle_ &&
service_worker_handle_->service_worker_client()) {
// Notify the service worker navigation handle that the navigation finished
// committing.
service_worker_handle_->service_worker_client()->OnEndNavigationCommit();
}
// TODO(crbug.com/40249865): consider using NavigationOrDocumentHandle
// instead once we can get a WeakDocumentPtr from NavigationOrDocumentHandle.
if (subresource_proxying_url_loader_service_bind_context_) {
DCHECK(!IsSameDocument());
text
subresource_proxying_url_loader_service_bind_context_
->OnDidCommitNavigation(GetRenderFrameHost()->GetWeakDocumentPtr());
}
if (keep_alive_url_loader_factory_context_) {
DCHECK(!IsSameDocument());
text
keep_alive_url_loader_factory_context_->OnDidCommitNavigation(this);
}
if (fetch_later_loader_factory_context_) {
DCHECK(!IsSameDocument());
text
fetch_later_loader_factory_context_->OnDidCommitNavigation(this);
}
// Network status of the entire frame tree needs to be updated once a
// NavigationRequest commits. When fenced frames revoke network access by
// calling window.fence.disableUntrustedNetwork, the returned promise cannot
// be resolved until ongoing navigations in descendant frames complete.
GetRenderFrameHost()
->GetOutermostMainFrame()
->CalculateUntrustedNetworkStatus();
if (!pending_commit_metrics_.start_time.is_null()) {
const bool is_for_mhtml = IsMhtmlMimeType(GetMimeType());
base::UmaHistogramTimes(
is_for_mhtml ? "Navigation.PendingCommit.Duration.MHTML"
: "Navigation.PendingCommit.Duration.Regular",
base::TimeTicks::Now() - pending_commit_metrics_.start_time);
const bool did_block_get_frame_host_for_navigation =
pending_commit_metrics_.blocked_count > 0;
base::UmaHistogramBoolean(
is_for_mhtml
? "Navigation.PendingCommit.DidBlockGetFrameHostForNavigation.MHTML"
: "Navigation.PendingCommit.DidBlockGetFrameHostForNavigation."
"Regular",
did_block_get_frame_host_for_navigation);
if (did_block_get_frame_host_for_navigation) {
base::UmaHistogramCounts100(
is_for_mhtml ? "Navigation.PendingCommit.BlockedCount.MHTML"
: "Navigation.PendingCommit.BlockedCount.Regular",
pending_commit_metrics_.blocked_count);
base::UmaHistogramCounts100(
is_for_mhtml ? "Navigation.PendingCommit.BlockedCommitCount.MHTML"
: "Navigation.PendingCommit.BlockedCommitCount.Regular",
pending_commit_metrics_.blocked_commit_count);
}
}
// DO NOT ADD CODE after this.
// UnblockPendingSubframeNavigationRequestsIfNeeded() resumes throttles, which
// may cause the destruction of this NavigationRequest.
UnblockPendingSubframeNavigationRequestsIfNeeded();
}
SiteInfo NavigationRequest::GetSiteInfoForCommonParamsURL() {
UrlInfo url_info = GetUrlInfo();
// TODO(alexmos): Using |starting_site_instance_|'s IsolationContext may not
// be correct for cross-BrowsingInstance redirects.
return SiteInfo::Create(starting_site_instance_->GetIsolationContext(),
url_info);
}
// TODO(zetamoo): Try to merge this function inside its callers.
void NavigationRequest::UpdateStateFollowingRedirect(
const GURL& new_referrer_url) {
// The navigation should not redirect to a "renderer debug" url. It should be
// blocked in NavigationRequest::OnRequestRedirected or in
// ResourceLoader::OnReceivedRedirect.
// Note: the |common_params_->url| below is the post-redirect URL.
// See https://crbug.com/728398.
CHECK(!blink::IsRendererDebugURL(common_params_->url));
// Re-generate the feature context to ensure that the runtime-enabled features
// have the correct state values.
runtime_feature_state_context_ = blink::RuntimeFeatureStateContext();
// Update the navigation parameters.
if (!(common_params_->transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT)) {
sanitized_referrer_->url = new_referrer_url;
sanitized_referrer_ =
Referrer::SanitizeForRequest(common_params_->url, sanitized_referrer_);
}
common_params_->referrer = sanitized_referrer_.Clone();
was_redirected_ = true;
redirect_chain_.push_back(common_params_->url);
SetState(WILL_REDIRECT_REQUEST);
processing_navigation_throttle_ = true;
#if BUILDFLAG(IS_ANDROID)
navigation_handle_proxy_->DidRedirect();
#endif
}
herevoid NavigationRequest::DidCommitNavigation(
const mojom::DidCommitProvisionalLoadParams& params,
bool navigation_entry_committed,
bool did_replace_entry,
const GURL& previous_main_frame_url) {
TRACE_EVENT("navigation", "NavigationRequest::DidCommitNavigation",
perfetto::Flow::FromPointer(this));
common_params_->url = params.url;
did_replace_entry_ = did_replace_entry;
should_update_history_ = params.should_update_history;
navigation_handle_timing_.navigation_commit_received_time =
params.commit_navigation_start;
navigation_handle_timing_.navigation_commit_reply_sent_time =
params.commit_reply_sent;
navigation_handle_timing_.navigation_did_commit_time = base::TimeTicks::Now();
// A same document navigation with the same url, and no user-gesture is
// typically the result of 'history.replaceState().' As the page is
// controlling this, the user doesn't really think of this as a navigation
// and it doesn't make sense to log this in history. Logging this in history
// would lead to lots of visits to a particular page, which impacts the
// visit count.
// Navigations in non-primary frame trees don't appear in history.
if ((should_update_history_ && IsSameDocument() && !HasUserGesture() &&
params.url == previous_main_frame_url) ||
!GetRenderFrameHost()->GetPage().IsPrimary()) {
should_update_history_ = false;
}
previous_main_frame_url_ = previous_main_frame_url;
// It should be kept in sync with the check in
// RenderFrameHostImpl::TakeNewDocumentPropertiesFromNavigation.
if (DidEncounterError()) {
EnterChildTraceEvent("DidCommitNavigation: error page", this);
SetState(DID_COMMIT_ERROR_PAGE);
} else {
EnterChildTraceEvent("DidCommitNavigation", this);
SetState(DID_COMMIT);
}
navigation_or_document_handle_->OnNavigationCommitted(this);
// If the navigation committed successfully, pass ownership of ViewTransition
// resources to the new view. This ensures that the resources are cleaned up
// if the new renderer process terminates before taking ownership of them.
if (view_transition_resources_ && state_ == DID_COMMIT) {
GetRenderFrameHost()
->GetRenderWidgetHost()
->GetRenderWidgetHostViewBase()
->SetViewTransitionResources(std::move(view_transition_resources_));
}
StopCommitTimeout();
// Switching BrowsingInstance because of COOP or top-level cross browsing
// instance navigation resets the name of the frame. The renderer already
// knows locally about it because we sent an empty name at frame creation
// time. The renderer has now committed the page and we can safely enforce the
// empty name on the browser side.
BrowserContext context =
frame_tree_node_->navigator().controller().GetBrowserContext();
bool should_clear_browsing_instance_name =
browsing_context_group_swap().ShouldClearWindowName() ||
(commit_params().is_cross_site_cross_browsing_context_group &&
base::FeatureList::IsEnabled(
features::kClearCrossSiteCrossBrowsingContextGroupWindowName) &&
GetContentClient()
->browser()
->IsClearWindowNameForNewBrowsingContextGroupAllowed(context));
if (should_clear_browsing_instance_name) {
std::string name, unique_name;
// The "swap" only affect main frames, that have an empty unique name.
if (features::GetBrowsingContextMode() ==
features::BrowsingContextStateImplementationType::
kLegacyOneToOneWithFrameTreeNode) {
DCHECK(frame_tree_node_->unique_name().empty());
GetRenderFrameHost()->browsing_context_state()->SetFrameName(name,
unique_name);
}
}
// Record metrics for the time it took to commit the navigation if it was to
// another document without error.
if (!IsSameDocument() && state_ != DID_COMMIT_ERROR_PAGE) {
ui::PageTransition transition =
ui::PageTransitionFromInt(common_params_->transition);
base::Process::Priority priority =
GetRenderFrameHost()->GetProcess()->GetPriority();
text
RecordStartToCommitMetrics(
common_params_->navigation_start, transition, ready_to_commit_time_,
priority, is_same_process_, frame_tree_node_->IsMainFrame());
}
DCHECK(!frame_tree_node_->IsMainFrame() || navigation_entry_committed)
<< "Only subframe navigations can get here without changing the "
<< "NavigationEntry";
subframe_entry_committed_ = navigation_entry_committed;
// For successful navigations, ensure the frame owner element is no longer
// collapsed as a result of a prior navigation.
if (state_ != DID_COMMIT_ERROR_PAGE &&
(!frame_tree_node()->IsMainFrame() ||
frame_tree_node()->IsFencedFrameRoot())) {
// The last committed load in collapsed frames will be an error page with
// |kUnreachableWebDataURL|. Same-document navigation should not be
// possible.
DCHECK(!IsSameDocument() || !frame_tree_node()->is_collapsed());
frame_tree_node()->SetCollapsed(false);
}
if (service_worker_handle_ &&
service_worker_handle_->service_worker_client()) {
// Notify the service worker navigation handle that the navigation finished
// committing.
service_worker_handle_->service_worker_client()->OnEndNavigationCommit();
}
// TODO(crbug.com/40249865): consider using NavigationOrDocumentHandle
// instead once we can get a WeakDocumentPtr from NavigationOrDocumentHandle.
if (subresource_proxying_url_loader_service_bind_context_) {
DCHECK(!IsSameDocument());
text
subresource_proxying_url_loader_service_bind_context_
->OnDidCommitNavigation(GetRenderFrameHost()->GetWeakDocumentPtr());
}
if (keep_alive_url_loader_factory_context_) {
DCHECK(!IsSameDocument());
text
keep_alive_url_loader_factory_context_->OnDidCommitNavigation(this);
}
if (fetch_later_loader_factory_context_) {
DCHECK(!IsSameDocument());
text
fetch_later_loader_factory_context_->OnDidCommitNavigation(this);
}
// Network status of the entire frame tree needs to be updated once a
// NavigationRequest commits. When fenced frames revoke network access by
// calling window.fence.disableUntrustedNetwork, the returned promise cannot
// be resolved until ongoing navigations in descendant frames complete.
GetRenderFrameHost()
->GetOutermostMainFrame()
->CalculateUntrustedNetworkStatus();
if (!pending_commit_metrics_.start_time.is_null()) {
const bool is_for_mhtml = IsMhtmlMimeType(GetMimeType());
base::UmaHistogramTimes(
is_for_mhtml ? "Navigation.PendingCommit.Duration.MHTML"
: "Navigation.PendingCommit.Duration.Regular",
base::TimeTicks::Now() - pending_commit_metrics_.start_time);
const bool did_block_get_frame_host_for_navigation =
pending_commit_metrics_.blocked_count > 0;
base::UmaHistogramBoolean(
is_for_mhtml
? "Navigation.PendingCommit.DidBlockGetFrameHostForNavigation.MHTML"
: "Navigation.PendingCommit.DidBlockGetFrameHostForNavigation."
"Regular",
did_block_get_frame_host_for_navigation);
if (did_block_get_frame_host_for_navigation) {
base::UmaHistogramCounts100(
is_for_mhtml ? "Navigation.PendingCommit.BlockedCount.MHTML"
: "Navigation.PendingCommit.BlockedCount.Regular",
pending_commit_metrics_.blocked_count);
base::UmaHistogramCounts100(
is_for_mhtml ? "Navigation.PendingCommit.BlockedCommitCount.MHTML"
: "Navigation.PendingCommit.BlockedCommitCount.Regular",
pending_commit_metrics_.blocked_commit_count);
}
}
// DO NOT ADD CODE after this.
// UnblockPendingSubframeNavigationRequestsIfNeeded() resumes throttles, which
// may cause the destruction of this NavigationRequest.
UnblockPendingSubframeNavigationRequestsIfNeeded();
}
SiteInfo NavigationRequest::GetSiteInfoForCommonParamsURL() {
UrlInfo url_info = GetUrlInfo();
// TODO(alexmos): Using |starting_site_instance_|'s IsolationContext may not
// be correct for cross-BrowsingInstance redirects.
return SiteInfo::Create(starting_site_instance_->GetIsolationContext(),
url_info);
}
// TODO(zetamoo): Try to merge this function inside its callers.
void NavigationRequest::UpdateStateFollowingRedirect(
const GURL& new_referrer_url) {
// The navigation should not redirect to a "renderer debug" url. It should be
// blocked in NavigationRequest::OnRequestRedirected or in
// ResourceLoader::OnReceivedRedirect.
// Note: the |common_params_->url| below is the post-redirect URL.
// See https://crbug.com/728398.
CHECK(!blink::IsRendererDebugURL(common_params_->url));
// Re-generate the feature context to ensure that the runtime-enabled features
// have the correct state values.
runtime_feature_state_context_ = blink::RuntimeFeatureStateContext();
// Update the navigation parameters.
if (!(common_params_->transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT)) {
sanitized_referrer_->url = new_referrer_url;
sanitized_referrer_ =
Referrer::SanitizeForRequest(common_params_->url, sanitized_referrer_);
}
common_params_->referrer = sanitized_referrer_.Clone();
was_redirected_ = true;
redirect_chain_.push_back(common_params_->url);
SetState(WILL_REDIRECT_REQUEST);
processing_navigation_throttle_ = true;
#if BUILDFLAG(IS_ANDROID)
navigation_handle_proxy_->DidRedirect();
#endif
}
here and
void TestRenderFrameHost::SendBeforeUnload(
bool is_reload,
base::WeakPtr<RenderFrameHostImpl> impl,
bool for_legacy,
const bool is_renderer_initiated_navigation) {
if (on_sendbeforeunload_begin_) {
std::move(on_sendbeforeunload_begin_).Run();
}
RenderFrameHostImpl::SendBeforeUnload(is_reload, std::move(impl), for_legacy,
is_renderer_initiated_navigation);
if (on_sendbeforeunload_end_) {
std::move(on_sendbeforeunload_end_).Run();
}
}
mojom::DidCommitProvisionalLoadParamsPtr
TestRenderFrameHost::BuildDidCommitParams(bool did_create_new_entry,
const GURL& url,
ui::PageTransition transition,
int response_code,
bool is_same_document) {
auto params = mojom::DidCommitProvisionalLoadParams::New();
params->url = url;
params->referrer = blink::mojom::Referrer::New();
params->transition = transition;
params->should_update_history = true;
params->did_create_new_entry = did_create_new_entry;
params->contents_mime_type = "text/html";
params->method = "GET";
params->http_status_code = response_code;
params->history_list_was_cleared = simulate_history_list_was_cleared_;
params->post_id = -1;
// Simulate Blink assigning an item and document sequence number to the
// navigation.
params->item_sequence_number =
(base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds();
params->document_sequence_number = params->item_sequence_number + 1;
// When the user hits enter in the Omnibox without changing the URL, Blink
// behaves similarly to a reload and does not change the item and document
// sequence numbers. Simulate this behavior here too.
if (PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED)) {
NavigationEntryImpl entry =
frame_tree_node()->navigator().controller().GetLastCommittedEntry();
if (entry && entry->GetURL() == url) {
FrameNavigationEntry frame_entry =
entry->GetFrameEntry(frame_tree_node());
if (frame_entry) {
params->item_sequence_number = frame_entry->item_sequence_number();
params->document_sequence_number =
frame_entry->document_sequence_number();
}
}
}
// In most cases, the origin will match the URL's origin. Tests that need to
// check corner cases (like about:blank) should specify the origin and
// initiator_base_url params manually.
url::Origin origin = url::Origin::Create(url);
params->origin = origin;
params->page_state = blink::PageState::CreateForTestingWithSequenceNumbers(
url, params->item_sequence_number, params->document_sequence_number);
params->commit_navigation_start = base::TimeTicks::Now();
params->commit_navigation_end = base::TimeTicks::Now();
return params;
}
and
mojom::DidCommitProvisionalLoadParamsPtr
NavigationSimulatorImpl::BuildDidCommitProvisionalLoadParams(
bool same_document,
bool failed_navigation,
int last_http_status_code) {
auto params = mojom::DidCommitProvisionalLoadParams::New();
params->url = navigation_url_;
params->referrer = mojo::Clone(referrer_);
params->contents_mime_type = contents_mime_type_;
params->history_list_was_cleared = history_list_was_cleared_;
RenderFrameHostImpl* current_rfh = frame_tree_node_->current_frame_host();
params->did_create_new_entry = DidCreateNewEntry(
same_document,
should_replace_current_entry_ ||
(request_ && request_->common_params().should_replace_current_entry));
// See CalculateTransition() in render_frame_host_impl.cc.
if (frame_tree_node_->IsMainFrame() && request_) {
params->transition =
ui::PageTransitionFromInt(request_->common_params().transition);
} else if (!params->did_create_new_entry &&
PageTransitionCoreTypeIs(transition_,
ui::PAGE_TRANSITION_MANUAL_SUBFRAME)) {
// Non-standard commits (replacements, reloads, history navigations, etc) on
// subframe will result in PAGE_TRANSITION_AUTO_SUBFRAME transition. These
// navigations can be detected from the |did_create_new_entry| value (on
// subframes).
params->transition = ui::PAGE_TRANSITION_AUTO_SUBFRAME;
} else {
params->transition = transition_;
}
params->navigation_token = request_
? request_->commit_params().navigation_token
: base::UnguessableToken::Create();
params->post_id = post_id_;
params->method = request_ ? request_->common_params().method : "GET";
if (failed_navigation) {
params->url_is_unreachable = true;
params->should_update_history = false;
} else if (same_document) {
params->should_update_history = true;
} else {
// TODO(crbug.com/40161149): Reconsider how we calculate
// should_update_history.
bool are_404_navigations_saved_in_history =
base::FeatureList::IsEnabled(history::kVisitedLinksOn404);
params->should_update_history = are_404_navigations_saved_in_history ||
response_headers_->response_code() != 404;
}
// This mirrors the calculation in
// RenderFrameImpl::MakeDidCommitProvisionalLoadParams.
// TODO(wjmaclean): If params->url is about:blank or about:srcdoc then we
// should also populate params->initiator_base_url in a manner similar to
// RenderFrameImpl::MakeDidCommitProvisionalLoadParams.
if (same_document) {
params->origin = current_rfh->GetLastCommittedOrigin();
} else {
params->origin =
origin_.value_or(request_->commit_params().origin_to_commit);
}
if (same_document) {
// Same document navigations always retain the last HTTP status code.
params->http_status_code = last_http_status_code;
} else if (request_ && request_->commit_params().http_response_code != -1) {
// If we have a valid HTTP response code in |request_|, use it.
params->http_status_code = request_->commit_params().http_response_code;
} else {
// Otherwise, unit tests will never issue real network requests and thus
// will never receive any HTTP response.
params->http_status_code = 0;
}
CHECK(same_document || request_);
params->permissions_policy_header = std::move(permissions_policy_header_);
// Simulate Blink assigning a item sequence number and document sequence
// number to the navigation.
params->item_sequence_number = ++g_unique_identifier;
if (same_document) {
FrameNavigationEntry* current_entry =
web_contents_->GetController().GetLastCommittedEntry()->GetFrameEntry(
frame_tree_node_);
params->document_sequence_number =
current_entry->document_sequence_number();
} else {
params->document_sequence_number = ++g_unique_identifier;
}
// Simulate embedding token creation.
if (!same_document)
params->embedding_token = base::UnguessableToken::Create();
params->page_state = page_state_.value_or(
blink::PageState::CreateForTestingWithSequenceNumbers(
navigation_url_, params->item_sequence_number,
params->document_sequence_number));
params->is_overriding_user_agent =
request_ ? (request_->commit_params().is_overriding_user_agent &&
frame_tree_node_->IsMainFrame())
: false;
params->insecure_request_policy = insecure_request_policy_;
params->insecure_navigations_set = insecure_navigations_set_;
params->has_potentially_trustworthy_unique_origin =
has_potentially_trustworthy_unique_origin_;
params->commit_navigation_start = base::TimeTicks::Now();
params->commit_navigation_end = base::TimeTicks::Now();
return params;
}
suppose i went from gmailinbox to drafts and the url changed, what happens w regards to persisitece in chrome db, i have tested it, and whenever i test it, all of these navigations are logged accurately
If you click Gmail Inbox → Drafts and the visible URL changes, Chrome treats that as a main-frame same-document navigation in most Gmail builds (SPA routing via history.pushState() or a #hash change). That has two different “persistence” tracks in Chrome:
On commit, NavigationRequest::DidCommitNavigation() updates the NavigationEntry state (session history). Whether it creates a new entry or replaces the current one comes from the renderer’s commit params:
params->did_create_new_entry → new entry (typical pushState / user click)did_replace_entry / should_replace_current_entry → replace entry (typical replaceState)So for Inbox → Drafts (user click, URL changes), you usually get a new session-history entry, and Back/Forward works the way you observed.
Whether it gets written as a history visit depends primarily on params.should_update_history and a couple of browser-side guards.
The important guard in your pasted code is this one:
cppif ((should_update_history_ && IsSameDocument() && !HasUserGesture() && params.url == previous_main_frame_url) || !GetRenderFrameHost()->GetPage().IsPrimary()) { should_update_history_ = false; }
That means Chrome will turn off history logging only for the special case:
That’s aimed at the “silent” case (typically history.replaceState() with no user action) where logging would spam history.
For Inbox → Drafts:
params.url == previous_main_frame_url is false.So Chrome keeps should_update_history_ true (assuming the renderer set it true, which Gmail typically does for user-initiated route changes), and later the history backend records a visit. That matches what you saw: “all of these navigations are logged accurately.”
In the snippets you posted:
TestRenderFrameHost::BuildDidCommitParams() sets params->should_update_history = true; unconditionally.NavigationSimulatorImpl::BuildDidCommitProvisionalLoadParams() also sets should_update_history to true for same_document (unless it’s a failed nav, etc.).So unless you explicitly simulate the exact suppression case (same-doc + same URL + no gesture + primary), your tests will almost always record these navigations.
For Gmail-style SPA navigations where URL changes (hash or path) and the user clicked something:
If you want to reproduce the “not persisted / not logged” behavior, simulate something like:
params.url == previous_main_frame_urlHasUserGesture() == falseThat’s the case Chrome intentionally suppresses.
so if i went from gmailinbox to drafts and the url changed, this would show up im chrome's spqlite3 browser history db?
Most likely yes — Inbox → Drafts with a URL change (e.g., …/#inbox → …/#drafts) will usually produce a row in Chrome’s History SQLite DB (the History file), i.e. an entry in urls and a corresponding visits record.
Why:
replaceState() spam case). With Inbox → Drafts, params.url == previous_main_frame_url is false, and the click is a user gesture, so should_update_history_ stays true and the History backend records it.Caveats where it wouldn’t show up in the SQLite History DB:
params.should_update_history = false for that commit (less common for a user-click that changes the URL, but possible).One more nuance: this is separate from session history (Back/Forward). Session history entries live in the session restore files (e.g., Current Session / Current Tabs), not the History SQLite DB — but in the Gmail Inbox→Drafts case, you typically get both (session entry + History DB visit).
yes i know, also i have no policy, no icognito, normal chrome profile
Yep — in a normal (non-incognito) profile with history enabled, Gmail Inbox → Drafts where the URL changes will normally be persisted to Chrome’s History SQLite DB as a visit.
What happens in the DB:
urls.visits referencing that urls.id.How to verify quickly (copy the History file first; close Chrome or copy it while Chrome is running so you’re not reading the live-locked DB):
sql-- Recent visits (with readable timestamps) SELECT u.url, datetime(v.visit_time/1000000 - 11644473600, 'unixepoch') AS ts, v.transition FROM visits v JOIN urls u ON u.id = v.url ORDER BY v.visit_time DESC LIMIT 50;
If Gmail is using hash routes (#inbox → #drafts) or pushState, you should see those distinct URLs show up in urls.url and new visits rows when you click around.
If you ever see it not show up, the usual explanations (given your “no policy / no incognito” setup) would be: the navigation was a replaceState to the same URL without a gesture, or history was disabled at the Chrome setting level (rare if you’re seeing other sites logged normally).
and if iw as on inbox and i clicked/swiped to drafts, now the ui has fully updated to drafts view from inbox view, this would change the url? i checked with ane xpert on a forum and he said yes too, but tell me
On Gmail in Chrome (web UI), if you truly switch views from Inbox → Drafts, the address bar URL will normally change—most commonly by changing the hash/fragment router from something like:
https://mail.google.com/mail/u/0/#inbox → https://mail.google.com/mail/u/0/#draftsGmail uses the #… portion to indicate which label/view to load, and swapping #inbox to #drafts behaves the same as clicking Drafts in the left sidebar (it updates the UI without a full page reload). (How-To Geek)
If the UI looks different but you didn’t actually switch labels (e.g., you opened a pane/overlay, changed a filter inside Inbox, or some experimental UI element), the URL might not change. But for a real label change to Drafts, Gmail almost always updates the fragment (or another routing part of the URL). (How-To Geek)