1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
content / browser / url_info.h [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_URL_INFO_H_
#define CONTENT_BROWSER_URL_INFO_H_
#include <optional>
#include "content/browser/agent_cluster_key.h"
#include "content/browser/web_exposed_isolation_info.h"
#include "content/common/content_export.h"
#include "content/public/browser/storage_partition_config.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
// This struct is used to package a GURL together with extra state required to
// make SiteInstance/process allocation decisions, e.g. whether the url's
// origin or site is requesting isolation as determined by response headers in
// the corresponding NavigationRequest. The extra state is generally most
// relevant when navigation to the URL is in progress, since once placed into a
// SiteInstance, the extra state will be available via SiteInfo. Otherwise,
// most callsites requiring a UrlInfo can create with a GURL, specifying kNone
// for |origin_isolation_request|. Some examples of where passing kNone for
// |origin_isolation_request| is safe are:
// * at DidCommitNavigation time, since at that point the SiteInstance has
// already been picked and the navigation can be considered finished,
// * before a response is received (the only way to request isolation is via
// response headers), and
// * outside of a navigation.
//
// If UrlInfo::origin_isolation_request is kNone, that does *not* imply that
// the URL's origin will not be isolated, and vice versa. The isolation
// decision involves both response headers and consistency within a
// BrowsingInstance, and once we decide on the isolation outcome for an origin,
// it won't change for the lifetime of the BrowsingInstance.
//
// To check whether a frame ends up in a site-isolated process, use
// SiteInfo::RequiresDedicatedProcess() on its SiteInstance's SiteInfo. To
// check whether a frame ends up being origin-isolated in a separate process
// (e.g., due to the Origin-Agent-Cluster header), use
// SiteInfo::requires_origin_keyed_process().
//
// Note: it is not expected that this struct will be exposed in content/public.
class IsolationContext;
class UrlInfoInit;
struct CONTENT_EXPORT UrlInfo {
public:
// Bitmask representing one or more isolation requests.
enum OriginIsolationRequest {
// No isolation has been requested, so the default isolation state for the
// current BrowsingInstance should be used.
kDefault = 0,
// Explicitly requests no isolation.
kNone = (1 << 0),
// The Origin-Agent-Cluster header is requesting OAC isolation for `url`'s
// origin in the renderer. If granted, this is tracked for consistency in
// ChildProcessSecurityPolicyImpl. If kRequiresOriginKeyedProcessByHeader is
// not set, then this only affects the renderer.
kOriginAgentClusterByHeader = (1 << 1),
// If kOriginAgentClusterByHeader is set, the following bit triggers an
// origin-keyed process for `url`'s origin. If
// kRequiresOriginKeyedProcessByHeader is not set and
// kOriginAgentClusterByHeader is, then OAC will be logical only, i.e.
// implemented in the renderer via a separate AgentCluster.
kRequiresOriginKeyedProcessByHeader = (1 << 2),
};
// For isolated sandboxed iframes, when per-document mode is used, we
// assign each sandboxed SiteInstance a unique identifier to prevent other
// same-site/same-origin frames from re-using the same SiteInstance. This
// identifier is used to indicate that the sandbox id is not in use.
static const int64_t kInvalidUniqueSandboxId;
UrlInfo(); // Needed for inclusion in SiteInstanceDescriptor.
UrlInfo(const UrlInfo& other);
explicit UrlInfo(const UrlInfoInit& init);
~UrlInfo();
// Used to convert GURL to UrlInfo in tests where opt-in isolation is not
// being tested.
static UrlInfo CreateForTesting(const GURL& url_in,
std::optional<StoragePartitionConfig>
storage_partition_config = std::nullopt);
// Depending on enabled features (some of which can change at runtime),
// default can be no isolation, requests origin agent cluster only, or
// requests origin agent cluster with origin keyed process. BrowsingInstances
// store a copy of the default isolation state at the time of their creation
// to make sure the default value stays constant over the lifetime of the
// BrowsingInstance.
bool requests_default_origin_agent_cluster_isolation() const {
return origin_isolation_request == OriginIsolationRequest::kDefault;
}
// Returns whether this UrlInfo is requesting an origin-keyed agent cluster
// for `url`'s origin due to the OriginAgentCluster header.
bool requests_origin_agent_cluster_by_header() const {
return (origin_isolation_request &
OriginIsolationRequest::kOriginAgentClusterByHeader);
}
// Returns whether this UrlInfo is requesting an origin-keyed process for
// `url`'s origin due to the OriginAgentCluster header.
bool requests_origin_keyed_process_by_header() const {
return (origin_isolation_request &
OriginIsolationRequest::kRequiresOriginKeyedProcessByHeader);
}
// Returns whether this UrlInfo is requesting an origin-keyed process for
// `url`'s origin due to the OriginAgentCluster header, or whether it should
// try to use an origin-keyed process by default within the given `context`,
// in cases without an explicit header.
bool RequestsOriginKeyedProcess(const IsolationContext& context) const;
// Returns whether this UrlInfo is requesting site isolation for its site in
// response to the Cross-Origin-Opener-Policy header. See
// https://chromium.googlesource.com/chromium/src/+/main/docs/process_model_and_site_isolation.md#Partial-Site-Isolation
// for details.
bool requests_coop_isolation() const { return is_coop_isolation_requested; }
// Returns whether this UrlInfo is for a page that should be cross-origin
// isolated.
bool IsIsolated() const;
GURL url;
// This field indicates whether the URL is requesting additional process
// isolation during the current navigation (e.g., via OriginAgentCluster). If
// URL did not explicitly request any isolation, this will be set to kDefault.
// This field is only relevant (1) during a navigation request, (2) up to the
// point where the origin is placed into a SiteInstance. Other than these
// cases, this should be set to kDefault.
OriginIsolationRequest origin_isolation_request =
OriginIsolationRequest::kDefault;
// True if the Cross-Origin-Opener-Policy header has triggered a hint to turn
// on site isolation for `url`'s site.
bool is_coop_isolation_requested = false;
// True if this resource is served from the prefetch cache, and its success
// may have been influenced by cross-site state. Such responses may require
// special handling to make it harder to detect that this has happened.
bool is_prefetch_with_cross_site_contamination = false;
// This allows overriding the origin of |url| for process assignment purposes
// in certain very special cases.
// - The navigation to |url| is through loadDataWithBaseURL (e.g., in a
// <webview> tag or on Android Webview): this will be the base origin
// provided via that API.
// - For renderer-initiated about:blank navigations: this will be the
// initiator's origin that about:blank should inherit.
// - data: URLs that will be rendered (e.g. not downloads) that do NOT use
// loadDataWithBaseURL: this will be the value of the tentative origin to
// commit, which we will use to keep the nonce of the opaque origin
// consistent across a navigation.
// - All other cases: this will be nullopt.
//
// TODO(alexmos): Currently, this is also used to hold the origin committed
// by the renderer at DidCommitNavigation() time, for use in commit-time URL
// and origin checks that require a UrlInfo. Investigate whether there's a
// cleaner way to organize these checks. See https://crbug.com/1320402.
std::optional<url::Origin> origin;
// If url is being loaded in a frame that is in a origin-restricted sandboxed,
// then this flag will be true.
bool is_sandboxed = false;
// Only used when `is_sandboxed` is true, this unique identifier allows for
// per-document SiteInfo grouping.
int64_t unique_sandbox_id = kInvalidUniqueSandboxId;
// The StoragePartitionConfig that should be used when loading content from
// |url|. If absent, ContentBrowserClient::GetStoragePartitionConfig will be
// used to determine which StoragePartitionConfig to use.
//
// If present, this value will be used as the StoragePartitionConfig in the
// SiteInfo, regardless of its validity. SiteInstances created from a UrlInfo
// containing a StoragePartitionConfig that isn't compatible with the
// BrowsingInstance that the SiteInstance should belong to will lead to a
// CHECK failure.
std::optional<StoragePartitionConfig> storage_partition_config;
// Pages may choose to isolate themselves more strongly than the web's
// default, thus allowing access to APIs that would be difficult to
// safely expose otherwise. "Cross-origin isolation", for example, requires
// assertion of a Cross-Origin-Opener-Policy and
// Cross-Origin-Embedder-Policy, and unlocks SharedArrayBuffer.
// When we haven't yet been to the network or inherited properties that are
// sufficient to know the future isolation state - we are in a speculative
// state - this member will be empty.
std::optional<WebExposedIsolationInfo> web_exposed_isolation_info;
// Indicates that the URL directs to PDF content, which should be isolated
// from other types of content. On Android, this can only be true when a PDF
// NativePage is created for a main frame navigation.
bool is_pdf = false;
// If set, indicates that this UrlInfo is for a document that sets either
// COOP: same-origin or COOP: restrict-properties from the given origin. For
// subframes, it is inherited from the top-level frame. This is used to select
// an appropriate BrowsingInstance when navigating within a CoopRelatedGroup.
//
// Note: This cannot be part of the WebExposedIsolationInfo, because while it
// might force a different BrowsingInstance to be used, it may not force a
// strict process isolation, which non-matching web_exposed_isolation_info
// implies. Example: a top-level a.com document sets COOP:
// restrict-properties, and an a.com iframe in another tab has no COOP set.
// Under memory pressure they should be able to reuse the same process. This
// is not the case if the top-level document sets COOP: restrict-properties +
// COEP, because it then has an isolated WebExposedIsolationInfo.
std::optional<url::Origin> common_coop_origin;
// The CrossOriginIsolationKey to use for the navigation. This represents the
// isolation requested by the page itself through the use of COOP, COEP and
// DIP. Right now, this is only set when DocumentIsolationPolicy is enabled,
// but it should eventually for COOP and COEP. It will eventually replace
// WebExposedIsolationInfo.
std::optional<AgentClusterKey::CrossOriginIsolationKey>
cross_origin_isolation_key;
// Any new UrlInfo fields should be added to UrlInfoInit as well, and the
// UrlInfo constructor that takes a UrlInfoInit should be updated as well.
};
class CONTENT_EXPORT UrlInfoInit {
public:
UrlInfoInit() = delete;
explicit UrlInfoInit(const GURL& url);
explicit UrlInfoInit(const UrlInfo& base);
~UrlInfoInit();
UrlInfoInit& operator=(const UrlInfoInit&) = delete;
UrlInfoInit& WithOriginIsolationRequest(
UrlInfo::OriginIsolationRequest origin_isolation_request);
UrlInfoInit& WithCOOPSiteIsolation(bool requests_coop_isolation);
UrlInfoInit& WithCrossSitePrefetchContamination(bool contaminated);
UrlInfoInit& WithOrigin(const url::Origin& origin);
UrlInfoInit& WithSandbox(bool is_sandboxed);
UrlInfoInit& WithUniqueSandboxId(int unique_sandbox_id);
UrlInfoInit& WithStoragePartitionConfig(
std::optional<StoragePartitionConfig> storage_partition_config);
UrlInfoInit& WithWebExposedIsolationInfo(
std::optional<WebExposedIsolationInfo> web_exposed_isolation_info);
UrlInfoInit& WithIsPdf(bool is_pdf);
UrlInfoInit& WithCommonCoopOrigin(const url::Origin& origin);
UrlInfoInit& WithCrossOriginIsolationKey(
const std::optional<AgentClusterKey::CrossOriginIsolationKey>&
cross_origin_isolation_key);
const std::optional<url::Origin>& origin() { return origin_; }
private:
UrlInfoInit(UrlInfoInit&);
friend UrlInfo;
GURL url_;
UrlInfo::OriginIsolationRequest origin_isolation_request_ =
UrlInfo::OriginIsolationRequest::kDefault;
bool requests_coop_isolation_ = false;
bool is_prefetch_with_cross_site_contamination_ = false;
std::optional<url::Origin> origin_;
bool is_sandboxed_ = false;
int64_t unique_sandbox_id_ = UrlInfo::kInvalidUniqueSandboxId;
std::optional<StoragePartitionConfig> storage_partition_config_;
std::optional<WebExposedIsolationInfo> web_exposed_isolation_info_;
bool is_pdf_ = false;
std::optional<url::Origin> common_coop_origin_;
std::optional<AgentClusterKey::CrossOriginIsolationKey>
cross_origin_isolation_key_;
// Any new fields should be added to the UrlInfoInit(UrlInfo) constructor.
}; // class UrlInfoInit
} // namespace content
#endif // CONTENT_BROWSER_URL_INFO_H_