blob: b4eaf1f9c9bda680198acbbf6162f080091f8f78 [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
Harkiran Bolaria2912a6b32022-02-22 16:43:457#include "content/browser/renderer_host/frame_tree_node.h"
Harkiran Bolaria3f83fba72022-03-10 17:48:408#include "content/browser/renderer_host/render_frame_host_impl.h"
Harkiran Bolaria2912a6b32022-02-22 16:43:459#include "content/browser/renderer_host/render_view_host_impl.h"
10#include "content/common/content_navigation_policy.h"
Harkiran Bolaria5ce27632022-01-20 15:05:0511#include "services/network/public/cpp/web_sandbox_flags.h"
12#include "services/network/public/mojom/web_sandbox_flags.mojom.h"
13
Harkiran Bolaria8dec6f92021-12-07 14:57:1214namespace features {
15const base::Feature kNewBrowsingContextStateOnBrowsingContextGroupSwap{
16 "NewBrowsingContextStateOnBrowsingContextGroupSwap",
17 base::FEATURE_DISABLED_BY_DEFAULT};
18
19BrowsingContextStateImplementationType GetBrowsingContextMode() {
20 if (base::FeatureList::IsEnabled(
21 kNewBrowsingContextStateOnBrowsingContextGroupSwap)) {
22 return BrowsingContextStateImplementationType::
23 kSwapForCrossBrowsingInstanceNavigations;
24 }
25
26 return BrowsingContextStateImplementationType::
27 kLegacyOneToOneWithFrameTreeNode;
28}
29} // namespace features
30
31namespace content {
32
Harkiran Bolaria4eacb3a2021-12-13 20:03:4733BrowsingContextState::BrowsingContextState(
Harkiran Bolaria880a7632022-02-28 16:02:5034 blink::mojom::FrameReplicationStatePtr replication_state,
Harkiran Bolaria0b3bdef02022-03-10 13:04:4035 raw_ptr<RenderFrameHostImpl> parent,
36 absl::optional<BrowsingInstanceId> browsing_instance_id)
37 : replication_state_(std::move(replication_state)),
38 parent_(parent),
39 browsing_instance_id_(browsing_instance_id) {}
Harkiran Bolaria8dec6f92021-12-07 14:57:1240
41BrowsingContextState::~BrowsingContextState() = default;
Harkiran Bolaria4eacb3a2021-12-13 20:03:4742
Harkiran Bolaria5ce27632022-01-20 15:05:0543RenderFrameProxyHost* BrowsingContextState::GetRenderFrameProxyHost(
44 SiteInstanceGroup* site_instance_group) const {
Harkiran Bolaria5c5a97392022-03-10 14:18:5045 if (features::GetBrowsingContextMode() ==
46 features::BrowsingContextStateImplementationType::
47 kSwapForCrossBrowsingInstanceNavigations) {
48 // CHECK to verify that the proxy is being accessed from the correct
49 // BrowsingContextState. As both BrowsingContextState (in non-legacy mode)
50 // and RenderFrameProxyHost (via SiteInstance) are tied to a given
51 // BrowsingInstance, the browsing instance id of the BrowsingContextState
52 // (in the non-legacy mode) and of the SiteInstanceGroup should match.
53 // If they do not, the code calling this method has likely chosen the
54 // wrong BrowsingContextGroup (e.g. one from the current RenderFrameHost
55 // rather than from speculative or vice versa) – as this can lead to
56 // various unpredictable bugs in proxy management logic, we want to
57 // crash the browser here when this condition fails.
58 //
59 // Note that the outer delegate and opener proxies are an exception and the
60 // only cases of a proxy associated with a SiteInstanceGroup from another
61 // BrowsingInstance. Meanwhile, for openers the opener and openee have to be
62 // in the same BrowsingInstance as well.
63 // TODO(crbug.com/1270671): Add exception here for outer delegate proxies.
64 CHECK_EQ(browsing_instance_id_.value(),
65 site_instance_group->browsing_instance_id());
66 }
Harkiran Bolaria5ce27632022-01-20 15:05:0567 auto it = proxy_hosts_.find(site_instance_group->GetId());
68 if (it != proxy_hosts_.end())
69 return it->second.get();
70 return nullptr;
71}
72
Harkiran Bolaria5c5a97392022-03-10 14:18:5073void BrowsingContextState::DeleteRenderFrameProxyHost(
74 SiteInstanceGroup* site_instance_group) {
75 if (features::GetBrowsingContextMode() ==
76 features::BrowsingContextStateImplementationType::
77 kSwapForCrossBrowsingInstanceNavigations) {
78 // See comments in GetRenderFrameProxyHost for why this check is needed.
79 CHECK_EQ(browsing_instance_id_.value(),
80 site_instance_group->browsing_instance_id());
81 }
82 site_instance_group->RemoveObserver(this);
83 proxy_hosts_.erase(site_instance_group->GetId());
84}
85
86RenderFrameProxyHost* BrowsingContextState::CreateRenderFrameProxyHost(
87 SiteInstance* site_instance,
88 const scoped_refptr<RenderViewHostImpl>& rvh,
89 FrameTreeNode* frame_tree_node) {
90 if (features::GetBrowsingContextMode() ==
91 features::BrowsingContextStateImplementationType::
92 kLegacyOneToOneWithFrameTreeNode) {
93 DCHECK_EQ(this,
94 frame_tree_node->current_frame_host()->browsing_context_state());
95 }
96
97 if (features::GetBrowsingContextMode() ==
98 features::BrowsingContextStateImplementationType::
99 kSwapForCrossBrowsingInstanceNavigations) {
100 // See comments in GetRenderFrameProxyHost for why this check is needed.
101 CHECK_EQ(browsing_instance_id_.value(),
102 site_instance->GetBrowsingInstanceId());
103 }
104
105 auto site_instance_group_id =
106 static_cast<SiteInstanceImpl*>(site_instance)->group()->GetId();
107 CHECK(proxy_hosts_.find(site_instance_group_id) == proxy_hosts_.end())
108 << "A proxy already existed for this SiteInstanceGroup.";
109 RenderFrameProxyHost* proxy_host =
110 new RenderFrameProxyHost(site_instance, std::move(rvh), frame_tree_node);
111 proxy_hosts_[site_instance_group_id] = base::WrapUnique(proxy_host);
112 static_cast<SiteInstanceImpl*>(site_instance)->group()->AddObserver(this);
113
114 TRACE_EVENT_INSTANT(
115 "navigation", "BrowsingContextState::CreateRenderFrameProxyHost",
116 perfetto::protos::pbzero::ChromeTrackEvent::kRenderFrameProxyHost,
117 *proxy_host);
118 return proxy_host;
119}
120
Harkiran Bolariad22a1dca2022-02-22 17:01:12121size_t BrowsingContextState::GetProxyCount() {
122 return proxy_hosts_.size();
123}
124
Harkiran Bolaria5ce27632022-01-20 15:05:05125bool BrowsingContextState::UpdateFramePolicyHeaders(
126 network::mojom::WebSandboxFlags sandbox_flags,
127 const blink::ParsedPermissionsPolicy& parsed_header) {
128 bool changed = false;
129 if (replication_state_->permissions_policy_header != parsed_header) {
130 replication_state_->permissions_policy_header = parsed_header;
131 changed = true;
132 }
133 // TODO(iclelland): Kill the renderer if sandbox flags is not a subset of the
134 // currently effective sandbox flags from the frame. https://crbug.com/740556
135 network::mojom::WebSandboxFlags updated_flags =
136 sandbox_flags | replication_state_->frame_policy.sandbox_flags;
137 if (replication_state_->active_sandbox_flags != updated_flags) {
138 replication_state_->active_sandbox_flags = updated_flags;
139 changed = true;
140 }
141 // Notify any proxies if the policies have been changed.
142 if (changed) {
143 for (const auto& pair : proxy_hosts_) {
144 pair.second->GetAssociatedRemoteFrame()->DidSetFramePolicyHeaders(
145 replication_state_->active_sandbox_flags,
146 replication_state_->permissions_policy_header);
147 }
148 }
149 return changed;
150}
151
152bool BrowsingContextState::CommitFramePolicy(
153 const blink::FramePolicy& new_frame_policy) {
154 // Documents create iframes, iframes host new documents. Both are associated
155 // with sandbox flags. They are required to be stricter or equal to their
156 // owner when they change, as we go down.
157 // TODO(https://crbug.com/1262061). Enforce the invariant mentioned above,
158 // once the interactions with fenced frame has been tested and clarified.
159
160 bool did_change_flags = new_frame_policy.sandbox_flags !=
161 replication_state_->frame_policy.sandbox_flags;
162 bool did_change_container_policy =
163 new_frame_policy.container_policy !=
164 replication_state_->frame_policy.container_policy;
165 bool did_change_required_document_policy =
166 new_frame_policy.required_document_policy !=
167 replication_state_->frame_policy.required_document_policy;
168 DCHECK_EQ(new_frame_policy.is_fenced,
169 replication_state_->frame_policy.is_fenced);
170
Harkiran Bolaria4eacb3a2021-12-13 20:03:47171 if (did_change_flags) {
172 replication_state_->frame_policy.sandbox_flags =
173 new_frame_policy.sandbox_flags;
174 }
175 if (did_change_container_policy) {
176 replication_state_->frame_policy.container_policy =
177 new_frame_policy.container_policy;
178 }
179 if (did_change_required_document_policy) {
180 replication_state_->frame_policy.required_document_policy =
181 new_frame_policy.required_document_policy;
182 }
Harkiran Bolariae3521432021-12-14 11:27:43183
Harkiran Bolaria5ce27632022-01-20 15:05:05184 UpdateFramePolicyHeaders(new_frame_policy.sandbox_flags,
185 replication_state_->permissions_policy_header);
186 return did_change_flags || did_change_container_policy ||
187 did_change_required_document_policy;
Harkiran Bolaria7fdb4c642021-12-20 12:47:00188}
189
Harkiran Bolaria880a7632022-02-28 16:02:50190void BrowsingContextState::SetFrameName(const std::string& name,
191 const std::string& unique_name) {
192 if (name == replication_state_->name) {
193 // |unique_name| shouldn't change unless |name| changes.
194 DCHECK_EQ(unique_name, replication_state_->unique_name);
195 return;
196 }
197
198 if (parent_) {
199 // Non-main frames should have a non-empty unique name.
200 DCHECK(!unique_name.empty());
201 } else {
202 // Unique name of main frames should always stay empty.
203 DCHECK(unique_name.empty());
204 }
205
206 // Note the unique name should only be able to change before the first real
207 // load is committed, but that's not strongly enforced here.
208 for (const auto& pair : proxy_hosts_) {
209 pair.second->GetAssociatedRemoteFrame()->SetReplicatedName(name,
210 unique_name);
211 }
212 replication_state_->unique_name = unique_name;
213 replication_state_->name = name;
214}
215
Harkiran Bolariae3521432021-12-14 11:27:43216void BrowsingContextState::SetCurrentOrigin(
217 const url::Origin& origin,
218 bool is_potentially_trustworthy_unique_origin) {
219 if (origin.IsSameOriginWith(replication_state_->origin) &&
220 replication_state_->has_potentially_trustworthy_unique_origin ==
221 is_potentially_trustworthy_unique_origin) {
222 return;
223 }
224
225 for (const auto& pair : proxy_hosts_) {
226 pair.second->GetAssociatedRemoteFrame()->SetReplicatedOrigin(
227 origin, is_potentially_trustworthy_unique_origin);
228 }
229
230 replication_state_->origin = origin;
231 replication_state_->has_potentially_trustworthy_unique_origin =
232 is_potentially_trustworthy_unique_origin;
233}
234
235void BrowsingContextState::SetInsecureRequestPolicy(
236 blink::mojom::InsecureRequestPolicy policy) {
237 if (policy == replication_state_->insecure_request_policy)
238 return;
239 for (const auto& pair : proxy_hosts_) {
240 pair.second->GetAssociatedRemoteFrame()->EnforceInsecureRequestPolicy(
241 policy);
242 }
243 replication_state_->insecure_request_policy = policy;
244}
245
246void BrowsingContextState::SetInsecureNavigationsSet(
247 const std::vector<uint32_t>& insecure_navigations_set) {
248 DCHECK(std::is_sorted(insecure_navigations_set.begin(),
249 insecure_navigations_set.end()));
250 if (insecure_navigations_set == replication_state_->insecure_navigations_set)
251 return;
252 for (const auto& pair : proxy_hosts_) {
253 pair.second->GetAssociatedRemoteFrame()->EnforceInsecureNavigationsSet(
254 insecure_navigations_set);
255 }
256 replication_state_->insecure_navigations_set = insecure_navigations_set;
257}
258
259void BrowsingContextState::OnSetHadStickyUserActivationBeforeNavigation(
260 bool value) {
261 for (const auto& pair : proxy_hosts_) {
262 pair.second->GetAssociatedRemoteFrame()
263 ->SetHadStickyUserActivationBeforeNavigation(value);
264 }
265 replication_state_->has_received_user_gesture_before_nav = value;
266}
267
268void BrowsingContextState::SetIsAdSubframe(bool is_ad_subframe) {
269 if (is_ad_subframe == replication_state_->is_ad_subframe)
270 return;
271
272 replication_state_->is_ad_subframe = is_ad_subframe;
273 for (const auto& pair : proxy_hosts_) {
274 pair.second->GetAssociatedRemoteFrame()->SetReplicatedIsAdSubframe(
275 is_ad_subframe);
276 }
277}
278
Harkiran Bolariae182a5942021-12-20 17:23:31279void BrowsingContextState::ActiveFrameCountIsZero(
Sharon Yanga2fe85e2022-02-09 21:38:29280 SiteInstanceGroup* site_instance_group) {
281 // |site_instance_group| no longer contains any active RenderFrameHosts, so we
282 // don't need to maintain a proxy there anymore.
283 RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(site_instance_group);
Harkiran Bolariae182a5942021-12-20 17:23:31284 CHECK(proxy);
285
Sharon Yanga2fe85e2022-02-09 21:38:29286 DeleteRenderFrameProxyHost(site_instance_group);
Harkiran Bolariae182a5942021-12-20 17:23:31287}
288
289void BrowsingContextState::RenderProcessGone(
Sharon Yanga2fe85e2022-02-09 21:38:29290 SiteInstanceGroup* site_instance_group,
Harkiran Bolariae182a5942021-12-20 17:23:31291 const ChildProcessTerminationInfo& info) {
Sharon Yanga2fe85e2022-02-09 21:38:29292 GetRenderFrameProxyHost(site_instance_group)
293 ->SetRenderFrameProxyCreated(false);
Harkiran Bolariae182a5942021-12-20 17:23:31294}
295
Harkiran Bolaria5ce27632022-01-20 15:05:05296void BrowsingContextState::SendFramePolicyUpdatesToProxies(
Sharon Yang571baee2022-03-18 19:01:54297 SiteInstanceGroup* parent_group,
Harkiran Bolaria5ce27632022-01-20 15:05:05298 const blink::FramePolicy& frame_policy) {
299 // Notify all of the frame's proxies about updated policies, excluding
300 // the parent process since it already knows the latest state.
301 for (const auto& pair : proxy_hosts_) {
Sharon Yang571baee2022-03-18 19:01:54302 if (pair.second->site_instance_group() != parent_group) {
Harkiran Bolaria5ce27632022-01-20 15:05:05303 pair.second->GetAssociatedRemoteFrame()->DidUpdateFramePolicy(
304 frame_policy);
305 }
306 }
307}
308
Harkiran Bolaria3f83fba72022-03-10 17:48:40309void BrowsingContextState::OnDidStartLoading() {
310 for (const auto& pair : proxy_hosts_)
311 pair.second->GetAssociatedRemoteFrame()->DidStartLoading();
312}
313
314void BrowsingContextState::OnDidStopLoading() {
315 for (const auto& pair : proxy_hosts_)
316 pair.second->GetAssociatedRemoteFrame()->DidStopLoading();
317}
318
Harkiran Bolaria0b3bdef02022-03-10 13:04:40319void BrowsingContextState::ResetProxyHosts() {
320 for (const auto& pair : proxy_hosts_) {
321 pair.second->site_instance_group()->RemoveObserver(this);
322 }
323 proxy_hosts_.clear();
324}
325
Sharon Yang571baee2022-03-18 19:01:54326void BrowsingContextState::UpdateOpener(
327 SiteInstanceGroup* source_site_instance_group) {
Harkiran Bolaria3f83fba72022-03-10 17:48:40328 for (const auto& pair : proxy_hosts_) {
Sharon Yang571baee2022-03-18 19:01:54329 if (pair.second->site_instance_group() == source_site_instance_group)
Harkiran Bolaria3f83fba72022-03-10 17:48:40330 continue;
331 pair.second->UpdateOpener();
332 }
333}
334
335void BrowsingContextState::OnDidUpdateFrameOwnerProperties(
336 const blink::mojom::FrameOwnerProperties& properties) {
337 // Notify this frame's proxies if they live in a different process from its
338 // parent. This is only currently needed for the allowFullscreen property,
339 // since that can be queried on RemoteFrame ancestors.
340 //
341 // TODO(alexmos): It would be sufficient to only send this update to proxies
342 // in the current FrameTree.
343 for (const auto& pair : proxy_hosts_) {
344 if (pair.second->site_instance_group() !=
345 parent_->GetSiteInstance()->group()) {
346 auto properties_for_remote_frame = properties.Clone();
347 RenderFrameProxyHost* proxy = pair.second.get();
348 proxy->GetAssociatedRemoteFrame()->SetFrameOwnerProperties(
349 std::move(properties_for_remote_frame));
350 }
351 }
352}
353
354void BrowsingContextState::ExecuteRemoteFramesBroadcastMethod(
355 base::RepeatingCallback<void(RenderFrameProxyHost*)> callback,
356 SiteInstance* instance_to_skip,
357 RenderFrameProxyHost* outer_delegate_proxy) {
358 for (const auto& pair : proxy_hosts_) {
359 if (outer_delegate_proxy == pair.second.get())
360 continue;
361 if (pair.second->GetSiteInstance() == instance_to_skip)
362 continue;
363 if (!pair.second->is_render_frame_proxy_live())
364 continue;
365 callback.Run(pair.second.get());
366 }
367}
368
Harkiran Bolaria3bf5457f2022-03-10 20:04:37369void BrowsingContextState::WriteIntoTrace(
Alexander Timin074cd182022-03-23 18:11:22370 perfetto::TracedProto<TraceProto> proto) const {
Harkiran Bolaria3bf5457f2022-03-10 20:04:37371 if (browsing_instance_id_.has_value())
372 proto->set_browsing_instance_id(browsing_instance_id_.value().value());
Alexander Timin074cd182022-03-23 18:11:22373
374 perfetto::TracedDictionary dict = std::move(proto).AddDebugAnnotations();
375 dict.Add("this", static_cast<const void*>(this));
Harkiran Bolaria3bf5457f2022-03-10 20:04:37376}
377
Alexander Timin07cad0762022-03-15 00:33:17378} // namespace content