blob: 9648dfb34ed5f8a4bebfbc2c6fafdeef8c79e422 [file] [log] [blame]
Harkiran Bolaria8dec6f92021-12-07 14:57:121// Copyright (c) 2021 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/browsing_context_state.h"
6
David Sanders27d32052022-04-04 18:08:197#include "base/memory/ptr_util.h"
Harkiran Bolaria2912a6b32022-02-22 16:43:458#include "content/browser/renderer_host/frame_tree_node.h"
Harkiran Bolaria3f83fba72022-03-10 17:48:409#include "content/browser/renderer_host/render_frame_host_impl.h"
Harkiran Bolaria2912a6b32022-02-22 16:43:4510#include "content/browser/renderer_host/render_view_host_impl.h"
11#include "content/common/content_navigation_policy.h"
Harkiran Bolaria5ce27632022-01-20 15:05:0512#include "services/network/public/cpp/web_sandbox_flags.h"
13#include "services/network/public/mojom/web_sandbox_flags.mojom.h"
14
Harkiran Bolaria8dec6f92021-12-07 14:57:1215namespace features {
16const base::Feature kNewBrowsingContextStateOnBrowsingContextGroupSwap{
17 "NewBrowsingContextStateOnBrowsingContextGroupSwap",
18 base::FEATURE_DISABLED_BY_DEFAULT};
19
20BrowsingContextStateImplementationType GetBrowsingContextMode() {
21 if (base::FeatureList::IsEnabled(
22 kNewBrowsingContextStateOnBrowsingContextGroupSwap)) {
23 return BrowsingContextStateImplementationType::
24 kSwapForCrossBrowsingInstanceNavigations;
25 }
26
27 return BrowsingContextStateImplementationType::
28 kLegacyOneToOneWithFrameTreeNode;
29}
30} // namespace features
31
32namespace content {
33
Harkiran Bolariaa8347782022-04-06 09:25:1134using perfetto::protos::pbzero::ChromeTrackEvent;
35
Harkiran Bolaria4eacb3a2021-12-13 20:03:4736BrowsingContextState::BrowsingContextState(
Harkiran Bolaria880a7632022-02-28 16:02:5037 blink::mojom::FrameReplicationStatePtr replication_state,
Harkiran Bolaria0b3bdef02022-03-10 13:04:4038 raw_ptr<RenderFrameHostImpl> parent,
39 absl::optional<BrowsingInstanceId> browsing_instance_id)
40 : replication_state_(std::move(replication_state)),
41 parent_(parent),
Harkiran Bolariaa8347782022-04-06 09:25:1142 browsing_instance_id_(browsing_instance_id) {
43 TRACE_EVENT_BEGIN("navigation", "BrowsingContextState",
44 perfetto::Track::FromPointer(this),
45 "browsing_context_state_when_created", this);
46}
Harkiran Bolaria8dec6f92021-12-07 14:57:1247
Harkiran Bolariaa8347782022-04-06 09:25:1148BrowsingContextState::~BrowsingContextState() {
49 TRACE_EVENT_END("navigation", perfetto::Track::FromPointer(this));
50}
Harkiran Bolaria4eacb3a2021-12-13 20:03:4751
Harkiran Bolaria5ce27632022-01-20 15:05:0552RenderFrameProxyHost* BrowsingContextState::GetRenderFrameProxyHost(
Harkiran Bolariae45272d2022-04-12 08:05:0153 SiteInstanceGroup* site_instance_group,
54 ProxyAccessMode proxy_access_mode) const {
Harkiran Bolariaa8347782022-04-06 09:25:1155 TRACE_EVENT_BEGIN("navigation",
56 "BrowsingContextState::GetRenderFrameProxyHost",
57 ChromeTrackEvent::kBrowsingContextState, this,
58 ChromeTrackEvent::kSiteInstanceGroup, site_instance_group);
Harkiran Bolariae45272d2022-04-12 08:05:0159 auto* proxy =
60 GetRenderFrameProxyHostImpl(site_instance_group, proxy_access_mode);
Harkiran Bolariaa8347782022-04-06 09:25:1161 TRACE_EVENT_END("navigation", ChromeTrackEvent::kRenderFrameProxyHost, proxy);
62 return proxy;
63}
64
65RenderFrameProxyHost* BrowsingContextState::GetRenderFrameProxyHostImpl(
Harkiran Bolariae45272d2022-04-12 08:05:0166 SiteInstanceGroup* site_instance_group,
67 ProxyAccessMode proxy_access_mode) const {
Harkiran Bolaria5c5a97392022-03-10 14:18:5068 if (features::GetBrowsingContextMode() ==
Harkiran Bolariae45272d2022-04-12 08:05:0169 features::BrowsingContextStateImplementationType::
70 kSwapForCrossBrowsingInstanceNavigations &&
71 proxy_access_mode == ProxyAccessMode::kRegular) {
Harkiran Bolaria5c5a97392022-03-10 14:18:5072 // CHECK to verify that the proxy is being accessed from the correct
73 // BrowsingContextState. As both BrowsingContextState (in non-legacy mode)
74 // and RenderFrameProxyHost (via SiteInstance) are tied to a given
75 // BrowsingInstance, the browsing instance id of the BrowsingContextState
76 // (in the non-legacy mode) and of the SiteInstanceGroup should match.
77 // If they do not, the code calling this method has likely chosen the
78 // wrong BrowsingContextGroup (e.g. one from the current RenderFrameHost
79 // rather than from speculative or vice versa) – as this can lead to
80 // various unpredictable bugs in proxy management logic, we want to
81 // crash the browser here when this condition fails.
82 //
83 // Note that the outer delegate and opener proxies are an exception and the
84 // only cases of a proxy associated with a SiteInstanceGroup from another
85 // BrowsingInstance. Meanwhile, for openers the opener and openee have to be
86 // in the same BrowsingInstance as well.
Harkiran Bolaria5c5a97392022-03-10 14:18:5087 CHECK_EQ(browsing_instance_id_.value(),
88 site_instance_group->browsing_instance_id());
89 }
Harkiran Bolaria5ce27632022-01-20 15:05:0590 auto it = proxy_hosts_.find(site_instance_group->GetId());
Harkiran Bolariaa8347782022-04-06 09:25:1191 if (it != proxy_hosts_.end()) {
Harkiran Bolaria5ce27632022-01-20 15:05:0592 return it->second.get();
Harkiran Bolariaa8347782022-04-06 09:25:1193 }
Harkiran Bolaria5ce27632022-01-20 15:05:0594 return nullptr;
95}
96
Harkiran Bolaria5c5a97392022-03-10 14:18:5097void BrowsingContextState::DeleteRenderFrameProxyHost(
Harkiran Bolariae45272d2022-04-12 08:05:0198 SiteInstanceGroup* site_instance_group,
99 ProxyAccessMode proxy_access_mode) {
Harkiran Bolaria5c5a97392022-03-10 14:18:50100 if (features::GetBrowsingContextMode() ==
Harkiran Bolariae45272d2022-04-12 08:05:01101 features::BrowsingContextStateImplementationType::
102 kSwapForCrossBrowsingInstanceNavigations &&
103 proxy_access_mode == ProxyAccessMode::kRegular) {
Harkiran Bolaria5c5a97392022-03-10 14:18:50104 // See comments in GetRenderFrameProxyHost for why this check is needed.
105 CHECK_EQ(browsing_instance_id_.value(),
106 site_instance_group->browsing_instance_id());
107 }
Harkiran Bolariaa8347782022-04-06 09:25:11108 TRACE_EVENT("navigation", "BrowsingContextState::DeleteRenderFrameProxyHost",
109 ChromeTrackEvent::kBrowsingContextState, this,
110 ChromeTrackEvent::kSiteInstanceGroup, site_instance_group);
Harkiran Bolaria5c5a97392022-03-10 14:18:50111 site_instance_group->RemoveObserver(this);
112 proxy_hosts_.erase(site_instance_group->GetId());
113}
114
115RenderFrameProxyHost* BrowsingContextState::CreateRenderFrameProxyHost(
116 SiteInstance* site_instance,
117 const scoped_refptr<RenderViewHostImpl>& rvh,
Harkiran Bolariae45272d2022-04-12 08:05:01118 FrameTreeNode* frame_tree_node,
119 ProxyAccessMode proxy_access_mode) {
Harkiran Bolariaa8347782022-04-06 09:25:11120 TRACE_EVENT_BEGIN(
121 "navigation", "BrowsingContextState::CreateRenderFrameProxyHost",
122 ChromeTrackEvent::kBrowsingContextState, this,
123 ChromeTrackEvent::kSiteInstanceGroup,
124 static_cast<SiteInstanceImpl*>(site_instance)->group(),
125 ChromeTrackEvent::kRenderViewHost, rvh ? rvh.get() : nullptr,
126 ChromeTrackEvent::kFrameTreeNodeInfo, frame_tree_node);
127
Harkiran Bolaria5c5a97392022-03-10 14:18:50128 if (features::GetBrowsingContextMode() ==
129 features::BrowsingContextStateImplementationType::
130 kLegacyOneToOneWithFrameTreeNode) {
131 DCHECK_EQ(this,
132 frame_tree_node->current_frame_host()->browsing_context_state());
133 }
134
135 if (features::GetBrowsingContextMode() ==
Harkiran Bolariae45272d2022-04-12 08:05:01136 features::BrowsingContextStateImplementationType::
137 kSwapForCrossBrowsingInstanceNavigations &&
138 proxy_access_mode == ProxyAccessMode::kRegular) {
Harkiran Bolaria5c5a97392022-03-10 14:18:50139 // See comments in GetRenderFrameProxyHost for why this check is needed.
140 CHECK_EQ(browsing_instance_id_.value(),
141 site_instance->GetBrowsingInstanceId());
142 }
143
144 auto site_instance_group_id =
145 static_cast<SiteInstanceImpl*>(site_instance)->group()->GetId();
146 CHECK(proxy_hosts_.find(site_instance_group_id) == proxy_hosts_.end())
147 << "A proxy already existed for this SiteInstanceGroup.";
148 RenderFrameProxyHost* proxy_host =
149 new RenderFrameProxyHost(site_instance, std::move(rvh), frame_tree_node);
150 proxy_hosts_[site_instance_group_id] = base::WrapUnique(proxy_host);
151 static_cast<SiteInstanceImpl*>(site_instance)->group()->AddObserver(this);
152
Harkiran Bolariaa8347782022-04-06 09:25:11153 TRACE_EVENT_END("navigation", ChromeTrackEvent::kRenderFrameProxyHost,
154 proxy_host);
Harkiran Bolaria5c5a97392022-03-10 14:18:50155 return proxy_host;
156}
157
Harkiran Bolariae45272d2022-04-12 08:05:01158RenderFrameProxyHost* BrowsingContextState::CreateOuterDelegateProxy(
159 SiteInstance* outer_contents_site_instance,
160 FrameTreeNode* frame_tree_node) {
161 // We only get here when Delegate for this manager is an inner delegate.
162 return CreateRenderFrameProxyHost(outer_contents_site_instance,
163 /*rvh=*/nullptr, frame_tree_node,
164 ProxyAccessMode::kAllowOuterDelegate);
165}
166
167void BrowsingContextState::DeleteOuterDelegateProxy(
168 SiteInstanceGroup* outer_contents_site_instance_group) {
169 DeleteRenderFrameProxyHost(
170 outer_contents_site_instance_group,
171 BrowsingContextState::ProxyAccessMode::kAllowOuterDelegate);
172}
173
Harkiran Bolariad22a1dca2022-02-22 17:01:12174size_t BrowsingContextState::GetProxyCount() {
175 return proxy_hosts_.size();
176}
177
Harkiran Bolaria5ce27632022-01-20 15:05:05178bool BrowsingContextState::UpdateFramePolicyHeaders(
179 network::mojom::WebSandboxFlags sandbox_flags,
180 const blink::ParsedPermissionsPolicy& parsed_header) {
181 bool changed = false;
182 if (replication_state_->permissions_policy_header != parsed_header) {
183 replication_state_->permissions_policy_header = parsed_header;
184 changed = true;
185 }
186 // TODO(iclelland): Kill the renderer if sandbox flags is not a subset of the
187 // currently effective sandbox flags from the frame. https://crbug.com/740556
188 network::mojom::WebSandboxFlags updated_flags =
189 sandbox_flags | replication_state_->frame_policy.sandbox_flags;
190 if (replication_state_->active_sandbox_flags != updated_flags) {
191 replication_state_->active_sandbox_flags = updated_flags;
192 changed = true;
193 }
194 // Notify any proxies if the policies have been changed.
195 if (changed) {
196 for (const auto& pair : proxy_hosts_) {
197 pair.second->GetAssociatedRemoteFrame()->DidSetFramePolicyHeaders(
198 replication_state_->active_sandbox_flags,
199 replication_state_->permissions_policy_header);
200 }
201 }
202 return changed;
203}
204
205bool BrowsingContextState::CommitFramePolicy(
206 const blink::FramePolicy& new_frame_policy) {
207 // Documents create iframes, iframes host new documents. Both are associated
208 // with sandbox flags. They are required to be stricter or equal to their
209 // owner when they change, as we go down.
210 // TODO(https://crbug.com/1262061). Enforce the invariant mentioned above,
211 // once the interactions with fenced frame has been tested and clarified.
212
213 bool did_change_flags = new_frame_policy.sandbox_flags !=
214 replication_state_->frame_policy.sandbox_flags;
215 bool did_change_container_policy =
216 new_frame_policy.container_policy !=
217 replication_state_->frame_policy.container_policy;
218 bool did_change_required_document_policy =
219 new_frame_policy.required_document_policy !=
220 replication_state_->frame_policy.required_document_policy;
221 DCHECK_EQ(new_frame_policy.is_fenced,
222 replication_state_->frame_policy.is_fenced);
Dominic Farolinobfd1f0292022-03-23 19:12:24223 DCHECK_EQ(new_frame_policy.fenced_frame_mode,
224 replication_state_->frame_policy.fenced_frame_mode);
Harkiran Bolaria5ce27632022-01-20 15:05:05225
Harkiran Bolaria4eacb3a2021-12-13 20:03:47226 if (did_change_flags) {
227 replication_state_->frame_policy.sandbox_flags =
228 new_frame_policy.sandbox_flags;
229 }
230 if (did_change_container_policy) {
231 replication_state_->frame_policy.container_policy =
232 new_frame_policy.container_policy;
233 }
234 if (did_change_required_document_policy) {
235 replication_state_->frame_policy.required_document_policy =
236 new_frame_policy.required_document_policy;
237 }
Harkiran Bolariae3521432021-12-14 11:27:43238
Harkiran Bolaria5ce27632022-01-20 15:05:05239 UpdateFramePolicyHeaders(new_frame_policy.sandbox_flags,
240 replication_state_->permissions_policy_header);
241 return did_change_flags || did_change_container_policy ||
242 did_change_required_document_policy;
Harkiran Bolaria7fdb4c642021-12-20 12:47:00243}
244
Harkiran Bolaria880a7632022-02-28 16:02:50245void BrowsingContextState::SetFrameName(const std::string& name,
246 const std::string& unique_name) {
247 if (name == replication_state_->name) {
248 // |unique_name| shouldn't change unless |name| changes.
249 DCHECK_EQ(unique_name, replication_state_->unique_name);
250 return;
251 }
252
253 if (parent_) {
254 // Non-main frames should have a non-empty unique name.
255 DCHECK(!unique_name.empty());
256 } else {
257 // Unique name of main frames should always stay empty.
258 DCHECK(unique_name.empty());
259 }
260
261 // Note the unique name should only be able to change before the first real
262 // load is committed, but that's not strongly enforced here.
263 for (const auto& pair : proxy_hosts_) {
264 pair.second->GetAssociatedRemoteFrame()->SetReplicatedName(name,
265 unique_name);
266 }
267 replication_state_->unique_name = unique_name;
268 replication_state_->name = name;
269}
270
Harkiran Bolariae3521432021-12-14 11:27:43271void BrowsingContextState::SetCurrentOrigin(
272 const url::Origin& origin,
273 bool is_potentially_trustworthy_unique_origin) {
274 if (origin.IsSameOriginWith(replication_state_->origin) &&
275 replication_state_->has_potentially_trustworthy_unique_origin ==
276 is_potentially_trustworthy_unique_origin) {
277 return;
278 }
279
280 for (const auto& pair : proxy_hosts_) {
281 pair.second->GetAssociatedRemoteFrame()->SetReplicatedOrigin(
282 origin, is_potentially_trustworthy_unique_origin);
283 }
284
285 replication_state_->origin = origin;
286 replication_state_->has_potentially_trustworthy_unique_origin =
287 is_potentially_trustworthy_unique_origin;
288}
289
290void BrowsingContextState::SetInsecureRequestPolicy(
291 blink::mojom::InsecureRequestPolicy policy) {
292 if (policy == replication_state_->insecure_request_policy)
293 return;
294 for (const auto& pair : proxy_hosts_) {
295 pair.second->GetAssociatedRemoteFrame()->EnforceInsecureRequestPolicy(
296 policy);
297 }
298 replication_state_->insecure_request_policy = policy;
299}
300
301void BrowsingContextState::SetInsecureNavigationsSet(
302 const std::vector<uint32_t>& insecure_navigations_set) {
303 DCHECK(std::is_sorted(insecure_navigations_set.begin(),
304 insecure_navigations_set.end()));
305 if (insecure_navigations_set == replication_state_->insecure_navigations_set)
306 return;
307 for (const auto& pair : proxy_hosts_) {
308 pair.second->GetAssociatedRemoteFrame()->EnforceInsecureNavigationsSet(
309 insecure_navigations_set);
310 }
311 replication_state_->insecure_navigations_set = insecure_navigations_set;
312}
313
314void BrowsingContextState::OnSetHadStickyUserActivationBeforeNavigation(
315 bool value) {
316 for (const auto& pair : proxy_hosts_) {
317 pair.second->GetAssociatedRemoteFrame()
318 ->SetHadStickyUserActivationBeforeNavigation(value);
319 }
320 replication_state_->has_received_user_gesture_before_nav = value;
321}
322
323void BrowsingContextState::SetIsAdSubframe(bool is_ad_subframe) {
324 if (is_ad_subframe == replication_state_->is_ad_subframe)
325 return;
326
327 replication_state_->is_ad_subframe = is_ad_subframe;
328 for (const auto& pair : proxy_hosts_) {
329 pair.second->GetAssociatedRemoteFrame()->SetReplicatedIsAdSubframe(
330 is_ad_subframe);
331 }
332}
333
Harkiran Bolariae182a5942021-12-20 17:23:31334void BrowsingContextState::ActiveFrameCountIsZero(
Sharon Yanga2fe85e2022-02-09 21:38:29335 SiteInstanceGroup* site_instance_group) {
336 // |site_instance_group| no longer contains any active RenderFrameHosts, so we
337 // don't need to maintain a proxy there anymore.
338 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(site_instance_group);
Harkiran Bolariae182a5942021-12-20 17:23:31339 CHECK(proxy);
340
Harkiran Bolariaa8347782022-04-06 09:25:11341 TRACE_EVENT_INSTANT("navigation",
342 "BrowsingContextState::ActiveFrameCountIsZero",
343 ChromeTrackEvent::kBrowsingContextState, this,
344 ChromeTrackEvent::kRenderFrameProxyHost, proxy);
345
Sharon Yanga2fe85e2022-02-09 21:38:29346 DeleteRenderFrameProxyHost(site_instance_group);
Harkiran Bolariae182a5942021-12-20 17:23:31347}
348
349void BrowsingContextState::RenderProcessGone(
Sharon Yanga2fe85e2022-02-09 21:38:29350 SiteInstanceGroup* site_instance_group,
Harkiran Bolariae182a5942021-12-20 17:23:31351 const ChildProcessTerminationInfo& info) {
Harkiran Bolariae45272d2022-04-12 08:05:01352 GetRenderFrameProxyHost(site_instance_group,
353 ProxyAccessMode::kAllowOuterDelegate)
Sharon Yanga2fe85e2022-02-09 21:38:29354 ->SetRenderFrameProxyCreated(false);
Harkiran Bolariae182a5942021-12-20 17:23:31355}
356
Harkiran Bolaria5ce27632022-01-20 15:05:05357void BrowsingContextState::SendFramePolicyUpdatesToProxies(
Sharon Yang571baee2022-03-18 19:01:54358 SiteInstanceGroup* parent_group,
Harkiran Bolaria5ce27632022-01-20 15:05:05359 const blink::FramePolicy& frame_policy) {
360 // Notify all of the frame's proxies about updated policies, excluding
361 // the parent process since it already knows the latest state.
362 for (const auto& pair : proxy_hosts_) {
Sharon Yang571baee2022-03-18 19:01:54363 if (pair.second->site_instance_group() != parent_group) {
Harkiran Bolaria5ce27632022-01-20 15:05:05364 pair.second->GetAssociatedRemoteFrame()->DidUpdateFramePolicy(
365 frame_policy);
366 }
367 }
368}
369
Harkiran Bolaria3f83fba72022-03-10 17:48:40370void BrowsingContextState::OnDidStartLoading() {
371 for (const auto& pair : proxy_hosts_)
372 pair.second->GetAssociatedRemoteFrame()->DidStartLoading();
373}
374
375void BrowsingContextState::OnDidStopLoading() {
376 for (const auto& pair : proxy_hosts_)
377 pair.second->GetAssociatedRemoteFrame()->DidStopLoading();
378}
379
Harkiran Bolaria0b3bdef02022-03-10 13:04:40380void BrowsingContextState::ResetProxyHosts() {
381 for (const auto& pair : proxy_hosts_) {
382 pair.second->site_instance_group()->RemoveObserver(this);
383 }
384 proxy_hosts_.clear();
385}
386
Sharon Yang571baee2022-03-18 19:01:54387void BrowsingContextState::UpdateOpener(
388 SiteInstanceGroup* source_site_instance_group) {
Harkiran Bolaria3f83fba72022-03-10 17:48:40389 for (const auto& pair : proxy_hosts_) {
Sharon Yang571baee2022-03-18 19:01:54390 if (pair.second->site_instance_group() == source_site_instance_group)
Harkiran Bolaria3f83fba72022-03-10 17:48:40391 continue;
392 pair.second->UpdateOpener();
393 }
394}
395
396void BrowsingContextState::OnDidUpdateFrameOwnerProperties(
397 const blink::mojom::FrameOwnerProperties& properties) {
398 // Notify this frame's proxies if they live in a different process from its
399 // parent. This is only currently needed for the allowFullscreen property,
400 // since that can be queried on RemoteFrame ancestors.
401 //
402 // TODO(alexmos): It would be sufficient to only send this update to proxies
403 // in the current FrameTree.
404 for (const auto& pair : proxy_hosts_) {
405 if (pair.second->site_instance_group() !=
406 parent_->GetSiteInstance()->group()) {
407 auto properties_for_remote_frame = properties.Clone();
408 RenderFrameProxyHost* proxy = pair.second.get();
409 proxy->GetAssociatedRemoteFrame()->SetFrameOwnerProperties(
410 std::move(properties_for_remote_frame));
411 }
412 }
413}
414
415void BrowsingContextState::ExecuteRemoteFramesBroadcastMethod(
416 base::RepeatingCallback<void(RenderFrameProxyHost*)> callback,
417 SiteInstance* instance_to_skip,
418 RenderFrameProxyHost* outer_delegate_proxy) {
419 for (const auto& pair : proxy_hosts_) {
420 if (outer_delegate_proxy == pair.second.get())
421 continue;
422 if (pair.second->GetSiteInstance() == instance_to_skip)
423 continue;
424 if (!pair.second->is_render_frame_proxy_live())
425 continue;
426 callback.Run(pair.second.get());
427 }
428}
429
Harkiran Bolaria3bf5457f2022-03-10 20:04:37430void BrowsingContextState::WriteIntoTrace(
Alexander Timin074cd182022-03-23 18:11:22431 perfetto::TracedProto<TraceProto> proto) const {
Harkiran Bolaria3bf5457f2022-03-10 20:04:37432 if (browsing_instance_id_.has_value())
433 proto->set_browsing_instance_id(browsing_instance_id_.value().value());
Alexander Timin074cd182022-03-23 18:11:22434
435 perfetto::TracedDictionary dict = std::move(proto).AddDebugAnnotations();
436 dict.Add("this", static_cast<const void*>(this));
Harkiran Bolaria3bf5457f2022-03-10 20:04:37437}
438
Alexander Timin07cad0762022-03-15 00:33:17439} // namespace content